@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,195 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { accountDetails, accountPlan, accountQuotaSummary, accountResets, accountState, accountUsageWindows, usagePeriod, until, readAccountRows } from './accounts.js';
|
|
3
|
+
import { plainText } from './formatting.js';
|
|
4
|
+
import { AuthSwitchOperations } from './classes.operations.js';
|
|
5
|
+
/** Owns account-management actions; terminal rendering and interaction belong to smartconsole. */
|
|
6
|
+
export class AuthSwitchTui {
|
|
7
|
+
harnesses;
|
|
8
|
+
out;
|
|
9
|
+
operations;
|
|
10
|
+
constructor(harnesses, out, operations = new AuthSwitchOperations()) {
|
|
11
|
+
this.harnesses = harnesses;
|
|
12
|
+
this.out = out;
|
|
13
|
+
this.operations = operations;
|
|
14
|
+
}
|
|
15
|
+
async run(preferredArg) {
|
|
16
|
+
let harness = preferredArg ?? this.harnesses[0];
|
|
17
|
+
if (!harness) {
|
|
18
|
+
await this.out.warn('No harnesses registered.');
|
|
19
|
+
return 2;
|
|
20
|
+
}
|
|
21
|
+
const ui = this.out.tui;
|
|
22
|
+
let state;
|
|
23
|
+
let rows = [];
|
|
24
|
+
const footer = ui.text('Loading account status…', { height: 2 });
|
|
25
|
+
const details = ui.viewer('Select an account to inspect its status.');
|
|
26
|
+
const table = ui.table({
|
|
27
|
+
rows: [], rowKey: row => JSON.stringify([row.harness.id, row.account.id]),
|
|
28
|
+
columns: [
|
|
29
|
+
{ key: 'account', title: 'Account', value: row => plainText(row.account.label) },
|
|
30
|
+
{ key: 'state', title: 'State', value: accountState },
|
|
31
|
+
{ key: 'plan', title: 'Plan', value: accountPlan },
|
|
32
|
+
{ key: 'usage', title: 'Usage / reset', value: row => accountQuotaSummary(row, Date.now()).replaceAll('\n', ' / ') },
|
|
33
|
+
{ key: 'resets', title: 'Resets', value: row => row.status?.summary?.resets?.available, render: accountResets, align: 'right' },
|
|
34
|
+
],
|
|
35
|
+
onSelect: () => updateDetails(),
|
|
36
|
+
onActivate: async (_row, screen) => { await perform(screen, () => switchSelected(screen)); },
|
|
37
|
+
});
|
|
38
|
+
const updateDetails = () => { details.setText(table.selected ? accountDetails(table.selected) : state?.saveUnavailableReason ?? harness.loginHint); };
|
|
39
|
+
const showOutcome = (outcomeArg) => {
|
|
40
|
+
for (const line of outcomeArg.lines)
|
|
41
|
+
ui.logs.append(plainText(line));
|
|
42
|
+
for (const problem of outcomeArg.problems)
|
|
43
|
+
ui.logs.append('Incomplete: ' + plainText(problem));
|
|
44
|
+
footer.setText(outcomeArg.problems.length ? 'Incomplete: ' + outcomeArg.problems.map(plainText).join('; ') : outcomeArg.lines.map(plainText).join(' · ') || 'Done.');
|
|
45
|
+
return outcomeArg.problems.length === 0;
|
|
46
|
+
};
|
|
47
|
+
const refresh = async (screen) => {
|
|
48
|
+
footer.setText(`Loading ${plainText(harness.label)} accounts and live status…`);
|
|
49
|
+
await screen.invalidate();
|
|
50
|
+
try {
|
|
51
|
+
const result = await readAccountRows(harness, { signal: screen.signal, onUpdate: async (updatedArg, stateArg) => {
|
|
52
|
+
if (screen.signal.aborted)
|
|
53
|
+
return;
|
|
54
|
+
rows = updatedArg;
|
|
55
|
+
state = stateArg;
|
|
56
|
+
table.setRows(rows);
|
|
57
|
+
updateDetails();
|
|
58
|
+
await screen.invalidate();
|
|
59
|
+
} });
|
|
60
|
+
if (screen.signal.aborted)
|
|
61
|
+
return;
|
|
62
|
+
state = result.state;
|
|
63
|
+
rows = result.rows;
|
|
64
|
+
const failures = rows.filter(row => row.status?.problems.length).length;
|
|
65
|
+
footer.setText(`${rows.length} account(s) · ${failures ? `${failures} with unavailable status sections` : 'Status refreshed'}${state.saveUnavailableReason ? ' · ' + plainText(state.saveUnavailableReason) : ''}`);
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
state = undefined;
|
|
69
|
+
rows = [];
|
|
70
|
+
table.setRows([]);
|
|
71
|
+
footer.setText(`Could not read ${plainText(harness.label)} accounts. Run authswitch ${harness.id} doctor.`);
|
|
72
|
+
}
|
|
73
|
+
updateDetails();
|
|
74
|
+
};
|
|
75
|
+
const perform = async (screen, action) => {
|
|
76
|
+
if (screen.signal.aborted)
|
|
77
|
+
return;
|
|
78
|
+
try {
|
|
79
|
+
await action();
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
footer.setText(`Operation failed. Run authswitch ${harness.id} doctor for diagnostics.`);
|
|
83
|
+
}
|
|
84
|
+
updateDetails();
|
|
85
|
+
};
|
|
86
|
+
const save = async (screen, keepActiveArg) => {
|
|
87
|
+
const latest = await harness.readState();
|
|
88
|
+
const activeAccounts = latest.accounts.filter(account => account.isActive);
|
|
89
|
+
const active = activeAccounts.find(account => account.id === table.selected?.account.id) ?? (activeAccounts.length === 1 ? activeAccounts[0] : undefined);
|
|
90
|
+
if (!active && activeAccounts.length > 1) {
|
|
91
|
+
footer.setText('Select the active account you want to save.');
|
|
92
|
+
return;
|
|
93
|
+
}
|
|
94
|
+
if (!active || latest.saveUnavailableReason) {
|
|
95
|
+
footer.setText(latest.saveUnavailableReason ?? 'No active login to save.');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
if (!await screen.confirm(`Save ${plainText(active.label)}${keepActiveArg ? ' and keep it active' : ' and clear the active login'}?`))
|
|
99
|
+
return;
|
|
100
|
+
if (screen.signal.aborted)
|
|
101
|
+
return;
|
|
102
|
+
const outcome = await this.operations.run(harness, { harnessId: harness.id, action: 'save', keepActive: keepActiveArg, accountId: active.id }, message => screen.confirm(message));
|
|
103
|
+
await refresh(screen);
|
|
104
|
+
showOutcome(outcome);
|
|
105
|
+
};
|
|
106
|
+
const switchSelected = async (screen) => {
|
|
107
|
+
const selected = table.selected;
|
|
108
|
+
if (!selected)
|
|
109
|
+
return;
|
|
110
|
+
const latest = await harness.readState();
|
|
111
|
+
const target = latest.accounts.find(account => account.id === selected.account.id && account.isStashed);
|
|
112
|
+
if (!target) {
|
|
113
|
+
footer.setText('Select an account with a verified saved login.');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
const active = latest.accounts.find(account => account.isActive && account.slotId === target.slotId);
|
|
117
|
+
if (active && !active.isStashed) {
|
|
118
|
+
if (latest.saveUnavailableReason) {
|
|
119
|
+
footer.setText(latest.saveUnavailableReason);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (!await screen.confirm(`${plainText(active.label)} is not saved. Save this login before switching?`, { confirmLabel: 'Save first' }))
|
|
123
|
+
return;
|
|
124
|
+
if (screen.signal.aborted)
|
|
125
|
+
return;
|
|
126
|
+
if (!showOutcome(await this.operations.run(harness, { harnessId: harness.id, action: 'save', keepActive: true, accountId: active.id }, message => screen.confirm(message))))
|
|
127
|
+
return;
|
|
128
|
+
const verified = await harness.readState();
|
|
129
|
+
if (!verified.accounts.some(account => account.isActive && account.isStashed && account.id === active.id)) {
|
|
130
|
+
footer.setText('The current login could not be verified as saved. Switching was cancelled.');
|
|
131
|
+
return;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (!await screen.confirm(`Switch ${plainText(harness.label)} to ${plainText(target.label)}?`, { confirmLabel: 'Switch' }))
|
|
135
|
+
return;
|
|
136
|
+
if (screen.signal.aborted)
|
|
137
|
+
return;
|
|
138
|
+
const outcome = await this.operations.run(harness, { harnessId: harness.id, action: 'switch', accountId: target.id }, message => screen.confirm(message));
|
|
139
|
+
await refresh(screen);
|
|
140
|
+
showOutcome(outcome);
|
|
141
|
+
};
|
|
142
|
+
const remove = async (screen) => {
|
|
143
|
+
const selected = table.selected;
|
|
144
|
+
if (!selected || (!selected.account.isStashed && selected.account.savedAt === null)) {
|
|
145
|
+
footer.setText('Select an account with a saved copy.');
|
|
146
|
+
return;
|
|
147
|
+
}
|
|
148
|
+
if (!await screen.confirm(`Remove the saved login for ${plainText(selected.account.label)}? The active login stays as it is.`, { confirmLabel: 'Remove saved copy' }))
|
|
149
|
+
return;
|
|
150
|
+
if (screen.signal.aborted)
|
|
151
|
+
return;
|
|
152
|
+
const outcome = await harness.removeAccount(selected.account.id);
|
|
153
|
+
await refresh(screen);
|
|
154
|
+
showOutcome(outcome);
|
|
155
|
+
};
|
|
156
|
+
const harnessTable = ui.table({
|
|
157
|
+
rows: this.harnesses, rowKey: item => item.id, selectedKey: harness.id,
|
|
158
|
+
columns: [{ key: 'harness', title: 'Harness', value: item => item.label }],
|
|
159
|
+
onActivate: async (selected, screen) => {
|
|
160
|
+
harness = selected;
|
|
161
|
+
state = undefined;
|
|
162
|
+
table.setRows([]);
|
|
163
|
+
await refresh(screen);
|
|
164
|
+
screen.focus(table);
|
|
165
|
+
},
|
|
166
|
+
});
|
|
167
|
+
const tabs = ui.tabs([{ title: 'Account details', content: details }, { title: 'Activity log', content: ui.logs }]);
|
|
168
|
+
await ui.run({
|
|
169
|
+
view: () => {
|
|
170
|
+
const usage = accountUsageWindows({ status: table.selected?.status })?.slice(0, 2).map(window => ui.progress(`${usagePeriod(window)} (${window.usedPercent}% used; reset in ${until(window.resetAt, Date.now())})`, Math.min(100, window.usedPercent), 100)) ?? [];
|
|
171
|
+
const accountView = ui.column([
|
|
172
|
+
ui.panel(`${plainText(harness.label)} accounts`, table),
|
|
173
|
+
ui.panel('Status and diagnostics', ui.column([...usage, tabs])),
|
|
174
|
+
]);
|
|
175
|
+
return ui.column([
|
|
176
|
+
ui.text('authswitch · account management', { height: 1 }),
|
|
177
|
+
this.harnesses.length > 1 ? ui.row([ui.panel('Harnesses', harnessTable, { width: 23 }), accountView]) : accountView,
|
|
178
|
+
ui.text('Enter switch · a save · c save+clear · d remove · r refresh · g diagnose · Tab focus · q quit', { height: 2 }),
|
|
179
|
+
footer,
|
|
180
|
+
]);
|
|
181
|
+
},
|
|
182
|
+
onReady: async (screen) => { screen.focus(table); await refresh(screen); },
|
|
183
|
+
keys: {
|
|
184
|
+
q: screen => screen.close(),
|
|
185
|
+
r: screen => refresh(screen),
|
|
186
|
+
a: screen => perform(screen, () => save(screen, true)),
|
|
187
|
+
c: screen => perform(screen, () => save(screen, false)),
|
|
188
|
+
d: screen => perform(screen, () => remove(screen)),
|
|
189
|
+
g: screen => perform(screen, async () => { showOutcome(await harness.diagnose()); }),
|
|
190
|
+
},
|
|
191
|
+
});
|
|
192
|
+
return 0;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50dWkuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLnR1aS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUV4QyxPQUFPLEVBQUUsY0FBYyxFQUFFLFdBQVcsRUFBRSxtQkFBbUIsRUFBRSxhQUFhLEVBQUUsWUFBWSxFQUFFLG1CQUFtQixFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsZUFBZSxFQUFvQixNQUFNLGVBQWUsQ0FBQztBQUMxTCxPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDNUMsT0FBTyxFQUFFLG9CQUFvQixFQUFFLE1BQU0seUJBQXlCLENBQUM7QUFFL0Qsa0dBQWtHO0FBQ2xHLE1BQU0sT0FBTyxhQUFhO0lBQ0s7SUFBcUQ7SUFBeUQ7SUFBM0ksWUFBNkIsU0FBa0MsRUFBbUIsR0FBc0MsRUFBbUIsYUFBYSxJQUFJLG9CQUFvQixFQUFFO1FBQXJKLGNBQVMsR0FBVCxTQUFTLENBQXlCO1FBQW1CLFFBQUcsR0FBSCxHQUFHLENBQW1DO1FBQW1CLGVBQVUsR0FBVixVQUFVLENBQTZCO0lBQUcsQ0FBQztJQUUvSyxLQUFLLENBQUMsR0FBRyxDQUFDLFlBQTJCO1FBQzFDLElBQUksT0FBTyxHQUFHLFlBQVksSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBQ2hELElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUFDLE1BQU0sSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsMEJBQTBCLENBQUMsQ0FBQztZQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQUMsQ0FBQztRQUM1RSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQztRQUN4QixJQUFJLEtBQWdDLENBQUM7UUFDckMsSUFBSSxJQUFJLEdBQWtCLEVBQUUsQ0FBQztRQUM3QixNQUFNLE1BQU0sR0FB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
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export declare const dim: (textArg: string) => string;
|
|
2
|
+
export declare const bold: (textArg: string) => string;
|
|
3
|
+
export declare const green: (textArg: string) => string;
|
|
4
|
+
export declare const red: (textArg: string) => string;
|
|
5
|
+
export declare const orange: (textArg: string) => string;
|
|
6
|
+
export declare const cyan: (textArg: string) => string;
|
|
7
|
+
/** Remote labels cannot inject terminal control sequences or extra output rows. */
|
|
8
|
+
export declare const plainText: (textArg: string) => string;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
const styled = () => process.stdout.isTTY === true && !Object.hasOwn(process.env, 'NO_COLOR');
|
|
3
|
+
const render = (textArg, styleArg) => styled() ? plugins.smartconsole.color.toAnsi(plugins.smartconsole.color.text(textArg, styleArg)) : plainText(textArg);
|
|
4
|
+
export const dim = (textArg) => render(textArg, { dim: true });
|
|
5
|
+
export const bold = (textArg) => render(textArg, { bold: true });
|
|
6
|
+
const paint = (textArg, colorArg) => render(textArg, { foreground: colorArg });
|
|
7
|
+
export const green = (textArg) => paint(textArg, 'green');
|
|
8
|
+
export const red = (textArg) => paint(textArg, 'red');
|
|
9
|
+
export const orange = (textArg) => paint(textArg, 'orange');
|
|
10
|
+
export const cyan = (textArg) => paint(textArg, 'cyan');
|
|
11
|
+
/** Remote labels cannot inject terminal control sequences or extra output rows. */
|
|
12
|
+
export const plainText = (textArg) => textArg.replace(/[\u0000-\u001f\u007f-\u009f]/g, '').slice(0, 500);
|
|
13
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybWF0dGluZy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2Zvcm1hdHRpbmcudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFFeEMsTUFBTSxNQUFNLEdBQUcsR0FBWSxFQUFFLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEtBQUssSUFBSSxJQUFJLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0FBQ3ZHLE1BQU0sTUFBTSxHQUFHLENBQUMsT0FBZSxFQUFFLFFBQXlDLEVBQVUsRUFBRSxDQUNwRixNQUFNLEVBQUUsQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxZQUFZLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxPQUFPLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0FBQ3hILE1BQU0sQ0FBQyxNQUFNLEdBQUcsR0FBRyxDQUFDLE9BQWUsRUFBVSxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxFQUFFLEdBQUcsRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQy9FLE1BQU0sQ0FBQyxNQUFNLElBQUksR0FBRyxDQUFDLE9BQWUsRUFBVSxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxFQUFFLElBQUksRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0FBQ2pGLE1BQU0sS0FBSyxHQUFHLENBQUMsT0FBZSxFQUFFLFFBQXlDLEVBQVUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsRUFBRSxVQUFVLEVBQUUsUUFBUSxFQUFFLENBQUMsQ0FBQztBQUNoSSxNQUFNLENBQUMsTUFBTSxLQUFLLEdBQUcsQ0FBQyxPQUFlLEVBQVUsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsT0FBTyxDQUFDLENBQUM7QUFDMUUsTUFBTSxDQUFDLE1BQU0sR0FBRyxHQUFHLENBQUMsT0FBZSxFQUFVLEVBQUUsQ0FBQyxLQUFLLENBQUMsT0FBTyxFQUFFLEtBQUssQ0FBQyxDQUFDO0FBQ3RFLE1BQU0sQ0FBQyxNQUFNLE1BQU0sR0FBRyxDQUFDLE9BQWUsRUFBVSxFQUFFLENBQUMsS0FBSyxDQUFDLE9BQU8sRUFBRSxRQUFRLENBQUMsQ0FBQztBQUM1RSxNQUFNLENBQUMsTUFBTSxJQUFJLEdBQUcsQ0FBQyxPQUFlLEVBQVUsRUFBRSxDQUFDLEtBQUssQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7QUFDeEUsbUZBQW1GO0FBQ25GLE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxDQUFDLE9BQWUsRUFBVSxFQUFFLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQywrQkFBK0IsRUFBRSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsQ0FBQyxFQUFFLEdBQUcsQ0FBQyxDQUFDIn0=
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { IRemoteControlEnrollment, TEnrollmentState } from './interfaces.js';
|
|
2
|
+
/**
|
|
3
|
+
* Writes a secret to `destinationPathArg` atomically and owner-only.
|
|
4
|
+
*
|
|
5
|
+
* Three things matter here, and none of them are free with a plain
|
|
6
|
+
* `writeFileSync`:
|
|
7
|
+
*
|
|
8
|
+
* - The temp file is created with the `wx` flag, so a leftover file from an
|
|
9
|
+
* interrupted run cannot silently receive a credential at whatever mode that
|
|
10
|
+
* run left behind.
|
|
11
|
+
* - Its mode is set explicitly after creation, because `writeFileSync`'s `mode`
|
|
12
|
+
* option only applies when the file is created.
|
|
13
|
+
* - It is removed on every failure path, so a complete credential is never left
|
|
14
|
+
* at a predictable path that nothing lists, cleans, or reports.
|
|
15
|
+
*
|
|
16
|
+
* The rename is atomic within a filesystem, so a reader sees either the old
|
|
17
|
+
* content or the new one, never a partial write.
|
|
18
|
+
*/
|
|
19
|
+
export declare const writeSecretFileAtomically: (destinationPathArg: string, contentArg: string) => void;
|
|
20
|
+
/**
|
|
21
|
+
* Trims third-party process output down to something safe to put in an error
|
|
22
|
+
* message: one line, length-capped, and never empty.
|
|
23
|
+
*/
|
|
24
|
+
export declare const summariseProcessOutput: (stdoutArg: string, stderrArg: string, spawnErrorArg: string | null) => string;
|
|
25
|
+
/**
|
|
26
|
+
* Classifies an enrollment row. See TEnrollmentState for why NULL and 0 are not
|
|
27
|
+
* the same answer.
|
|
28
|
+
*/
|
|
29
|
+
export declare const enrollmentState: (enrollmentArg: IRemoteControlEnrollment) => TEnrollmentState;
|
|
30
|
+
/** How many of these enrollments carry a working pairing. */
|
|
31
|
+
export declare const countPaired: (enrollmentsArg: IRemoteControlEnrollment[]) => number;
|
|
32
|
+
/**
|
|
33
|
+
* Turns a failed Codex invocation into a diagnosis rather than an errno.
|
|
34
|
+
*
|
|
35
|
+
* A timeout and a missing binary are different problems with different fixes,
|
|
36
|
+
* and neither is "the stop command failed" -- surfacing the raw spawn error
|
|
37
|
+
* leaves the user to guess which one they hit.
|
|
38
|
+
*/
|
|
39
|
+
export declare const describeCodexFailure: (binaryArg: string, stdoutArg: string, stderrArg: string, spawnErrorArg: string | null) => string;
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Writes a secret to `destinationPathArg` atomically and owner-only.
|
|
4
|
+
*
|
|
5
|
+
* Three things matter here, and none of them are free with a plain
|
|
6
|
+
* `writeFileSync`:
|
|
7
|
+
*
|
|
8
|
+
* - The temp file is created with the `wx` flag, so a leftover file from an
|
|
9
|
+
* interrupted run cannot silently receive a credential at whatever mode that
|
|
10
|
+
* run left behind.
|
|
11
|
+
* - Its mode is set explicitly after creation, because `writeFileSync`'s `mode`
|
|
12
|
+
* option only applies when the file is created.
|
|
13
|
+
* - It is removed on every failure path, so a complete credential is never left
|
|
14
|
+
* at a predictable path that nothing lists, cleans, or reports.
|
|
15
|
+
*
|
|
16
|
+
* The rename is atomic within a filesystem, so a reader sees either the old
|
|
17
|
+
* content or the new one, never a partial write.
|
|
18
|
+
*/
|
|
19
|
+
export const writeSecretFileAtomically = (destinationPathArg, contentArg) => {
|
|
20
|
+
const tempPath = `${destinationPathArg}.authswitch-tmp`;
|
|
21
|
+
// A stale temp file means an earlier run died mid-write. Its content is
|
|
22
|
+
// superseded by what we are about to write, so clearing it is safe -- and
|
|
23
|
+
// necessary, since `wx` would otherwise fail forever.
|
|
24
|
+
if (plugins.fs.existsSync(tempPath)) {
|
|
25
|
+
plugins.fs.rmSync(tempPath, { force: true });
|
|
26
|
+
}
|
|
27
|
+
let handle = null;
|
|
28
|
+
try {
|
|
29
|
+
handle = plugins.fs.openSync(tempPath, 'wx', 0o600);
|
|
30
|
+
plugins.fs.fchmodSync(handle, 0o600);
|
|
31
|
+
plugins.fs.writeFileSync(handle, contentArg, { encoding: 'utf8' });
|
|
32
|
+
plugins.fs.fsyncSync(handle);
|
|
33
|
+
plugins.fs.closeSync(handle);
|
|
34
|
+
handle = null;
|
|
35
|
+
plugins.fs.renameSync(tempPath, destinationPathArg);
|
|
36
|
+
}
|
|
37
|
+
catch (errorArg) {
|
|
38
|
+
if (handle !== null) {
|
|
39
|
+
try {
|
|
40
|
+
plugins.fs.closeSync(handle);
|
|
41
|
+
}
|
|
42
|
+
catch {
|
|
43
|
+
// The handle is being discarded either way.
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
plugins.fs.rmSync(tempPath, { force: true });
|
|
47
|
+
throw errorArg;
|
|
48
|
+
}
|
|
49
|
+
plugins.fs.chmodSync(destinationPathArg, 0o600);
|
|
50
|
+
};
|
|
51
|
+
/**
|
|
52
|
+
* Trims third-party process output down to something safe to put in an error
|
|
53
|
+
* message: one line, length-capped, and never empty.
|
|
54
|
+
*/
|
|
55
|
+
export const summariseProcessOutput = (stdoutArg, stderrArg, spawnErrorArg) => {
|
|
56
|
+
const candidate = (spawnErrorArg ?? stderrArg.trim() ?? '') || stdoutArg.trim();
|
|
57
|
+
if (!candidate) {
|
|
58
|
+
return 'no output';
|
|
59
|
+
}
|
|
60
|
+
const firstLine = candidate.split('\n').find((lineArg) => lineArg.trim().length > 0) ?? '';
|
|
61
|
+
const collapsed = firstLine.trim();
|
|
62
|
+
return collapsed.length > 200 ? `${collapsed.slice(0, 200)}...` : collapsed;
|
|
63
|
+
};
|
|
64
|
+
/**
|
|
65
|
+
* Classifies an enrollment row. See TEnrollmentState for why NULL and 0 are not
|
|
66
|
+
* the same answer.
|
|
67
|
+
*/
|
|
68
|
+
export const enrollmentState = (enrollmentArg) => {
|
|
69
|
+
if (enrollmentArg.remoteControlEnabled === null) {
|
|
70
|
+
return 'unpaired';
|
|
71
|
+
}
|
|
72
|
+
return enrollmentArg.remoteControlEnabled === 0 ? 'disabled' : 'paired';
|
|
73
|
+
};
|
|
74
|
+
/** How many of these enrollments carry a working pairing. */
|
|
75
|
+
export const countPaired = (enrollmentsArg) => enrollmentsArg.filter((enrollmentArg) => enrollmentState(enrollmentArg) === 'paired').length;
|
|
76
|
+
/**
|
|
77
|
+
* Turns a failed Codex invocation into a diagnosis rather than an errno.
|
|
78
|
+
*
|
|
79
|
+
* A timeout and a missing binary are different problems with different fixes,
|
|
80
|
+
* and neither is "the stop command failed" -- surfacing the raw spawn error
|
|
81
|
+
* leaves the user to guess which one they hit.
|
|
82
|
+
*/
|
|
83
|
+
export const describeCodexFailure = (binaryArg, stdoutArg, stderrArg, spawnErrorArg) => {
|
|
84
|
+
if (spawnErrorArg && /ETIMEDOUT/i.test(spawnErrorArg)) {
|
|
85
|
+
return `the Codex app-server did not respond in time - it is running but unresponsive. Try \`codex app-server daemon restart\`, then run this again`;
|
|
86
|
+
}
|
|
87
|
+
if (spawnErrorArg && /ENOENT/i.test(spawnErrorArg)) {
|
|
88
|
+
return `the Codex CLI "${binaryArg}" was not found - put it on PATH or set AUTHSWITCH_CODEX_BIN to its full path`;
|
|
89
|
+
}
|
|
90
|
+
return summariseProcessOutput(stdoutArg, stderrArg, spawnErrorArg);
|
|
91
|
+
};
|
|
92
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGVscGVycy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2hlbHBlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFHeEM7Ozs7Ozs7Ozs7Ozs7Ozs7R0FnQkc7QUFDSCxNQUFNLENBQUMsTUFBTSx5QkFBeUIsR0FBRyxDQUN2QyxrQkFBMEIsRUFDMUIsVUFBa0IsRUFDWixFQUFFO0lBQ1IsTUFBTSxRQUFRLEdBQUcsR0FBRyxrQkFBa0IsaUJBQWlCLENBQUM7SUFDeEQsd0VBQXdFO0lBQ3hFLDBFQUEwRTtJQUMxRSxzREFBc0Q7SUFDdEQsSUFBSSxPQUFPLENBQUMsRUFBRSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsRUFBRSxDQUFDO1FBQ3BDLE9BQU8sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLFFBQVEsRUFBRSxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxJQUFJLE1BQU0sR0FBa0IsSUFBSSxDQUFDO0lBQ2pDLElBQUksQ0FBQztRQUNILE1BQU0sR0FBRyxPQUFPLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3BELE9BQU8sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyQyxPQUFPLENBQUMsRUFBRSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxDQUFDLENBQUM7UUFDbkUsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDN0IsTUFBTSxHQUFHLElBQUksQ0FBQztRQUNkLE9BQU8sQ0FBQyxFQUFFLENBQUMs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
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export * from './interfaces.js';
|
|
2
|
+
export * from './interfaces.harness.js';
|
|
3
|
+
export * from './interfaces.list.js';
|
|
4
|
+
export * from './classes.codexharness.js';
|
|
5
|
+
export * from './classes.opencodeharness.js';
|
|
6
|
+
export * from './classes.claudecodeharness.js';
|
|
7
|
+
export * from './classes.claudestatus.js';
|
|
8
|
+
export * from './classes.codexstatus.js';
|
|
9
|
+
export * from './classes.codexpreuse.js';
|
|
10
|
+
export * from './preuse.js';
|
|
11
|
+
export * from './helpers.js';
|
|
12
|
+
export * from './classes.codexhome.js';
|
|
13
|
+
export * from './classes.codexauth.js';
|
|
14
|
+
export * from './classes.remotecontrol.js';
|
|
15
|
+
export * from './classes.stashstore.js';
|
|
16
|
+
export * from './classes.codexdaemon.js';
|
|
17
|
+
export * from './classes.codexswitcher.js';
|
|
18
|
+
export * from './classes.cli.js';
|
|
19
|
+
export * from './classes.login.js';
|
|
20
|
+
export * from './classes.operations.js';
|
|
21
|
+
export * from './classes.service.js';
|
|
22
|
+
export declare const runCli: (argvArg?: string[]) => Promise<void>;
|
package/dist_ts/index.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
export * from './interfaces.js';
|
|
2
|
+
export * from './interfaces.harness.js';
|
|
3
|
+
export * from './interfaces.list.js';
|
|
4
|
+
export * from './classes.codexharness.js';
|
|
5
|
+
export * from './classes.opencodeharness.js';
|
|
6
|
+
export * from './classes.claudecodeharness.js';
|
|
7
|
+
export * from './classes.claudestatus.js';
|
|
8
|
+
export * from './classes.codexstatus.js';
|
|
9
|
+
export * from './classes.codexpreuse.js';
|
|
10
|
+
export * from './preuse.js';
|
|
11
|
+
export * from './helpers.js';
|
|
12
|
+
export * from './classes.codexhome.js';
|
|
13
|
+
export * from './classes.codexauth.js';
|
|
14
|
+
export * from './classes.remotecontrol.js';
|
|
15
|
+
export * from './classes.stashstore.js';
|
|
16
|
+
export * from './classes.codexdaemon.js';
|
|
17
|
+
export * from './classes.codexswitcher.js';
|
|
18
|
+
export * from './classes.cli.js';
|
|
19
|
+
export * from './classes.login.js';
|
|
20
|
+
export * from './classes.operations.js';
|
|
21
|
+
export * from './classes.service.js';
|
|
22
|
+
import { AuthSwitchCli } from './classes.cli.js';
|
|
23
|
+
export const runCli = async (argvArg = process.argv.slice(2)) => {
|
|
24
|
+
const exitCode = await new AuthSwitchCli().run(argvArg);
|
|
25
|
+
process.exitCode = exitCode;
|
|
26
|
+
};
|
|
27
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxjQUFjLGlCQUFpQixDQUFDO0FBQ2hDLGNBQWMseUJBQXlCLENBQUM7QUFDeEMsY0FBYyxzQkFBc0IsQ0FBQztBQUNyQyxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMsOEJBQThCLENBQUM7QUFDN0MsY0FBYyxnQ0FBZ0MsQ0FBQztBQUMvQyxjQUFjLDJCQUEyQixDQUFDO0FBQzFDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLGFBQWEsQ0FBQztBQUM1QixjQUFjLGNBQWMsQ0FBQztBQUM3QixjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsd0JBQXdCLENBQUM7QUFDdkMsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLHlCQUF5QixDQUFDO0FBQ3hDLGNBQWMsMEJBQTBCLENBQUM7QUFDekMsY0FBYyw0QkFBNEIsQ0FBQztBQUMzQyxjQUFjLGtCQUFrQixDQUFDO0FBQ2pDLGNBQWMsb0JBQW9CLENBQUM7QUFDbkMsY0FBYyx5QkFBeUIsQ0FBQztBQUN4QyxjQUFjLHNCQUFzQixDQUFDO0FBRXJDLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUVqRCxNQUFNLENBQUMsTUFBTSxNQUFNLEdBQUcsS0FBSyxFQUFFLFVBQW9CLE9BQU8sQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxFQUFpQixFQUFFO0lBQ3ZGLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxhQUFhLEVBQUUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUM7SUFDeEQsT0FBTyxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUM7QUFDOUIsQ0FBQyxDQUFDIn0=
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lowercase harness namespace. Adapters are registered independently of the CLI.
|
|
3
|
+
*/
|
|
4
|
+
export type THarnessName = string;
|
|
5
|
+
/**
|
|
6
|
+
* Where the currently active Codex credential lives.
|
|
7
|
+
* - 'file' -> $CODEX_HOME/auth.json
|
|
8
|
+
* - 'keyring' -> an OS keyring entry (authswitch cannot move these)
|
|
9
|
+
* - 'none' -> no credential is active
|
|
10
|
+
*/
|
|
11
|
+
export type TAuthSource = 'file' | 'keyring' | 'none';
|
|
12
|
+
/**
|
|
13
|
+
* How a stashed credential identifies its account.
|
|
14
|
+
* - 'chatgpt' -> ChatGPT OAuth login, identified by the id_token email claim
|
|
15
|
+
* - 'apikey' -> plain API key login, which carries no email
|
|
16
|
+
*/
|
|
17
|
+
export type TAccountKind = 'chatgpt' | 'apikey';
|
|
18
|
+
/**
|
|
19
|
+
* Identity extracted from a Codex credential without ever exposing the token.
|
|
20
|
+
*/
|
|
21
|
+
export interface ICodexIdentity {
|
|
22
|
+
kind: TAccountKind;
|
|
23
|
+
/** The account email, or a synthetic `apikey:<fingerprint>` label for API-key logins. */
|
|
24
|
+
email: string;
|
|
25
|
+
accountId: string | null;
|
|
26
|
+
planType: string | null;
|
|
27
|
+
userId: string | null;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* The active credential as found on disk, plus its decoded identity.
|
|
31
|
+
* `raw` is the verbatim file content and is never logged.
|
|
32
|
+
*/
|
|
33
|
+
export interface IActiveAuth {
|
|
34
|
+
source: TAuthSource;
|
|
35
|
+
authFilePath: string;
|
|
36
|
+
identity: ICodexIdentity | null;
|
|
37
|
+
raw: string | null;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* One row of the `remote_control_enrollments` table in Codex' state database.
|
|
41
|
+
* This is the record that binds a Codex app-server to a paired ChatGPT client.
|
|
42
|
+
*/
|
|
43
|
+
export interface IRemoteControlEnrollment {
|
|
44
|
+
websocketUrl: string;
|
|
45
|
+
accountId: string;
|
|
46
|
+
appServerClientName: string;
|
|
47
|
+
serverId: string;
|
|
48
|
+
environmentId: string;
|
|
49
|
+
serverName: string;
|
|
50
|
+
updatedAt: number;
|
|
51
|
+
remoteControlEnabled: number | null;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Metadata stored alongside a stashed credential.
|
|
55
|
+
*/
|
|
56
|
+
export interface IStashEntry {
|
|
57
|
+
email: string;
|
|
58
|
+
kind: TAccountKind;
|
|
59
|
+
accountId: string | null;
|
|
60
|
+
planType: string | null;
|
|
61
|
+
userId: string | null;
|
|
62
|
+
stashedAt: string;
|
|
63
|
+
codexHome: string;
|
|
64
|
+
enrollments: IRemoteControlEnrollment[];
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* How far along an enrollment row is.
|
|
68
|
+
*
|
|
69
|
+
* Codex writes the row when an account registers a server, but its upsert
|
|
70
|
+
* deliberately leaves `remote_control_enabled` alone, so a freshly logged-in
|
|
71
|
+
* account starts at NULL. A row is therefore not the same thing as a working
|
|
72
|
+
* pairing, and the three states have to stay distinguishable:
|
|
73
|
+
* - 'paired' -> remote_control_enabled = 1, reachable from the ChatGPT app
|
|
74
|
+
* - 'disabled' -> remote_control_enabled = 0, deliberately turned off
|
|
75
|
+
* - 'unpaired' -> remote_control_enabled IS NULL, registered but never paired
|
|
76
|
+
*/
|
|
77
|
+
export type TEnrollmentState = 'paired' | 'disabled' | 'unpaired';
|
|
78
|
+
/**
|
|
79
|
+
* A stash entry plus the derived facts the CLI needs for display.
|
|
80
|
+
*/
|
|
81
|
+
export interface IStashListing extends IStashEntry {
|
|
82
|
+
slug: string;
|
|
83
|
+
isActive: boolean;
|
|
84
|
+
/** Rows stashed for this account, paired or not. */
|
|
85
|
+
enrollmentsTotal: number;
|
|
86
|
+
/** Rows that actually carry a working pairing. */
|
|
87
|
+
enrollmentsPaired: number;
|
|
88
|
+
/**
|
|
89
|
+
* True only when at least one enrollment is paired. A registered-but-unpaired
|
|
90
|
+
* row is not remote control, and reporting it as such would tell the user the
|
|
91
|
+
* account is reachable when it is not.
|
|
92
|
+
*/
|
|
93
|
+
hasRemoteControl: boolean;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* The outcome of running a Codex subcommand.
|
|
97
|
+
*/
|
|
98
|
+
export interface ICommandResult {
|
|
99
|
+
ok: boolean;
|
|
100
|
+
stdout: string;
|
|
101
|
+
stderr: string;
|
|
102
|
+
code: number | null;
|
|
103
|
+
/** Set when the process could not be spawned at all, or timed out. */
|
|
104
|
+
spawnError: string | null;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* What `codex app-server daemon version` reports about the managed daemon.
|
|
108
|
+
*/
|
|
109
|
+
export interface IDaemonStatus {
|
|
110
|
+
running: boolean;
|
|
111
|
+
backend: string | null;
|
|
112
|
+
appServerVersion: string | null;
|
|
113
|
+
cliVersion: string | null;
|
|
114
|
+
socketPath: string | null;
|
|
115
|
+
}
|
|
116
|
+
export interface ICodexSwitcherOptions {
|
|
117
|
+
codexHome?: string;
|
|
118
|
+
stashRoot?: string;
|
|
119
|
+
codexBinary?: string;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Result of stashing the active credential.
|
|
123
|
+
*
|
|
124
|
+
* `complete` is false when the credential was saved but something the user
|
|
125
|
+
* cares about did not finish -- the app-server failing to come back, say.
|
|
126
|
+
*/
|
|
127
|
+
export interface IStashResult {
|
|
128
|
+
entry: IStashEntry;
|
|
129
|
+
daemonRestarted: boolean;
|
|
130
|
+
complete: boolean;
|
|
131
|
+
notes: string[];
|
|
132
|
+
problems: string[];
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Result of a switch, used for reporting and for the CLI exit code.
|
|
136
|
+
*/
|
|
137
|
+
export interface ISwitchResult {
|
|
138
|
+
from: string | null;
|
|
139
|
+
to: string;
|
|
140
|
+
enrollmentsRestored: number;
|
|
141
|
+
daemonRestarted: boolean;
|
|
142
|
+
complete: boolean;
|
|
143
|
+
notes: string[];
|
|
144
|
+
problems: string[];
|
|
145
|
+
}
|