@modelprofile.com/authswitch 6.4.0 → 7.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/authority-contract.d.ts +302 -6
- package/dist_ts/authority-contract.js +1 -1
- package/dist_ts/authority-runtime-contract.d.ts +15 -0
- package/dist_ts/authorityrehearsal.child.d.ts +1 -0
- package/dist_ts/authorityrehearsal.child.js +395 -0
- package/dist_ts/classes.accountlist.js +4 -3
- package/dist_ts/classes.authoritybackup.d.ts +134 -0
- package/dist_ts/classes.authoritybackup.js +769 -0
- package/dist_ts/classes.authoritybroker.d.ts +29 -6
- package/dist_ts/classes.authoritybroker.js +413 -122
- package/dist_ts/classes.authoritycli.d.ts +24 -0
- package/dist_ts/classes.authoritycli.js +675 -0
- package/dist_ts/classes.authorityclient.d.ts +34 -9
- package/dist_ts/classes.authorityclient.js +136 -38
- package/dist_ts/classes.authoritydaemon.d.ts +47 -0
- package/dist_ts/classes.authoritydaemon.js +705 -16
- package/dist_ts/classes.authoritydatabase.d.ts +182 -8
- package/dist_ts/classes.authoritydatabase.js +1188 -41
- package/dist_ts/classes.authoritymodels.d.ts +247 -1
- package/dist_ts/classes.authoritymodels.js +870 -6
- package/dist_ts/classes.authoritypreuse.d.ts +47 -0
- package/dist_ts/classes.authoritypreuse.js +278 -0
- package/dist_ts/classes.authorityregistry.d.ts +24 -0
- package/dist_ts/classes.authorityregistry.js +88 -0
- package/dist_ts/classes.authorityrehearsal.d.ts +127 -0
- package/dist_ts/classes.authorityrehearsal.js +632 -0
- package/dist_ts/classes.authorityusage.d.ts +160 -0
- package/dist_ts/classes.authorityusage.js +429 -0
- package/dist_ts/classes.claudeauthority.d.ts +66 -0
- package/dist_ts/classes.claudeauthority.js +532 -0
- package/dist_ts/classes.claudecodeharness.js +3 -2
- package/dist_ts/classes.claudecodelocks.d.ts +13 -0
- package/dist_ts/classes.claudecodelocks.js +75 -3
- package/dist_ts/classes.claudenative.d.ts +137 -0
- package/dist_ts/classes.claudenative.js +731 -0
- package/dist_ts/classes.claudestatus.d.ts +9 -0
- package/dist_ts/classes.claudestatus.js +26 -9
- package/dist_ts/classes.claudetokenrefresh.d.ts +15 -1
- package/dist_ts/classes.claudetokenrefresh.js +74 -21
- package/dist_ts/classes.codexharness.js +4 -2
- package/dist_ts/classes.codexmanaged.d.ts +91 -0
- package/dist_ts/classes.codexmanaged.js +404 -0
- package/dist_ts/classes.codexpreuse.d.ts +8 -0
- package/dist_ts/classes.codexpreuse.js +24 -6
- package/dist_ts/classes.fileharness.d.ts +2 -0
- package/dist_ts/classes.fileharness.js +6 -4
- package/dist_ts/classes.limits.js +12 -7
- package/dist_ts/classes.opencodeharness.js +2 -2
- package/dist_ts/claudehttp.d.ts +10 -0
- package/dist_ts/claudehttp.js +29 -3
- package/dist_ts/index.d.ts +2 -0
- package/dist_ts/index.js +8 -1
- package/dist_ts/interfaces.harness.d.ts +6 -0
- package/dist_ts/interfaces.list.d.ts +9 -3
- package/dist_ts/plugins.d.ts +7 -3
- package/dist_ts/plugins.js +9 -4
- package/dist_ts/ts_migration/0001_authority_meta.d.ts +3 -0
- package/dist_ts/ts_migration/0001_authority_meta.js +32 -0
- package/dist_ts/ts_migration/index.d.ts +3 -0
- package/dist_ts/ts_migration/index.js +6 -0
- package/package.json +12 -2
- package/readme.md +205 -13
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/authority-contract.ts +264 -9
- package/ts/authority-runtime-contract.ts +21 -1
- package/ts/authorityrehearsal.child.ts +330 -0
- package/ts/classes.accountlist.ts +3 -2
- package/ts/classes.authoritybackup.ts +780 -0
- package/ts/classes.authoritybroker.ts +410 -120
- package/ts/classes.authoritycli.ts +719 -0
- package/ts/classes.authorityclient.ts +164 -38
- package/ts/classes.authoritydaemon.ts +614 -17
- package/ts/classes.authoritydatabase.ts +1229 -44
- package/ts/classes.authoritymodels.ts +579 -4
- package/ts/classes.authoritypreuse.ts +297 -0
- package/ts/classes.authorityregistry.ts +118 -0
- package/ts/classes.authorityrehearsal.ts +625 -0
- package/ts/classes.authorityusage.ts +527 -0
- package/ts/classes.claudeauthority.ts +541 -0
- package/ts/classes.claudecodeharness.ts +2 -1
- package/ts/classes.claudecodelocks.ts +70 -1
- package/ts/classes.claudenative.ts +816 -0
- package/ts/classes.claudestatus.ts +38 -9
- package/ts/classes.claudetokenrefresh.ts +82 -19
- package/ts/classes.codexharness.ts +3 -1
- package/ts/classes.codexmanaged.ts +402 -0
- package/ts/classes.codexpreuse.ts +33 -5
- package/ts/classes.fileharness.ts +7 -3
- package/ts/classes.limits.ts +11 -6
- package/ts/classes.opencodeharness.ts +1 -1
- package/ts/claudehttp.ts +31 -2
- package/ts/index.ts +7 -0
- package/ts/interfaces.harness.ts +6 -0
- package/ts/interfaces.list.ts +9 -3
- package/ts/plugins.ts +9 -3
- package/ts/ts_migration/0001_authority_meta.ts +33 -0
- package/ts/ts_migration/index.ts +7 -0
|
@@ -0,0 +1,719 @@
|
|
|
1
|
+
import type { IAuthSwitchDoctorPage, IAuthSwitchOperation, IAuthSwitchPreuseOperation,
|
|
2
|
+
IAuthSwitchSnapshot, IReq_AuthSwitchDoctor, IReq_AuthSwitchStartPreuse } from './authority-contract.js';
|
|
3
|
+
import { AuthSwitchClient } from './classes.authorityclient.js';
|
|
4
|
+
import { resolveAuthSwitchAuthorityPaths } from './classes.authorityservice.js';
|
|
5
|
+
import { defaultPreusePrompt, validatePreuseOptions } from './preuse.js';
|
|
6
|
+
import { plainText } from './formatting.js';
|
|
7
|
+
import * as plugins from './plugins.js';
|
|
8
|
+
|
|
9
|
+
export interface IAuthSwitchAuthorityCliClient {
|
|
10
|
+
snapshotAll(): Promise<IAuthSwitchSnapshot>;
|
|
11
|
+
doctorPage(request: IReq_AuthSwitchDoctor['request']): Promise<IAuthSwitchDoctorPage>;
|
|
12
|
+
beginAddOpenAi(operationId: string): Promise<IAuthSwitchOperation>;
|
|
13
|
+
beginReauthOpenAi(operationId: string, accountId: string, loginId: string,
|
|
14
|
+
purpose: 'openai_managed'): Promise<IAuthSwitchOperation>;
|
|
15
|
+
getOperation(operationId: string): Promise<IAuthSwitchOperation>;
|
|
16
|
+
cancelOperation(operationId: string): Promise<IAuthSwitchOperation>;
|
|
17
|
+
startPreuse(input: IReq_AuthSwitchStartPreuse['request']): Promise<IAuthSwitchPreuseOperation>;
|
|
18
|
+
getPreuse(operationId: string): Promise<IAuthSwitchPreuseOperation>;
|
|
19
|
+
cancelPreuse(operationId: string): Promise<IAuthSwitchPreuseOperation>;
|
|
20
|
+
close(reason?: Error): void;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export interface IAuthSwitchAuthorityCliOptions {
|
|
24
|
+
clientFactory?: () => IAuthSwitchAuthorityCliClient;
|
|
25
|
+
stdout?: (text: string) => void | Promise<void>;
|
|
26
|
+
stderr?: (text: string) => void | Promise<void>;
|
|
27
|
+
signal?: AbortSignal;
|
|
28
|
+
now?: () => number;
|
|
29
|
+
wait?: (milliseconds: number, signal: AbortSignal) => Promise<void>;
|
|
30
|
+
operationIdFactory?: () => string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
type TAuthorityCliCommand =
|
|
34
|
+
| { kind: 'list'; json: boolean }
|
|
35
|
+
| { kind: 'doctor'; json: boolean }
|
|
36
|
+
| { kind: 'add'; json: boolean }
|
|
37
|
+
| { kind: 'reauth'; accountId: string; loginId: string; json: boolean }
|
|
38
|
+
| { kind: 'get'; operationId: string; json: boolean }
|
|
39
|
+
| { kind: 'cancel'; operationId: string; json: boolean }
|
|
40
|
+
| { kind: 'resume'; operationId: string; json: boolean }
|
|
41
|
+
| { kind: 'preuse'; target: { accountId: string; loginId: string } | 'all';
|
|
42
|
+
prompt: string; model?: string; json: boolean }
|
|
43
|
+
| { kind: 'preuseGet'; operationId: string; json: boolean }
|
|
44
|
+
| { kind: 'preuseCancel'; operationId: string; json: boolean }
|
|
45
|
+
| { kind: 'preuseResume'; operationId: string; json: boolean };
|
|
46
|
+
type TAuthorityCliFailure = 'output' | 'response';
|
|
47
|
+
|
|
48
|
+
class AuthorityCliFailure extends Error {
|
|
49
|
+
constructor(public readonly kind: TAuthorityCliFailure) {
|
|
50
|
+
super(`Authswitch authority CLI ${kind} failure.`);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const usage = 'Usage: authswitch account list [--json] | authswitch account add openai [--json] | authswitch account reauth <account-id> <login-id> [--json] | authswitch account operation get|cancel|resume <operation-id> [--json] | authswitch account preuse <account-id> <login-id>|--all [--prompt <text>] [--model <id>] [--json] | authswitch account preuse operation get|cancel|resume <operation-id> [--json] | authswitch authority doctor [--json]';
|
|
55
|
+
const safe = (value: string | number | null): string => plainText(value === null ? 'none' : String(value));
|
|
56
|
+
const isId = (value: string | undefined): value is string => Boolean(value && !value.startsWith('-'));
|
|
57
|
+
|
|
58
|
+
const parsePreuse = (argv: readonly string[]): TAuthorityCliCommand | null => {
|
|
59
|
+
if (argv[2] === 'operation') {
|
|
60
|
+
if ((argv[3] === 'get' || argv[3] === 'cancel' || argv[3] === 'resume') && isId(argv[4])
|
|
61
|
+
&& (argv.length === 5 || (argv.length === 6 && argv[5] === '--json'))) {
|
|
62
|
+
const kind = argv[3] === 'get' ? 'preuseGet'
|
|
63
|
+
: argv[3] === 'cancel' ? 'preuseCancel' : 'preuseResume';
|
|
64
|
+
return { kind, operationId: argv[4], json: argv[5] === '--json' };
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
let target: Extract<TAuthorityCliCommand, { kind: 'preuse' }>['target'];
|
|
69
|
+
let index: number;
|
|
70
|
+
if (argv[2] === '--all') {
|
|
71
|
+
target = 'all';
|
|
72
|
+
index = 3;
|
|
73
|
+
} else if (isId(argv[2]) && isId(argv[3])) {
|
|
74
|
+
target = { accountId: argv[2], loginId: argv[3] };
|
|
75
|
+
index = 4;
|
|
76
|
+
} else return null;
|
|
77
|
+
let prompt = defaultPreusePrompt;
|
|
78
|
+
let model: string | undefined;
|
|
79
|
+
let json = false;
|
|
80
|
+
let promptSet = false;
|
|
81
|
+
let modelSet = false;
|
|
82
|
+
while (index < argv.length) {
|
|
83
|
+
const option = argv[index];
|
|
84
|
+
if (option === '--json' && !json) {
|
|
85
|
+
json = true;
|
|
86
|
+
index++;
|
|
87
|
+
} else if (option === '--prompt' && !promptSet && argv[index + 1] !== undefined
|
|
88
|
+
&& !argv[index + 1]!.startsWith('--')) {
|
|
89
|
+
prompt = argv[index + 1]!;
|
|
90
|
+
promptSet = true;
|
|
91
|
+
index += 2;
|
|
92
|
+
} else if (option === '--model' && !modelSet && argv[index + 1] !== undefined
|
|
93
|
+
&& !argv[index + 1]!.startsWith('--')) {
|
|
94
|
+
model = argv[index + 1]!;
|
|
95
|
+
modelSet = true;
|
|
96
|
+
index += 2;
|
|
97
|
+
} else return null;
|
|
98
|
+
}
|
|
99
|
+
try { validatePreuseOptions({ prompt, model }); } catch { return null; }
|
|
100
|
+
return { kind: 'preuse', target, prompt, ...(model === undefined ? {} : { model }), json };
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const parse = (argv: readonly string[]): TAuthorityCliCommand | null => {
|
|
104
|
+
if (argv[0] === 'account' && argv[1] === 'list'
|
|
105
|
+
&& (argv.length === 2 || (argv.length === 3 && argv[2] === '--json'))) {
|
|
106
|
+
return { kind: 'list', json: argv[2] === '--json' };
|
|
107
|
+
}
|
|
108
|
+
if (argv[0] === 'authority' && argv[1] === 'doctor'
|
|
109
|
+
&& (argv.length === 2 || (argv.length === 3 && argv[2] === '--json'))) {
|
|
110
|
+
return { kind: 'doctor', json: argv[2] === '--json' };
|
|
111
|
+
}
|
|
112
|
+
if (argv[0] === 'account' && argv[1] === 'add' && argv[2] === 'openai'
|
|
113
|
+
&& (argv.length === 3 || (argv.length === 4 && argv[3] === '--json'))) {
|
|
114
|
+
return { kind: 'add', json: argv[3] === '--json' };
|
|
115
|
+
}
|
|
116
|
+
if (argv[0] === 'account' && argv[1] === 'reauth' && isId(argv[2]) && isId(argv[3])
|
|
117
|
+
&& (argv.length === 4 || (argv.length === 5 && argv[4] === '--json'))) {
|
|
118
|
+
return { kind: 'reauth', accountId: argv[2], loginId: argv[3], json: argv[4] === '--json' };
|
|
119
|
+
}
|
|
120
|
+
if (argv[0] === 'account' && argv[1] === 'operation'
|
|
121
|
+
&& (argv[2] === 'get' || argv[2] === 'cancel' || argv[2] === 'resume') && isId(argv[3])
|
|
122
|
+
&& (argv.length === 4 || (argv.length === 5 && argv[4] === '--json'))) {
|
|
123
|
+
return { kind: argv[2], operationId: argv[3], json: argv[4] === '--json' };
|
|
124
|
+
}
|
|
125
|
+
if (argv[0] === 'account' && argv[1] === 'preuse') return parsePreuse(argv);
|
|
126
|
+
return null;
|
|
127
|
+
};
|
|
128
|
+
|
|
129
|
+
class ScopedAuthorityCliClient implements IAuthSwitchAuthorityCliClient {
|
|
130
|
+
private readonly controller = new AbortController();
|
|
131
|
+
private readonly client: AuthSwitchClient;
|
|
132
|
+
|
|
133
|
+
constructor() {
|
|
134
|
+
const paths = resolveAuthSwitchAuthorityPaths();
|
|
135
|
+
this.client = new AuthSwitchClient(paths.authoritySocketPath, paths.runtimeSocketPath);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
public snapshotAll(): Promise<IAuthSwitchSnapshot> {
|
|
139
|
+
return this.client.snapshotAll({ limit: 128, signal: this.controller.signal });
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
public doctorPage(request: IReq_AuthSwitchDoctor['request']): Promise<IAuthSwitchDoctorPage> {
|
|
143
|
+
return this.client.doctorPage(request, this.controller.signal);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
public beginAddOpenAi(operationId: string): Promise<IAuthSwitchOperation> {
|
|
147
|
+
return this.client.beginAddOpenAi(operationId, this.controller.signal);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
public beginReauthOpenAi(operationId: string, accountId: string, loginId: string,
|
|
151
|
+
purpose: 'openai_managed'): Promise<IAuthSwitchOperation> {
|
|
152
|
+
return this.client.beginReauthOpenAi(operationId, accountId, loginId, purpose, this.controller.signal);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public getOperation(operationId: string): Promise<IAuthSwitchOperation> {
|
|
156
|
+
return this.client.getOperation(operationId, this.controller.signal);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
public cancelOperation(operationId: string): Promise<IAuthSwitchOperation> {
|
|
160
|
+
return this.client.cancelOperation(operationId, this.controller.signal);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
public startPreuse(input: IReq_AuthSwitchStartPreuse['request']): Promise<IAuthSwitchPreuseOperation> {
|
|
164
|
+
return this.client.startPreuse(input, this.controller.signal);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
public getPreuse(operationId: string): Promise<IAuthSwitchPreuseOperation> {
|
|
168
|
+
return this.client.getPreuse(operationId, this.controller.signal);
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
public cancelPreuse(operationId: string): Promise<IAuthSwitchPreuseOperation> {
|
|
172
|
+
return this.client.cancelPreuse(operationId, this.controller.signal);
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
public close(reason = new Error('Authswitch authority CLI closed.')): void {
|
|
176
|
+
if (!this.controller.signal.aborted) this.controller.abort(reason);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const renderList = (snapshot: IAuthSwitchSnapshot): string => {
|
|
181
|
+
const lines = [`Authority accounts — generated ${safe(snapshot.generatedAt)}, revision ${snapshot.revision}`];
|
|
182
|
+
if (snapshot.accounts.length === 0) lines.push('No authority accounts are registered.');
|
|
183
|
+
for (const account of snapshot.accounts) {
|
|
184
|
+
const identity = account.email ?? account.label;
|
|
185
|
+
lines.push(`${safe(identity)} [${safe(account.providerId)}]`,
|
|
186
|
+
` account ${safe(account.id)}; plan ${safe(account.plan)}; ${account.removed ? 'removed' : 'registered'}; stored ${safe(account.statusObservedAt)}`);
|
|
187
|
+
const logins = snapshot.logins.filter(login => login.accountId === account.id);
|
|
188
|
+
if (logins.length === 0) lines.push(' logins: none');
|
|
189
|
+
else {
|
|
190
|
+
lines.push(' stored login state (live provider check not performed):');
|
|
191
|
+
for (const login of logins) {
|
|
192
|
+
lines.push(` ${safe(login.id)} ${safe(login.purpose)} owner=${safe(login.owner)} health=${safe(login.health)} problem=${safe(login.problem)} observed=${safe(login.statusObservedAt)}`);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
const bindings = snapshot.bindings.filter(binding => binding.accountId === account.id);
|
|
196
|
+
if (bindings.length === 0) lines.push(' runtime bindings: none');
|
|
197
|
+
else for (const binding of bindings) {
|
|
198
|
+
lines.push(` runtime ${safe(binding.runtime)} scope=${safe(binding.scopeId)} binding=${safe(binding.id)}`);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return lines.join('\n') + '\n';
|
|
202
|
+
};
|
|
203
|
+
|
|
204
|
+
const terminalOperation = (operation: IAuthSwitchOperation): boolean =>
|
|
205
|
+
operation.state === 'complete' || operation.state === 'failed' || operation.state === 'cancelled'
|
|
206
|
+
|| operation.state === 'interrupted' || operation.state === 'outcome_unknown';
|
|
207
|
+
|
|
208
|
+
const resumeCommand = (operationId: string, json: boolean): string =>
|
|
209
|
+
`authswitch account operation resume ${safe(operationId)}${json ? ' --json' : ''}`;
|
|
210
|
+
|
|
211
|
+
const terminalPreuseOperation = (operation: IAuthSwitchPreuseOperation): boolean =>
|
|
212
|
+
operation.state === 'complete' || operation.state === 'not_sent' || operation.state === 'outcome_unknown';
|
|
213
|
+
|
|
214
|
+
const preuseResumeCommand = (operationId: string, json: boolean): string =>
|
|
215
|
+
`authswitch account preuse operation resume ${safe(operationId)}${json ? ' --json' : ''}`;
|
|
216
|
+
|
|
217
|
+
const renderOperation = (operation: IAuthSwitchOperation, json: boolean): string => {
|
|
218
|
+
if (json) return JSON.stringify(operation) + '\n';
|
|
219
|
+
const lines = [
|
|
220
|
+
`Authority operation ${safe(operation.id)} — ${safe(operation.state)}, revision ${operation.revision}`,
|
|
221
|
+
` kind=${safe(operation.kind)}; purpose=${safe(operation.purpose)}`,
|
|
222
|
+
];
|
|
223
|
+
if (operation.targetAccountId || operation.targetLoginId) {
|
|
224
|
+
lines.push(` target account=${safe(operation.targetAccountId)}; login=${safe(operation.targetLoginId)}`);
|
|
225
|
+
}
|
|
226
|
+
if (operation.prompt?.flow === 'device') {
|
|
227
|
+
lines.push(` Open ${safe(operation.prompt.verificationUrl)}`, ` Code: ${safe(operation.prompt.userCode)}`);
|
|
228
|
+
} else if (operation.prompt?.flow === 'browser') lines.push(` Open ${safe(operation.prompt.authUrl)}`);
|
|
229
|
+
if (operation.result) {
|
|
230
|
+
lines.push(` completed account=${safe(operation.result.accountId)}; login=${safe(operation.result.loginId)}; account revision=${operation.result.accountRevision}; login generation=${operation.result.loginGeneration}`);
|
|
231
|
+
}
|
|
232
|
+
if (operation.error) lines.push(` problem=${safe(operation.error)}`);
|
|
233
|
+
if (!terminalOperation(operation)) lines.push(` Resume: ${resumeCommand(operation.id, false)}`);
|
|
234
|
+
return lines.join('\n') + '\n';
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
const renderPreuseOperation = (operation: IAuthSwitchPreuseOperation, json: boolean,
|
|
238
|
+
batch = false): string => {
|
|
239
|
+
if (json) return JSON.stringify(batch ? { type: 'operation', operation } : operation) + '\n';
|
|
240
|
+
const lines = [
|
|
241
|
+
`Authority preuse operation ${safe(operation.id)} — ${safe(operation.state)}, revision ${operation.revision}`,
|
|
242
|
+
` account=${safe(operation.accountId)}; login=${safe(operation.loginId)}; purpose=${safe(operation.purpose)}`,
|
|
243
|
+
` requested model=${safe(operation.requestedModel)}; model=${safe(operation.model)}; problem=${safe(operation.problem)}`,
|
|
244
|
+
];
|
|
245
|
+
if (operation.result) {
|
|
246
|
+
lines.push(` tokens input=${safe(operation.result.inputTokens)}; output=${safe(operation.result.outputTokens)}; total=${safe(operation.result.totalTokens)}`);
|
|
247
|
+
}
|
|
248
|
+
if (!terminalPreuseOperation(operation)) {
|
|
249
|
+
lines.push(` Resume: ${preuseResumeCommand(operation.id, false)}`);
|
|
250
|
+
}
|
|
251
|
+
return lines.join('\n') + '\n';
|
|
252
|
+
};
|
|
253
|
+
|
|
254
|
+
interface IPreuseBatchSkip {
|
|
255
|
+
type: 'skipped';
|
|
256
|
+
snapshotRevision: number;
|
|
257
|
+
accountId: string;
|
|
258
|
+
loginId: string;
|
|
259
|
+
loginRevision: number;
|
|
260
|
+
statusObservedAt: string;
|
|
261
|
+
health: IAuthSwitchSnapshot['logins'][number]['health'];
|
|
262
|
+
problem: IAuthSwitchSnapshot['logins'][number]['problem'];
|
|
263
|
+
reason: 'snapshot_not_preuse_capable';
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const renderPreuseSkip = (skip: IPreuseBatchSkip, json: boolean): string => {
|
|
267
|
+
if (json) return JSON.stringify(skip) + '\n';
|
|
268
|
+
return `Preuse skipped account ${safe(skip.accountId)}; login ${safe(skip.loginId)} — snapshot revision ${skip.snapshotRevision}, login revision ${skip.loginRevision}; health=${safe(skip.health)}; problem=${safe(skip.problem)}; observed=${safe(skip.statusObservedAt)}; reason=${skip.reason}\n`;
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
const defaultWait = (milliseconds: number, signal: AbortSignal): Promise<void> => new Promise((resolve, reject) => {
|
|
272
|
+
if (signal.aborted) {
|
|
273
|
+
reject(signal.reason);
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
const timer = setTimeout(() => {
|
|
277
|
+
signal.removeEventListener('abort', onAbort);
|
|
278
|
+
resolve();
|
|
279
|
+
}, milliseconds);
|
|
280
|
+
const onAbort = (): void => {
|
|
281
|
+
clearTimeout(timer);
|
|
282
|
+
signal.removeEventListener('abort', onAbort);
|
|
283
|
+
reject(signal.reason);
|
|
284
|
+
};
|
|
285
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const renderDoctorPage = (page: IAuthSwitchDoctorPage, pageNumber: number): string => {
|
|
289
|
+
const lines = [
|
|
290
|
+
`Authority doctor page ${pageNumber} — observed ${safe(page.observedAt)}`,
|
|
291
|
+
` daemon=${safe(page.daemon.state)}; Claude native authority=${safe(page.daemon.claudeNativeAuthority)}; observed=${safe(page.daemon.observedAt)}`,
|
|
292
|
+
` database=${safe(page.database.state)}; admission=${safe(page.database.admission)}; schema=${page.database.schemaVersion}; revision=${page.database.revision}; observed=${safe(page.database.observedAt)}`,
|
|
293
|
+
` accounts: ${page.accounts.length} stored evidence record(s); live provider check not performed`,
|
|
294
|
+
` logins: ${page.logins.length} stored evidence record(s); live provider check not performed`,
|
|
295
|
+
];
|
|
296
|
+
for (const login of page.logins) {
|
|
297
|
+
lines.push(` login ${safe(login.id)} ${safe(login.purpose)} state=${safe(login.state)} owner=${safe(login.owner)} problem=${safe(login.problem)}`);
|
|
298
|
+
}
|
|
299
|
+
for (const runtime of page.managedCodex) {
|
|
300
|
+
lines.push(` managed Codex ${safe(runtime.scopeId)}: health=${safe(runtime.health)}; durable=${safe(runtime.durable.state)}; daemon=${safe(runtime.daemon.state)}/${safe(runtime.daemon.assignment)}; process=${safe(runtime.process.state)}/${safe(runtime.process.identity)}; problem=${safe(runtime.process.problem)}`);
|
|
301
|
+
}
|
|
302
|
+
for (const home of page.claudeHomes) {
|
|
303
|
+
lines.push(` Claude home ${safe(home.id)}: status=${safe(home.status)}; account=${safe(home.activeAccountId)}; login=${safe(home.activeLoginId)}`);
|
|
304
|
+
}
|
|
305
|
+
for (const handoff of page.claudeHandoffs) {
|
|
306
|
+
lines.push(` Claude handoff ${safe(handoff.id)}: phase=${safe(handoff.phase)}; problem=${safe(handoff.problem)}`);
|
|
307
|
+
}
|
|
308
|
+
for (const handoff of page.nativeHandoffs) {
|
|
309
|
+
lines.push(` native handoff ${safe(handoff.id)}: direction=${safe(handoff.direction)}; phase=${safe(handoff.phase)}`);
|
|
310
|
+
}
|
|
311
|
+
for (const migration of page.migrations) {
|
|
312
|
+
lines.push(` migration ${safe(migration.id)}: source=${safe(migration.sourceKind)}; status=${safe(migration.status)}`);
|
|
313
|
+
}
|
|
314
|
+
return lines.join('\n') + '\n';
|
|
315
|
+
};
|
|
316
|
+
|
|
317
|
+
const observationTimes = (page: IAuthSwitchDoctorPage): string[] => [
|
|
318
|
+
page.database.observedAt,
|
|
319
|
+
page.daemon.observedAt,
|
|
320
|
+
...page.managedCodex.map(runtime => runtime.process.observedAt),
|
|
321
|
+
page.observedAt,
|
|
322
|
+
];
|
|
323
|
+
|
|
324
|
+
const nextDoctorRequest = (request: IReq_AuthSwitchDoctor['request'], page: IAuthSwitchDoctorPage): IReq_AuthSwitchDoctor['request'] => ({
|
|
325
|
+
accountAfter: page.nextAccountCursor ?? page.accounts.at(-1)?.id ?? request.accountAfter,
|
|
326
|
+
loginAfter: page.nextLoginCursor ?? page.logins.at(-1)?.id ?? request.loginAfter,
|
|
327
|
+
codexHomeAfter: page.nextCodexHomeCursor ?? page.managedCodex.at(-1)?.homeId ?? request.codexHomeAfter,
|
|
328
|
+
claudeHomeAfter: page.nextClaudeHomeCursor ?? page.claudeHomes.at(-1)?.id ?? request.claudeHomeAfter,
|
|
329
|
+
claudeHandoffAfter: page.nextClaudeHandoffCursor ?? page.claudeHandoffs.at(-1)?.id ?? request.claudeHandoffAfter,
|
|
330
|
+
nativeHandoffAfter: page.nextNativeHandoffCursor ?? page.nativeHandoffs.at(-1)?.id ?? request.nativeHandoffAfter,
|
|
331
|
+
migrationAfter: page.nextMigrationCursor ?? page.migrations.at(-1)?.id ?? request.migrationAfter,
|
|
332
|
+
limit: 128,
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
const doctorComplete = (page: IAuthSwitchDoctorPage): boolean => page.nextAccountCursor === null
|
|
336
|
+
&& page.nextLoginCursor === null && page.nextCodexHomeCursor === null && page.nextClaudeHomeCursor === null
|
|
337
|
+
&& page.nextClaudeHandoffCursor === null && page.nextNativeHandoffCursor === null
|
|
338
|
+
&& page.nextMigrationCursor === null;
|
|
339
|
+
|
|
340
|
+
const runDoctor = async (client: IAuthSwitchAuthorityCliClient, json: boolean,
|
|
341
|
+
write: (text: string) => void | Promise<void>): Promise<void> => {
|
|
342
|
+
let request: IReq_AuthSwitchDoctor['request'] = { limit: 128 };
|
|
343
|
+
let pageNumber = 0;
|
|
344
|
+
let observedFrom: string | null = null;
|
|
345
|
+
let observedTo: string | null = null;
|
|
346
|
+
while (true) {
|
|
347
|
+
const page = await client.doctorPage(request);
|
|
348
|
+
pageNumber++;
|
|
349
|
+
for (const timestamp of observationTimes(page)) {
|
|
350
|
+
if (observedFrom === null || timestamp < observedFrom) observedFrom = timestamp;
|
|
351
|
+
if (observedTo === null || timestamp > observedTo) observedTo = timestamp;
|
|
352
|
+
}
|
|
353
|
+
if (json) {
|
|
354
|
+
await write((pageNumber === 1 ? '{"type":"authswitch-authority-doctor","schemaVersion":1,"pages":[' : ',')
|
|
355
|
+
+ JSON.stringify({ pageNumber, page }));
|
|
356
|
+
} else await write(renderDoctorPage(page, pageNumber));
|
|
357
|
+
if (doctorComplete(page)) break;
|
|
358
|
+
const next = nextDoctorRequest(request, page);
|
|
359
|
+
if (JSON.stringify(next) === JSON.stringify(request)) throw new AuthorityCliFailure('response');
|
|
360
|
+
request = next;
|
|
361
|
+
}
|
|
362
|
+
if (json) await write(`],"observationSpan":${JSON.stringify({ pageCount: pageNumber, observedFrom, observedTo })},"globallyAtomic":false}\n`);
|
|
363
|
+
else await write(`Authority doctor completed ${pageNumber} page(s); observation span ${safe(observedFrom)} to ${safe(observedTo)}. Pages are independently observed and are not globally atomic.\n`);
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const streamWrite = (stream: NodeJS.WriteStream, text: string): Promise<void> => new Promise((resolve, reject) => {
|
|
367
|
+
let settled = false;
|
|
368
|
+
const finish = (error?: Error | null): void => {
|
|
369
|
+
if (settled) return;
|
|
370
|
+
settled = true;
|
|
371
|
+
if (error) reject(error);
|
|
372
|
+
else resolve();
|
|
373
|
+
};
|
|
374
|
+
const onError = (error: Error): void => finish(error);
|
|
375
|
+
stream.once('error', onError);
|
|
376
|
+
stream.write(text, error => {
|
|
377
|
+
if (error) {
|
|
378
|
+
// Writable streams may emit the same failure after invoking the callback. Keep the
|
|
379
|
+
// one-shot listener through the current turn so an EPIPE cannot become unhandled.
|
|
380
|
+
finish(error);
|
|
381
|
+
setImmediate(() => stream.off('error', onError));
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
stream.off('error', onError);
|
|
385
|
+
finish();
|
|
386
|
+
});
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
const abortable = <T>(operation: Promise<T>, signal: AbortSignal): Promise<T> => {
|
|
390
|
+
if (signal.aborted) return Promise.reject(signal.reason);
|
|
391
|
+
return new Promise<T>((resolve, reject) => {
|
|
392
|
+
const onAbort = (): void => {
|
|
393
|
+
signal.removeEventListener('abort', onAbort);
|
|
394
|
+
reject(signal.reason);
|
|
395
|
+
};
|
|
396
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
397
|
+
operation.then(value => {
|
|
398
|
+
signal.removeEventListener('abort', onAbort);
|
|
399
|
+
resolve(value);
|
|
400
|
+
}, error => {
|
|
401
|
+
signal.removeEventListener('abort', onAbort);
|
|
402
|
+
reject(error);
|
|
403
|
+
});
|
|
404
|
+
});
|
|
405
|
+
};
|
|
406
|
+
|
|
407
|
+
const preuseBatchTargets = (snapshot: IAuthSwitchSnapshot): IAuthSwitchSnapshot['logins'] => {
|
|
408
|
+
const accountIds = new Set(snapshot.accounts
|
|
409
|
+
.filter(account => account.providerId === 'openai' && !account.removed)
|
|
410
|
+
.map(account => account.id));
|
|
411
|
+
const seen = new Set<string>();
|
|
412
|
+
return snapshot.logins.filter(login => {
|
|
413
|
+
const key = `${login.accountId}:${login.id}`;
|
|
414
|
+
if (seen.has(key) || !accountIds.has(login.accountId) || login.providerId !== 'openai'
|
|
415
|
+
|| login.purpose !== 'openai_managed' || login.owner !== 'daemon') return false;
|
|
416
|
+
seen.add(key);
|
|
417
|
+
return true;
|
|
418
|
+
});
|
|
419
|
+
};
|
|
420
|
+
|
|
421
|
+
const operationPollIntervalMs = 1_000;
|
|
422
|
+
const operationDeadlineMs = 15 * 60 * 1_000;
|
|
423
|
+
|
|
424
|
+
/** Credential-free daemon CLI. It never opens the database or falls back to native harness stores. */
|
|
425
|
+
export const runAuthSwitchAuthorityCli = async (argv: readonly string[],
|
|
426
|
+
options: IAuthSwitchAuthorityCliOptions = {}): Promise<number> => {
|
|
427
|
+
const write = options.stdout ?? (text => streamWrite(process.stdout, text));
|
|
428
|
+
const writeError = options.stderr ?? (text => streamWrite(process.stderr, text));
|
|
429
|
+
const now = options.now ?? Date.now;
|
|
430
|
+
const wait = options.wait ?? defaultWait;
|
|
431
|
+
const operationIdFactory = options.operationIdFactory ?? (() => plugins.crypto.randomUUID());
|
|
432
|
+
const command = parse(argv);
|
|
433
|
+
if (!command) {
|
|
434
|
+
await writeError(`${usage}\n`);
|
|
435
|
+
return 2;
|
|
436
|
+
}
|
|
437
|
+
let client: IAuthSwitchAuthorityCliClient | undefined;
|
|
438
|
+
let clientClosed = false;
|
|
439
|
+
let cancelled = false;
|
|
440
|
+
let timedOut = false;
|
|
441
|
+
let deadlineAt: number | null = null;
|
|
442
|
+
let operationIdForHint: string | null = null;
|
|
443
|
+
let preuseHint = false;
|
|
444
|
+
let beginAttempted = false;
|
|
445
|
+
let beginResponded = false;
|
|
446
|
+
const operationController = new AbortController();
|
|
447
|
+
const closeClient = (reason?: Error): void => {
|
|
448
|
+
if (clientClosed || !client) return;
|
|
449
|
+
clientClosed = true;
|
|
450
|
+
client.close(reason);
|
|
451
|
+
};
|
|
452
|
+
const detach = (reason: Error): void => {
|
|
453
|
+
if (!operationController.signal.aborted) operationController.abort(reason);
|
|
454
|
+
closeClient(reason);
|
|
455
|
+
};
|
|
456
|
+
const close = () => {
|
|
457
|
+
cancelled = true;
|
|
458
|
+
detach(new Error('Authswitch authority request cancelled.'));
|
|
459
|
+
};
|
|
460
|
+
const expire = (): Error => {
|
|
461
|
+
const reason = new Error('Authswitch authority operation timed out.');
|
|
462
|
+
timedOut = true;
|
|
463
|
+
detach(reason);
|
|
464
|
+
return reason;
|
|
465
|
+
};
|
|
466
|
+
const withinDeadline = async <T>(work: () => Promise<T>): Promise<T> => {
|
|
467
|
+
if (deadlineAt === null) return abortable(Promise.resolve().then(work), operationController.signal);
|
|
468
|
+
const remaining = deadlineAt - now();
|
|
469
|
+
if (remaining <= 0) throw expire();
|
|
470
|
+
const timerController = new AbortController();
|
|
471
|
+
const stopTimer = (): void => {
|
|
472
|
+
if (!timerController.signal.aborted) timerController.abort(new Error('Authswitch authority deadline timer stopped.'));
|
|
473
|
+
};
|
|
474
|
+
const onOperationAbort = (): void => {
|
|
475
|
+
if (!timerController.signal.aborted) timerController.abort(operationController.signal.reason);
|
|
476
|
+
};
|
|
477
|
+
operationController.signal.addEventListener('abort', onOperationAbort, { once: true });
|
|
478
|
+
const operation = abortable(Promise.resolve().then(work), operationController.signal);
|
|
479
|
+
const timer = wait(remaining, timerController.signal).then(() => {
|
|
480
|
+
if (timerController.signal.aborted) throw timerController.signal.reason;
|
|
481
|
+
throw expire();
|
|
482
|
+
});
|
|
483
|
+
timer.catch(() => undefined);
|
|
484
|
+
try {
|
|
485
|
+
return await Promise.race([operation, timer]);
|
|
486
|
+
} finally {
|
|
487
|
+
operationController.signal.removeEventListener('abort', onOperationAbort);
|
|
488
|
+
stopTimer();
|
|
489
|
+
}
|
|
490
|
+
};
|
|
491
|
+
const writeOutput = async (text: string): Promise<void> => {
|
|
492
|
+
try {
|
|
493
|
+
await withinDeadline(() => Promise.resolve(write(text)));
|
|
494
|
+
} catch (error) {
|
|
495
|
+
if (operationController.signal.aborted) throw error;
|
|
496
|
+
throw new AuthorityCliFailure('output');
|
|
497
|
+
}
|
|
498
|
+
};
|
|
499
|
+
const writeDiagnostic = async (text: string): Promise<void> => {
|
|
500
|
+
let pending: Promise<void>;
|
|
501
|
+
try {
|
|
502
|
+
pending = Promise.resolve(writeError(text));
|
|
503
|
+
} catch {
|
|
504
|
+
return;
|
|
505
|
+
}
|
|
506
|
+
pending.catch(() => undefined);
|
|
507
|
+
if (operationController.signal.aborted) return;
|
|
508
|
+
try {
|
|
509
|
+
await withinDeadline(() => pending);
|
|
510
|
+
} catch {
|
|
511
|
+
// Diagnostics are best effort. A failed or timed-out stderr must not recurse into
|
|
512
|
+
// another diagnostic or keep signal handlers and the scoped client alive.
|
|
513
|
+
}
|
|
514
|
+
};
|
|
515
|
+
const validateOperation = (operation: IAuthSwitchOperation, expectedId: string,
|
|
516
|
+
previousRevision?: number): IAuthSwitchOperation => {
|
|
517
|
+
if (operation.id !== expectedId || (previousRevision !== undefined && operation.revision < previousRevision)) {
|
|
518
|
+
throw new AuthorityCliFailure('response');
|
|
519
|
+
}
|
|
520
|
+
return operation;
|
|
521
|
+
};
|
|
522
|
+
const validatePreuseOperation = (operation: IAuthSwitchPreuseOperation, expectedId: string,
|
|
523
|
+
previousRevision?: number, expected?: {
|
|
524
|
+
accountId: string; loginId: string; requestedModel: string | null;
|
|
525
|
+
}): IAuthSwitchPreuseOperation => {
|
|
526
|
+
if (operation.id !== expectedId || (previousRevision !== undefined && operation.revision < previousRevision)
|
|
527
|
+
|| (expected && (operation.accountId !== expected.accountId || operation.loginId !== expected.loginId
|
|
528
|
+
|| operation.requestedModel !== expected.requestedModel))) {
|
|
529
|
+
throw new AuthorityCliFailure('response');
|
|
530
|
+
}
|
|
531
|
+
return operation;
|
|
532
|
+
};
|
|
533
|
+
try {
|
|
534
|
+
client = options.clientFactory?.() ?? new ScopedAuthorityCliClient();
|
|
535
|
+
const activeClient = client;
|
|
536
|
+
if (options.signal?.aborted) close();
|
|
537
|
+
else options.signal?.addEventListener('abort', close, { once: true });
|
|
538
|
+
if (!options.signal) {
|
|
539
|
+
process.once('SIGINT', close);
|
|
540
|
+
process.once('SIGTERM', close);
|
|
541
|
+
}
|
|
542
|
+
if (cancelled) throw new Error('Authswitch authority request cancelled.');
|
|
543
|
+
const followOperation = async (initial: IAuthSwitchOperation): Promise<IAuthSwitchOperation> => {
|
|
544
|
+
let current = validateOperation(initial, initial.id);
|
|
545
|
+
await writeOutput(renderOperation(current, command.json));
|
|
546
|
+
while (!terminalOperation(current)) {
|
|
547
|
+
await withinDeadline(() => wait(operationPollIntervalMs, operationController.signal));
|
|
548
|
+
const next = validateOperation(
|
|
549
|
+
await withinDeadline(() => activeClient.getOperation(current.id)), current.id, current.revision);
|
|
550
|
+
if (next.revision !== current.revision) await writeOutput(renderOperation(next, command.json));
|
|
551
|
+
current = next;
|
|
552
|
+
}
|
|
553
|
+
return current;
|
|
554
|
+
};
|
|
555
|
+
const followPreuseOperation = async (initial: IAuthSwitchPreuseOperation,
|
|
556
|
+
batch: boolean): Promise<IAuthSwitchPreuseOperation> => {
|
|
557
|
+
const expected = { accountId: initial.accountId, loginId: initial.loginId,
|
|
558
|
+
requestedModel: initial.requestedModel };
|
|
559
|
+
let current = validatePreuseOperation(initial, initial.id, undefined, expected);
|
|
560
|
+
await writeOutput(renderPreuseOperation(current, command.json, batch));
|
|
561
|
+
while (!terminalPreuseOperation(current)) {
|
|
562
|
+
await withinDeadline(() => wait(operationPollIntervalMs, operationController.signal));
|
|
563
|
+
const next = validatePreuseOperation(
|
|
564
|
+
await withinDeadline(() => activeClient.getPreuse(current.id)),
|
|
565
|
+
current.id, current.revision, expected);
|
|
566
|
+
if (next.revision !== current.revision) {
|
|
567
|
+
await writeOutput(renderPreuseOperation(next, command.json, batch));
|
|
568
|
+
}
|
|
569
|
+
current = next;
|
|
570
|
+
}
|
|
571
|
+
return current;
|
|
572
|
+
};
|
|
573
|
+
if (command.kind === 'list') {
|
|
574
|
+
const snapshot = await activeClient.snapshotAll();
|
|
575
|
+
await writeOutput(command.json ? JSON.stringify(snapshot) + '\n' : renderList(snapshot));
|
|
576
|
+
return 0;
|
|
577
|
+
}
|
|
578
|
+
if (command.kind === 'doctor') {
|
|
579
|
+
await runDoctor(activeClient, command.json, writeOutput);
|
|
580
|
+
return 0;
|
|
581
|
+
}
|
|
582
|
+
if (command.kind === 'preuseGet' || command.kind === 'preuseCancel') {
|
|
583
|
+
const operation = validatePreuseOperation(command.kind === 'preuseGet'
|
|
584
|
+
? await activeClient.getPreuse(command.operationId)
|
|
585
|
+
: await activeClient.cancelPreuse(command.operationId), command.operationId);
|
|
586
|
+
await writeOutput(renderPreuseOperation(operation, command.json));
|
|
587
|
+
return 0;
|
|
588
|
+
}
|
|
589
|
+
if (command.kind === 'get' || command.kind === 'cancel') {
|
|
590
|
+
const operation = validateOperation(command.kind === 'get'
|
|
591
|
+
? await activeClient.getOperation(command.operationId)
|
|
592
|
+
: await activeClient.cancelOperation(command.operationId), command.operationId);
|
|
593
|
+
await writeOutput(renderOperation(operation, command.json));
|
|
594
|
+
return 0;
|
|
595
|
+
}
|
|
596
|
+
if (command.kind === 'preuseResume') {
|
|
597
|
+
deadlineAt = now() + operationDeadlineMs;
|
|
598
|
+
operationIdForHint = command.operationId;
|
|
599
|
+
preuseHint = true;
|
|
600
|
+
const initial = validatePreuseOperation(
|
|
601
|
+
await withinDeadline(() => activeClient.getPreuse(command.operationId)), command.operationId);
|
|
602
|
+
const finalOperation = await followPreuseOperation(initial, false);
|
|
603
|
+
if (finalOperation.state !== 'complete') {
|
|
604
|
+
await writeDiagnostic('Authswitch authority preuse was unsuccessful.\n');
|
|
605
|
+
return 1;
|
|
606
|
+
}
|
|
607
|
+
return 0;
|
|
608
|
+
}
|
|
609
|
+
if (command.kind === 'preuse') {
|
|
610
|
+
if (command.target === 'all') {
|
|
611
|
+
deadlineAt = now() + operationDeadlineMs;
|
|
612
|
+
const snapshot = await withinDeadline(() => activeClient.snapshotAll());
|
|
613
|
+
let unsuccessful = false;
|
|
614
|
+
for (const login of preuseBatchTargets(snapshot)) {
|
|
615
|
+
if (operationController.signal.aborted) throw operationController.signal.reason;
|
|
616
|
+
deadlineAt = now() + operationDeadlineMs;
|
|
617
|
+
if (!login.capabilities.canPreuse) {
|
|
618
|
+
operationIdForHint = null;
|
|
619
|
+
const skip: IPreuseBatchSkip = {
|
|
620
|
+
type: 'skipped', snapshotRevision: snapshot.revision,
|
|
621
|
+
accountId: login.accountId, loginId: login.id, loginRevision: login.revision,
|
|
622
|
+
statusObservedAt: login.statusObservedAt, health: login.health, problem: login.problem,
|
|
623
|
+
reason: 'snapshot_not_preuse_capable',
|
|
624
|
+
};
|
|
625
|
+
await writeOutput(renderPreuseSkip(skip, command.json));
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const operationId = operationIdFactory();
|
|
629
|
+
operationIdForHint = operationId;
|
|
630
|
+
preuseHint = true;
|
|
631
|
+
beginAttempted = true;
|
|
632
|
+
beginResponded = false;
|
|
633
|
+
const expected = { accountId: login.accountId, loginId: login.id,
|
|
634
|
+
requestedModel: command.model ?? null };
|
|
635
|
+
const initial = await withinDeadline(() => activeClient.startPreuse({
|
|
636
|
+
operationId, accountId: login.accountId, loginId: login.id, purpose: 'openai_managed',
|
|
637
|
+
prompt: command.prompt, ...(command.model === undefined ? {} : { model: command.model }),
|
|
638
|
+
}));
|
|
639
|
+
beginResponded = true;
|
|
640
|
+
validatePreuseOperation(initial, operationId, undefined, expected);
|
|
641
|
+
const finalOperation = await followPreuseOperation(initial, true);
|
|
642
|
+
if (finalOperation.state !== 'complete') unsuccessful = true;
|
|
643
|
+
}
|
|
644
|
+
if (unsuccessful) {
|
|
645
|
+
await writeDiagnostic('Authswitch authority preuse was unsuccessful.\n');
|
|
646
|
+
return 1;
|
|
647
|
+
}
|
|
648
|
+
return 0;
|
|
649
|
+
}
|
|
650
|
+
deadlineAt = now() + operationDeadlineMs;
|
|
651
|
+
const target = command.target;
|
|
652
|
+
const operationId = operationIdFactory();
|
|
653
|
+
operationIdForHint = operationId;
|
|
654
|
+
preuseHint = true;
|
|
655
|
+
beginAttempted = true;
|
|
656
|
+
const expected = { accountId: target.accountId, loginId: target.loginId,
|
|
657
|
+
requestedModel: command.model ?? null };
|
|
658
|
+
const initial = await withinDeadline(() => activeClient.startPreuse({
|
|
659
|
+
operationId, accountId: target.accountId, loginId: target.loginId,
|
|
660
|
+
purpose: 'openai_managed', prompt: command.prompt,
|
|
661
|
+
...(command.model === undefined ? {} : { model: command.model }),
|
|
662
|
+
}));
|
|
663
|
+
beginResponded = true;
|
|
664
|
+
validatePreuseOperation(initial, operationId, undefined, expected);
|
|
665
|
+
const finalOperation = await followPreuseOperation(initial, false);
|
|
666
|
+
if (finalOperation.state !== 'complete') {
|
|
667
|
+
await writeDiagnostic('Authswitch authority preuse was unsuccessful.\n');
|
|
668
|
+
return 1;
|
|
669
|
+
}
|
|
670
|
+
return 0;
|
|
671
|
+
}
|
|
672
|
+
deadlineAt = now() + operationDeadlineMs;
|
|
673
|
+
let initial: IAuthSwitchOperation;
|
|
674
|
+
if (command.kind === 'resume') {
|
|
675
|
+
operationIdForHint = command.operationId;
|
|
676
|
+
initial = validateOperation(
|
|
677
|
+
await withinDeadline(() => activeClient.getOperation(command.operationId)), command.operationId);
|
|
678
|
+
} else {
|
|
679
|
+
const operationId = operationIdFactory();
|
|
680
|
+
operationIdForHint = operationId;
|
|
681
|
+
beginAttempted = true;
|
|
682
|
+
initial = await withinDeadline(() => command.kind === 'add'
|
|
683
|
+
? activeClient.beginAddOpenAi(operationId)
|
|
684
|
+
: activeClient.beginReauthOpenAi(operationId, command.accountId, command.loginId, 'openai_managed'));
|
|
685
|
+
beginResponded = true;
|
|
686
|
+
validateOperation(initial, operationId);
|
|
687
|
+
}
|
|
688
|
+
const finalOperation = await followOperation(initial);
|
|
689
|
+
if (finalOperation.state !== 'complete') {
|
|
690
|
+
await writeDiagnostic('Authswitch authority sign-in was unsuccessful.\n');
|
|
691
|
+
return 1;
|
|
692
|
+
}
|
|
693
|
+
return 0;
|
|
694
|
+
} catch (error) {
|
|
695
|
+
let message = cancelled ? 'Authswitch authority request was cancelled.\n'
|
|
696
|
+
: timedOut ? 'Authswitch authority operation timed out.\n'
|
|
697
|
+
: beginAttempted && !beginResponded
|
|
698
|
+
? 'Authswitch authority operation start response was lost.\n'
|
|
699
|
+
: error instanceof AuthorityCliFailure && error.kind === 'output'
|
|
700
|
+
? 'Authswitch authority output failed.\n'
|
|
701
|
+
: error instanceof AuthorityCliFailure && error.kind === 'response'
|
|
702
|
+
? 'Authswitch authority daemon returned an invalid response.\n'
|
|
703
|
+
: 'Authswitch authority daemon is unavailable.\n';
|
|
704
|
+
if (operationIdForHint !== null) {
|
|
705
|
+
const resume = preuseHint ? preuseResumeCommand(operationIdForHint, command.json)
|
|
706
|
+
: resumeCommand(operationIdForHint, command.json);
|
|
707
|
+
message += `Operation ID: ${safe(operationIdForHint)}\nResume: ${resume}\n`;
|
|
708
|
+
}
|
|
709
|
+
await writeDiagnostic(message);
|
|
710
|
+
return 1;
|
|
711
|
+
} finally {
|
|
712
|
+
options.signal?.removeEventListener('abort', close);
|
|
713
|
+
if (!options.signal) {
|
|
714
|
+
process.off('SIGINT', close);
|
|
715
|
+
process.off('SIGTERM', close);
|
|
716
|
+
}
|
|
717
|
+
closeClient();
|
|
718
|
+
}
|
|
719
|
+
};
|