@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.
Files changed (95) hide show
  1. package/.smartconfig.json +34 -0
  2. package/cli.js +21 -0
  3. package/dist_ts/00_commitinfo_data.d.ts +8 -0
  4. package/dist_ts/00_commitinfo_data.js +9 -0
  5. package/dist_ts/accounts.d.ts +31 -0
  6. package/dist_ts/accounts.js +74 -0
  7. package/dist_ts/classes.accountlist.d.ts +17 -0
  8. package/dist_ts/classes.accountlist.js +214 -0
  9. package/dist_ts/classes.claudecodeharness.d.ts +34 -0
  10. package/dist_ts/classes.claudecodeharness.js +123 -0
  11. package/dist_ts/classes.claudestatus.d.ts +8 -0
  12. package/dist_ts/classes.claudestatus.js +139 -0
  13. package/dist_ts/classes.cli.d.ts +31 -0
  14. package/dist_ts/classes.cli.js +584 -0
  15. package/dist_ts/classes.codexauth.d.ts +35 -0
  16. package/dist_ts/classes.codexauth.js +184 -0
  17. package/dist_ts/classes.codexdaemon.d.ts +38 -0
  18. package/dist_ts/classes.codexdaemon.js +122 -0
  19. package/dist_ts/classes.codexharness.d.ts +35 -0
  20. package/dist_ts/classes.codexharness.js +199 -0
  21. package/dist_ts/classes.codexhome.d.ts +25 -0
  22. package/dist_ts/classes.codexhome.js +60 -0
  23. package/dist_ts/classes.codexpreuse.d.ts +8 -0
  24. package/dist_ts/classes.codexpreuse.js +90 -0
  25. package/dist_ts/classes.codexstatus.d.ts +20 -0
  26. package/dist_ts/classes.codexstatus.js +304 -0
  27. package/dist_ts/classes.codexswitcher.d.ts +61 -0
  28. package/dist_ts/classes.codexswitcher.js +226 -0
  29. package/dist_ts/classes.credentialstore.d.ts +32 -0
  30. package/dist_ts/classes.credentialstore.js +115 -0
  31. package/dist_ts/classes.fileharness.d.ts +47 -0
  32. package/dist_ts/classes.fileharness.js +119 -0
  33. package/dist_ts/classes.login.d.ts +42 -0
  34. package/dist_ts/classes.login.js +102 -0
  35. package/dist_ts/classes.opencodeharness.d.ts +34 -0
  36. package/dist_ts/classes.opencodeharness.js +125 -0
  37. package/dist_ts/classes.operations.d.ts +44 -0
  38. package/dist_ts/classes.operations.js +97 -0
  39. package/dist_ts/classes.remotecontrol.d.ts +46 -0
  40. package/dist_ts/classes.remotecontrol.js +169 -0
  41. package/dist_ts/classes.service.d.ts +47 -0
  42. package/dist_ts/classes.service.js +142 -0
  43. package/dist_ts/classes.stashstore.d.ts +63 -0
  44. package/dist_ts/classes.stashstore.js +192 -0
  45. package/dist_ts/classes.tui.d.ts +11 -0
  46. package/dist_ts/classes.tui.js +195 -0
  47. package/dist_ts/formatting.d.ts +8 -0
  48. package/dist_ts/formatting.js +13 -0
  49. package/dist_ts/helpers.d.ts +39 -0
  50. package/dist_ts/helpers.js +92 -0
  51. package/dist_ts/index.d.ts +22 -0
  52. package/dist_ts/index.js +27 -0
  53. package/dist_ts/interfaces.d.ts +145 -0
  54. package/dist_ts/interfaces.harness.d.ts +130 -0
  55. package/dist_ts/interfaces.harness.js +2 -0
  56. package/dist_ts/interfaces.js +2 -0
  57. package/dist_ts/interfaces.list.d.ts +19 -0
  58. package/dist_ts/interfaces.list.js +2 -0
  59. package/dist_ts/plugins.d.ts +14 -0
  60. package/dist_ts/plugins.js +18 -0
  61. package/dist_ts/preuse.d.ts +6 -0
  62. package/dist_ts/preuse.js +13 -0
  63. package/license.md +21 -0
  64. package/package.json +53 -0
  65. package/readme.md +502 -0
  66. package/ts/00_commitinfo_data.ts +8 -0
  67. package/ts/accounts.ts +78 -0
  68. package/ts/classes.accountlist.ts +211 -0
  69. package/ts/classes.claudecodeharness.ts +111 -0
  70. package/ts/classes.claudestatus.ts +99 -0
  71. package/ts/classes.cli.ts +479 -0
  72. package/ts/classes.codexauth.ts +199 -0
  73. package/ts/classes.codexdaemon.ts +137 -0
  74. package/ts/classes.codexharness.ts +233 -0
  75. package/ts/classes.codexhome.ts +68 -0
  76. package/ts/classes.codexpreuse.ts +76 -0
  77. package/ts/classes.codexstatus.ts +257 -0
  78. package/ts/classes.codexswitcher.ts +272 -0
  79. package/ts/classes.credentialstore.ts +101 -0
  80. package/ts/classes.fileharness.ts +120 -0
  81. package/ts/classes.login.ts +103 -0
  82. package/ts/classes.opencodeharness.ts +114 -0
  83. package/ts/classes.operations.ts +101 -0
  84. package/ts/classes.remotecontrol.ts +208 -0
  85. package/ts/classes.service.ts +152 -0
  86. package/ts/classes.stashstore.ts +223 -0
  87. package/ts/classes.tui.ts +138 -0
  88. package/ts/formatting.ts +14 -0
  89. package/ts/helpers.ts +109 -0
  90. package/ts/index.ts +28 -0
  91. package/ts/interfaces.harness.ts +112 -0
  92. package/ts/interfaces.list.ts +19 -0
  93. package/ts/interfaces.ts +158 -0
  94. package/ts/plugins.ts +20 -0
  95. package/ts/preuse.ts +15 -0
@@ -0,0 +1,32 @@
1
+ export declare const credentialRecord: (value: unknown) => Record<string, unknown>;
2
+ export declare const credentialText: (value: unknown) => string | undefined;
3
+ export declare const credentialHash: (value: string) => string;
4
+ /** A bounded file read; malformed secrets never become parser diagnostics in the CLI. */
5
+ export declare const readCredentialDocument: (file: string) => {
6
+ raw: string | null;
7
+ data: Record<string, unknown>;
8
+ };
9
+ export interface IStoredCredential {
10
+ schemaVersion: 1;
11
+ id: string;
12
+ slotId: string;
13
+ identity: string;
14
+ label: string;
15
+ savedAt: string;
16
+ /** Harness-owned payload. This object must never cross the public account interface. */
17
+ credential: Record<string, unknown>;
18
+ }
19
+ /** A single atomic, owner-only record keeps the saved credential and its identity together. */
20
+ export declare class CredentialStore {
21
+ readonly dir: string;
22
+ constructor(harness: string, root?: string);
23
+ id(slot: string, identity: string): string;
24
+ private file;
25
+ read(id: string): IStoredCredential;
26
+ list(): IStoredCredential[];
27
+ save(entry: Omit<IStoredCredential, 'schemaVersion' | 'id' | 'savedAt'>): IStoredCredential;
28
+ remove(id: string): void;
29
+ locked<T>(action: () => T): T;
30
+ }
31
+ /** Native harnesses retain credentials and may refresh them. Refuse writes while one is running. */
32
+ export declare const requireHarnessStopped: (binary: "opencode" | "claude") => void;
@@ -0,0 +1,115 @@
1
+ import * as plugins from './plugins.js';
2
+ import { writeSecretFileAtomically } from './helpers.js';
3
+ export const credentialRecord = (value) => {
4
+ if (!value || typeof value !== 'object' || Array.isArray(value))
5
+ throw new Error('Unsupported credential document.');
6
+ return value;
7
+ };
8
+ export const credentialText = (value) => typeof value === 'string' && value.length > 0 ? value : undefined;
9
+ export const credentialHash = (value) => plugins.crypto.createHash('sha256').update(value).digest('hex');
10
+ /** A bounded file read; malformed secrets never become parser diagnostics in the CLI. */
11
+ export const readCredentialDocument = (file) => {
12
+ let fd;
13
+ try {
14
+ fd = plugins.fs.openSync(file, plugins.fs.constants.O_RDONLY | plugins.fs.constants.O_NONBLOCK);
15
+ const stat = plugins.fs.fstatSync(fd);
16
+ if (!stat.isFile() || stat.size > 4 * 1024 * 1024)
17
+ throw new Error();
18
+ const buffer = Buffer.alloc(4 * 1024 * 1024 + 1);
19
+ let size = 0;
20
+ while (size < buffer.length) {
21
+ const count = plugins.fs.readSync(fd, buffer, size, buffer.length - size, null);
22
+ if (!count)
23
+ break;
24
+ size += count;
25
+ }
26
+ if (size === buffer.length)
27
+ throw new Error();
28
+ const raw = buffer.subarray(0, size).toString('utf8');
29
+ return { raw, data: credentialRecord(JSON.parse(raw)) };
30
+ }
31
+ catch (error) {
32
+ if (error.code === 'ENOENT')
33
+ return { raw: null, data: {} };
34
+ throw new Error('Credential file is unreadable, malformed, or too large; no changes were made.');
35
+ }
36
+ finally {
37
+ if (fd !== undefined)
38
+ plugins.fs.closeSync(fd);
39
+ }
40
+ };
41
+ /** A single atomic, owner-only record keeps the saved credential and its identity together. */
42
+ export class CredentialStore {
43
+ dir;
44
+ constructor(harness, root = process.env.AUTHSWITCH_HOME || plugins.path.join(plugins.os.homedir(), '.authswitch')) {
45
+ this.dir = plugins.path.join(root, harness);
46
+ }
47
+ id(slot, identity) { return credentialHash(JSON.stringify([slot, identity])); }
48
+ file(id) {
49
+ if (!/^[a-f0-9]{64}$/.test(id))
50
+ throw new Error('Invalid saved account ID.');
51
+ return plugins.path.join(this.dir, `${id}.json`);
52
+ }
53
+ read(id) {
54
+ const value = readCredentialDocument(this.file(id)).data;
55
+ if (value.schemaVersion !== 1 || value.id !== id || !credentialText(value.slotId) || !credentialText(value.identity)
56
+ || !credentialText(value.label) || typeof value.savedAt !== 'string' || !Number.isFinite(Date.parse(value.savedAt))
57
+ || this.id(value.slotId, value.identity) !== id)
58
+ throw new Error('Saved account metadata is invalid; restore it from a verified backup.');
59
+ credentialRecord(value.credential);
60
+ return value;
61
+ }
62
+ list() {
63
+ if (!plugins.fs.existsSync(this.dir))
64
+ return [];
65
+ return plugins.fs.readdirSync(this.dir).filter(name => /^[a-f0-9]{64}\.json$/.test(name))
66
+ .map(name => this.read(name.slice(0, -5))).sort((a, b) => b.savedAt.localeCompare(a.savedAt));
67
+ }
68
+ save(entry) {
69
+ const record = { ...entry, schemaVersion: 1, id: this.id(entry.slotId, entry.identity), savedAt: new Date().toISOString() };
70
+ plugins.fs.mkdirSync(this.dir, { recursive: true, mode: 0o700 });
71
+ plugins.fs.chmodSync(this.dir, 0o700);
72
+ const raw = JSON.stringify(record, null, 2) + '\n';
73
+ writeSecretFileAtomically(this.file(record.id), raw);
74
+ if (readCredentialDocument(this.file(record.id)).raw !== raw)
75
+ throw new Error('Saved credential verification failed; the active login was preserved.');
76
+ return this.read(record.id);
77
+ }
78
+ remove(id) { this.read(id); plugins.fs.unlinkSync(this.file(id)); }
79
+ locked(action) {
80
+ plugins.fs.mkdirSync(this.dir, { recursive: true, mode: 0o700 });
81
+ const file = plugins.path.join(this.dir, '.lock');
82
+ let fd;
83
+ try {
84
+ fd = plugins.fs.openSync(file, 'wx', 0o600);
85
+ }
86
+ catch {
87
+ throw new Error(`Account storage is locked. Close other authswitch operations; if none remain, remove ${file}.`);
88
+ }
89
+ try {
90
+ return action();
91
+ }
92
+ finally {
93
+ plugins.fs.closeSync(fd);
94
+ plugins.fs.unlinkSync(file);
95
+ }
96
+ }
97
+ }
98
+ /** Native harnesses retain credentials and may refresh them. Refuse writes while one is running. */
99
+ export const requireHarnessStopped = (binary) => {
100
+ let names;
101
+ try {
102
+ if (process.platform === 'win32') {
103
+ names = plugins.childProcess.execFileSync('tasklist', ['/FO', 'CSV', '/NH'], { encoding: 'utf8', timeout: 5000 }).split('\n').map(line => line.split('",')[0].replace(/^"/, ''));
104
+ }
105
+ else {
106
+ names = plugins.childProcess.execFileSync('ps', ['-u', String(process.getuid()), '-o', 'comm='], { encoding: 'utf8', timeout: 5000 }).split('\n').map(line => plugins.path.basename(line.trim()));
107
+ }
108
+ }
109
+ catch {
110
+ throw new Error(`Could not verify that ${binary} is stopped. No login was changed.`);
111
+ }
112
+ if (names.some(name => name === binary || name === `${binary}.exe`))
113
+ throw new Error(`Exit running ${binary} processes before saving or switching credentials, then start ${binary} again.`);
114
+ };
115
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5jcmVkZW50aWFsc3RvcmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90cy9jbGFzc2VzLmNyZWRlbnRpYWxzdG9yZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUseUJBQXlCLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFFekQsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsQ0FBQyxLQUFjLEVBQTJCLEVBQUU7SUFDMUUsSUFBSSxDQUFDLEtBQUssSUFBSSxPQUFPLEtBQUssS0FBSyxRQUFRLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxLQUFLLENBQUM7UUFBRSxNQUFNLElBQUksS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUM7SUFDckgsT0FBTyxLQUFnQyxDQUFDO0FBQzFDLENBQUMsQ0FBQztBQUNGLE1BQU0sQ0FBQyxNQUFNLGNBQWMsR0FBRyxDQUFDLEtBQWMsRUFBc0IsRUFBRSxDQUFDLE9BQU8sS0FBSyxLQUFLLFFBQVEsSUFBSSxLQUFLLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxTQUFTLENBQUM7QUFDeEksTUFBTSxDQUFDLE1BQU0sY0FBYyxHQUFHLENBQUMsS0FBYSxFQUFVLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO0FBRXpILHlGQUF5RjtBQUN6RixNQUFNLENBQUMsTUFBTSxzQkFBc0IsR0FBRyxDQUFDLElBQVksRUFBeUQsRUFBRTtJQUM1RyxJQUFJLEVBQXNCLENBQUM7SUFDM0IsSUFBSSxDQUFDO1FBQ0gsRUFBRSxHQUFHLE9BQU8sQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDLElBQUksRUFBRSxPQUFPLENBQUMs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
@@ -0,0 +1,47 @@
1
+ import type { IAuthHarness, IHarnessAccountStatus, IHarnessOutcome, IHarnessState } from './interfaces.harness.js';
2
+ import { CredentialStore } from './classes.credentialstore.js';
3
+ export interface IFileAccount {
4
+ slotId: string;
5
+ identity: string;
6
+ label: string;
7
+ credential: Record<string, unknown>;
8
+ }
9
+ export interface IFileHarnessSnapshot {
10
+ accounts: IFileAccount[];
11
+ unavailable: string | null;
12
+ }
13
+ /** Shared verified preservation for harnesses with independently replaceable credential slots. */
14
+ export declare abstract class FileHarness implements IAuthHarness {
15
+ abstract readonly id: string;
16
+ abstract readonly label: string;
17
+ abstract readonly loginHint: string;
18
+ readonly diagnosticsLabel = "Check credential storage and account availability";
19
+ protected abstract readonly store: CredentialStore;
20
+ protected abstract snapshot(): IFileHarnessSnapshot;
21
+ protected abstract apply(slotId: string, previous: IFileAccount | undefined, target: IFileAccount | undefined): void;
22
+ protected abstract beforeMutation(): void;
23
+ protected abstract inspect(credential: Record<string, unknown>, slotId: string): IFileAccount;
24
+ abstract readAccountStatus(id: string): Promise<IHarnessAccountStatus>;
25
+ private saved;
26
+ readState(): IHarnessState;
27
+ protected readCredential(id: string): IFileAccount;
28
+ /** Save a newly authenticated credential without changing a native harness's login. */
29
+ importCredential(slotId: string, credential: Record<string, unknown>): {
30
+ accountId: string;
31
+ };
32
+ /** Backend-only login handoff. Preserve the outgoing credential before replacing its slot. */
33
+ activateCredential(slotId: string, credential: Record<string, unknown>): IHarnessOutcome;
34
+ resolveAccount(reference: string): {
35
+ id: string;
36
+ } | {
37
+ candidates: string[];
38
+ };
39
+ private outcome;
40
+ saveCurrent(options: {
41
+ keepActive: boolean;
42
+ accountId?: string;
43
+ }): IHarnessOutcome;
44
+ switchAccount(id: string): IHarnessOutcome;
45
+ removeAccount(id: string): IHarnessOutcome;
46
+ diagnose(): IHarnessOutcome;
47
+ }
@@ -0,0 +1,119 @@
1
+ import { CredentialStore } from './classes.credentialstore.js';
2
+ import { plainText } from './formatting.js';
3
+ /** Shared verified preservation for harnesses with independently replaceable credential slots. */
4
+ export class FileHarness {
5
+ diagnosticsLabel = 'Check credential storage and account availability';
6
+ saved(entry) {
7
+ const account = this.inspect(entry.credential, entry.slotId);
8
+ if (account.identity !== entry.identity)
9
+ throw new Error('Saved credential does not match its account identity.');
10
+ return account;
11
+ }
12
+ readState() {
13
+ const snapshot = this.snapshot();
14
+ const saved = this.store.list();
15
+ const accounts = saved.map(entry => {
16
+ this.saved(entry);
17
+ return { id: entry.id, slotId: entry.slotId, label: entry.label, isActive: false, isStashed: true, savedAt: entry.savedAt, details: [`Provider: ${entry.slotId}`] };
18
+ });
19
+ for (const active of snapshot.accounts) {
20
+ const id = this.store.id(active.slotId, active.identity);
21
+ const existing = accounts.find(account => account.id === id);
22
+ if (existing) {
23
+ existing.isActive = true;
24
+ existing.label = active.label;
25
+ }
26
+ else
27
+ accounts.unshift({ id, slotId: active.slotId, label: active.label, isActive: true, isStashed: false, savedAt: null, details: [`Provider: ${active.slotId}`] });
28
+ }
29
+ for (const account of accounts) {
30
+ if (accounts.some(other => other.id !== account.id && other.label === account.label))
31
+ account.details.push(`Account ID: ${account.id}`);
32
+ }
33
+ return { accounts, saveUnavailableReason: snapshot.unavailable };
34
+ }
35
+ readCredential(id) {
36
+ const active = this.snapshot().accounts.find(account => this.store.id(account.slotId, account.identity) === id);
37
+ return active ?? this.saved(this.store.read(id));
38
+ }
39
+ /** Save a newly authenticated credential without changing a native harness's login. */
40
+ importCredential(slotId, credential) {
41
+ return this.store.locked(() => ({ accountId: this.store.save(this.inspect(credential, slotId)).id }));
42
+ }
43
+ /** Backend-only login handoff. Preserve the outgoing credential before replacing its slot. */
44
+ activateCredential(slotId, credential) {
45
+ return this.outcome(() => {
46
+ this.beforeMutation();
47
+ const target = this.inspect(credential, slotId);
48
+ const snapshot = this.snapshot();
49
+ if (snapshot.unavailable)
50
+ throw new Error(snapshot.unavailable);
51
+ const previous = snapshot.accounts.find(account => account.slotId === slotId);
52
+ if (previous)
53
+ this.store.save(previous);
54
+ this.apply(slotId, previous, target);
55
+ return `Activated ${plainText(target.label)} (${plainText(slotId)}).`;
56
+ });
57
+ }
58
+ resolveAccount(reference) {
59
+ const accounts = this.store.list();
60
+ const exact = accounts.filter(account => account.id === reference || account.label.toLowerCase() === reference.toLowerCase()
61
+ || `${account.slotId}:${account.label}`.toLowerCase() === reference.toLowerCase());
62
+ const matches = exact.length ? exact : accounts.filter(account => account.label.toLowerCase().startsWith(reference.toLowerCase()));
63
+ return matches.length === 1 ? { id: matches[0].id } : { candidates: matches.map(account => `${account.slotId}:${account.label} (${account.id})`) };
64
+ }
65
+ outcome(action) {
66
+ try {
67
+ return this.store.locked(() => ({ lines: [action()], problems: [] }));
68
+ }
69
+ catch (error) {
70
+ return { lines: [], problems: [error instanceof Error ? error.message : 'Credential operation failed.'] };
71
+ }
72
+ }
73
+ saveCurrent(options) {
74
+ return this.outcome(() => {
75
+ this.beforeMutation();
76
+ const snapshot = this.snapshot();
77
+ if (snapshot.unavailable)
78
+ throw new Error(snapshot.unavailable);
79
+ const matches = snapshot.accounts.filter(account => !options.accountId || this.store.id(account.slotId, account.identity) === options.accountId || account.slotId === options.accountId || account.label === options.accountId);
80
+ if (matches.length !== 1)
81
+ throw new Error(matches.length ? 'Several logins are active. Select the account or provider to save.' : 'No matching active login to save.');
82
+ const active = matches[0];
83
+ this.store.save(active);
84
+ if (!options.keepActive)
85
+ this.apply(active.slotId, active, undefined);
86
+ return `Saved ${plainText(active.label)} (${plainText(active.slotId)})${options.keepActive ? '; login remains in place.' : `. Start ${this.label} to log in again.`}`;
87
+ });
88
+ }
89
+ switchAccount(id) {
90
+ return this.outcome(() => {
91
+ this.beforeMutation();
92
+ const target = this.saved(this.store.read(id));
93
+ const snapshot = this.snapshot();
94
+ if (snapshot.unavailable)
95
+ throw new Error(snapshot.unavailable);
96
+ const previous = snapshot.accounts.find(account => account.slotId === target.slotId);
97
+ // Refresh the outgoing stash even when this account was already saved.
98
+ if (previous)
99
+ this.store.save(previous);
100
+ if (previous?.identity === target.identity)
101
+ return `${plainText(target.label)} is already active; its latest credential is saved.`;
102
+ this.apply(target.slotId, previous, target);
103
+ return `Activated ${plainText(target.label)} (${plainText(target.slotId)}). Start ${this.label} to use it.`;
104
+ });
105
+ }
106
+ removeAccount(id) {
107
+ return this.outcome(() => { const account = this.store.read(id); this.store.remove(id); return `Removed saved login for ${plainText(account.label)}; the active login is preserved.`; });
108
+ }
109
+ diagnose() {
110
+ try {
111
+ const state = this.readState();
112
+ return { lines: [`${this.label}: ${state.accounts.filter(account => account.isActive).length} active login(s), ${state.accounts.filter(account => account.isStashed).length} saved account(s).`, this.loginHint], problems: state.saveUnavailableReason ? [state.saveUnavailableReason] : [] };
113
+ }
114
+ catch {
115
+ return { lines: [], problems: ['Credential storage could not be verified. Check file permissions and saved credential records.'] };
116
+ }
117
+ }
118
+ }
119
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5maWxlaGFybmVzcy5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMuZmlsZWhhcm5lc3MudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQ0EsT0FBTyxFQUFFLGVBQWUsRUFBMEIsTUFBTSw4QkFBOEIsQ0FBQztBQUN2RixPQUFPLEVBQUUsU0FBUyxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFhNUMsa0dBQWtHO0FBQ2xHLE1BQU0sT0FBZ0IsV0FBVztJQUlmLGdCQUFnQixHQUFHLG1EQUFtRCxDQUFDO0lBUS9FLEtBQUssQ0FBQyxLQUF3QjtRQUNwQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxVQUFVLEVBQUUsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzdELElBQUksT0FBTyxDQUFDLFFBQVEsS0FBSyxLQUFLLENBQUMsUUFBUTtZQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsdURBQXVELENBQUMsQ0FBQztRQUNsSCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBQ00sU0FBUztRQUNkLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUNqQyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksRUFBRSxDQUFDO1FBQ2hDLE1BQU0sUUFBUSxHQUE4QixLQUFLLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQzVELElBQUksQ0FBQyxLQUFLLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDbEIsT0FBTyxFQUFFLEVBQUUsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLE1BQU0sRUFBRSxLQUFLLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxLQUFLLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxPQUFPLEVBQUUsQ0FBQyxhQUFhLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQyxFQUFFLENBQUM7UUFDdEssQ0FBQyxDQUFDLENBQUM7UUFDSCxLQUFLLE1BQU0sTUFBTSxJQUFJLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUN2QyxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUN6RCxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsQ0FBQztZQUM3RCxJQUFJLFFBQVEsRUFBRSxDQUFDO2dCQUFDLFFBQVEsQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDO2dCQUFDLFFBQVEsQ0FBQyxLQUFLLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQztZQUFDLENBQUM7O2dCQUNyRSxRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsRUFBRSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsTUFBTSxFQUFFLEtBQUssRUFBRSxNQUFNLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxJQUFJLEVBQUUsU0FBUyxFQUFFLEtBQUssRUFBRSxPQUFPLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxDQUFDLGFBQWEsTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDLEVBQUUsQ0FBQyxDQUFDO1FBQ3RLLENBQUM7UUFDRCxLQUFLLE1BQU0sT0FBTyxJQUFJLFFBQVEsRUFBRSxDQUFDO1lBQy9CLElBQUksUUFBUSxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQyxFQUFFLEtBQUssT0FBTyxDQUFDLEVBQUUsSUFBSSxLQUFLLENBQUMsS0FBSyxLQUFLLE9BQU8sQ0FBQyxLQUFLLENBQUM7Z0JBQUUsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsZUFBZSxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUMxSSxDQUFDO1FBQ0QsT0FBTyxFQUFFLFFBQVEsRUFBRSxxQkFBcUIsRUFBRSxRQUFRLENBQUMsV0FBVyxFQUFFLENBQUM7SUFDbkUsQ0FBQztJQUNTLGNBQWMsQ0FBQyxFQUFVO1FBQ2pDLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLE1BQU0sRUFBRSxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssRUFBRSxDQUFDLENBQUM7UUFDaEgsT0FBTyxNQUFNLElBQUksSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDO0lBQ25ELENBQUM7SUFDRCx1RkFBdUY7SUFDaEYsZ0JBQWdCLENBQUMsTUFBYyxFQUFFLFVBQW1DO1FBQ3pFLE9BQU8sSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsQ0FBQyxFQUFFLFNBQVMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQztJQUN4RyxDQUFDO0lBQ0QsOEZBQThGO0lBQ3ZGLGtCQUFrQixDQUFDLE1BQWMsRUFBRSxVQUFtQztRQUMzRSxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN0QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFVBQVUsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNoRCxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDakMsSUFBSSxRQUFRLENBQUMsV0FBVztnQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUNoRSxNQUFNLFFBQVEsR0FBRyxRQUFRLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEtBQUssTUFBTSxDQUFDLENBQUM7WUFDOUUsSUFBSSxRQUFRO2dCQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3hDLElBQUksQ0FBQyxLQUFLLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUNyQyxPQUFPLGFBQWEsU0FBUyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxTQUFTLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQztRQUN4RSxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFDTSxjQUFjLENBQUMsU0FBaUI7UUFDckMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUNuQyxNQUFNLEtBQUssR0FBRyxRQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEVBQUUsS0FBSyxTQUFTLElBQUksT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsS0FBSyxTQUFTLENBQUMsV0FBVyxFQUFFO2VBQ3ZILEdBQUcsT0FBTyxDQUFDLE1BQU0sSUFBSSxPQUFPLENBQUMsS0FBSyxFQUFFLENBQUMsV0FBVyxFQUFFLEtBQUssU0FBUyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7UUFDckYsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxXQUFXLEVBQUUsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQztRQUNuSSxPQUFPLE9BQU8sQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxHQUFHLE9BQU8sQ0FBQyxNQUFNLElBQUksT0FBTyxDQUFDLEtBQUssS0FBSyxPQUFPLENBQUMsRUFBRSxHQUFHLENBQUMsRUFBRSxDQUFDO0lBQ3JKLENBQUM7SUFDTyxPQUFPLENBQUMsTUFBb0I7UUFDbEMsSUFBSSxDQUFDO1lBQUMsT0FBTyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLEVBQUUsS0FBSyxFQUFFLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxRQUFRLEVBQUUsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDO1FBQUMsQ0FBQztRQUM5RSxPQUFPLEtBQUssRUFBRSxDQUFDO1lBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsS0FBSyxZQUFZLEtBQUssQ0FBQyxDQUFDLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUMsOEJBQThCLENBQUMsRUFBRSxDQUFDO1FBQUMsQ0FBQztJQUM5SCxDQUFDO0lBQ00sV0FBVyxDQUFDLE9BQW9EO1FBQ3JFLE9BQU8sSUFBSSxDQUFDLE9BQU8sQ0FBQyxHQUFHLEVBQUU7WUFDdkIsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3RCLE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNqQyxJQUFJLFFBQVEsQ0FBQyxXQUFXO2dCQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ2hFLE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxRQUFRLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxPQUFPLENBQUMsU0FBUyxJQUFJLElBQUksQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLFFBQVEsQ0FBQyxLQUFLLE9BQU8sQ0FBQyxTQUFTLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxPQUFPLENBQUMsU0FBUyxJQUFJLE9BQU8sQ0FBQyxLQUFLLEtBQUssT0FBTyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQ2hPLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxDQUFDO2dCQUFFLE1BQU0sSUFBSSxLQUFLLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUMsb0VBQW9FLENBQUMsQ0FBQyxDQUFDLG1DQUFtQyxDQUFDLENBQUM7WUFDdkssTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzFCLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1lBQ3hCLElBQUksQ0FBQyxPQUFPLENBQUMsVUFBVTtnQkFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxNQUFNLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1lBQ3RFLE9BQU8sU0FBUyxTQUFTLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxLQUFLLFNBQVMsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLElBQUksT0FBTyxDQUFDLFVBQVUsQ0FBQyxDQUFDLENBQUMsMkJBQTJCLENBQUMsQ0FBQyxDQUFDLFdBQVcsSUFBSSxDQUFDLEtBQUssbUJBQW1CLEVBQUUsQ0FBQztRQUN4SyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFDTSxhQUFhLENBQUMsRUFBVTtRQUM3QixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFO1lBQ3ZCLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN0QixNQUFNLE1BQU0sR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDL0MsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ2pDLElBQUksUUFBUSxDQUFDLFdBQVc7Z0JBQUUsTUFBTSxJQUFJLEtBQUssQ0FBQyxRQUFRLENBQUMsV0FBVyxDQUFDLENBQUM7WUFDaEUsTUFBTSxRQUFRLEdBQUcsUUFBUSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxPQUFPLENBQUMsTUFBTSxLQUFLLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUNyRix1RUFBdUU7WUFDdkUsSUFBSSxRQUFRO2dCQUFFLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1lBQ3hDLElBQUksUUFBUSxFQUFFLFFBQVEsS0FBSyxNQUFNLENBQUMsUUFBUTtnQkFBRSxPQUFPLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMscURBQXFELENBQUM7WUFDbkksSUFBSSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztZQUM1QyxPQUFPLGFBQWEsU0FBUyxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsS0FBSyxTQUFTLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQyxZQUFZLElBQUksQ0FBQyxLQUFLLGFBQWEsQ0FBQztRQUM5RyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFDTSxhQUFhLENBQUMsRUFBVTtRQUM3QixPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLEdBQUcsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sMkJBQTJCLFNBQVMsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLGtDQUFrQyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDM0wsQ0FBQztJQUNNLFFBQVE7UUFDYixJQUFJLENBQUM7WUFDSCxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDL0IsT0FBTyxFQUFFLEtBQUssRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssS0FBSyxLQUFLLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsQ0FBQyxNQUFNLHFCQUFxQixLQUFLLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxTQUFTLENBQUMsQ0FBQyxNQUFNLG9CQUFvQixFQUFFLElBQUksQ0FBQyxTQUFTLENBQUMsRUFBRSxRQUFRLEVBQUUsS0FBSyxDQUFDLHFCQUFxQixDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQyxxQkFBcUIsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQztRQUNqUyxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsUUFBUSxFQUFFLENBQUMsZ0dBQWdHLENBQUMsRUFBRSxDQUFDO1FBQUMsQ0FBQztJQUNqSixDQUFDO0NBQ0YifQ==
@@ -0,0 +1,42 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { IHarnessLoginHandle, IHarnessLoginOptions, IHarnessLoginResult } from './interfaces.harness.js';
3
+ export type TAuthLoginFlow = plugins.flexAccounts.TSmartAiProviderLoginFlow;
4
+ export type TAuthLoginCredential = plugins.flexAccounts.TSmartAiProviderCredential;
5
+ export type TAuthLoginPrompt = plugins.flexAccounts.TSmartAiProviderLoginPrompt;
6
+ export interface IAuthLoginResult extends plugins.flexAccounts.ISmartAiProviderLoginResult {
7
+ }
8
+ export interface IAuthLoginHandle extends plugins.flexAccounts.ISmartAiProviderLoginHandle {
9
+ }
10
+ export interface IAuthLoginProvider extends Pick<plugins.flexAccounts.ISmartAiProviderAdapter, 'descriptor' | 'beginLogin' | 'dispose'> {
11
+ }
12
+ export interface IAuthLoginOptions extends plugins.flexAccounts.ISmartAiProviderLoginOptions {
13
+ providerId: string;
14
+ }
15
+ export interface IAuthSwitchLoginOptions {
16
+ /** False when an enclosing provider registry owns disposal of injected adapters. */
17
+ disposeProviders?: boolean;
18
+ }
19
+ /** Shared login owner for terminal and hosted UIs. Credential results stay on the backend. */
20
+ export declare class AuthSwitchLogin {
21
+ private readonly options;
22
+ private readonly providers;
23
+ private pending;
24
+ private closed;
25
+ private closing?;
26
+ private readonly handles;
27
+ constructor(providers?: IAuthLoginProvider[], options?: IAuthSwitchLoginOptions);
28
+ listProviders(): plugins.flexAccounts.ISmartAiProviderDescriptor[];
29
+ beginLogin(options: IAuthLoginOptions): Promise<IAuthLoginHandle>;
30
+ close(): Promise<void>;
31
+ private closeOwnedResources;
32
+ }
33
+ /** A hosted or terminal UI sees only the prompt and saved-account outcome. */
34
+ export declare const beginSavedOpenAiLogin: (save: (result: IAuthLoginResult) => IHarnessLoginResult, options: IHarnessLoginOptions, fetcher?: typeof fetch) => Promise<IHarnessLoginHandle>;
35
+ /** Convert a verified OpenAI login for native OpenCode without exposing it in public account DTOs. */
36
+ export declare const openCodeCredentialFromLogin: (credential: plugins.flexAccounts.IOpenAiChatGptOAuthCredential) => {
37
+ type: "oauth";
38
+ access: string;
39
+ refresh: string;
40
+ expires: number;
41
+ accountId?: string;
42
+ };
@@ -0,0 +1,102 @@
1
+ import * as plugins from './plugins.js';
2
+ /** Shared login owner for terminal and hosted UIs. Credential results stay on the backend. */
3
+ export class AuthSwitchLogin {
4
+ options;
5
+ providers = new Map();
6
+ pending = 0;
7
+ closed = false;
8
+ closing;
9
+ handles = new Set();
10
+ constructor(providers = [new plugins.flexAccounts.OpenAiProviderAdapter()], options = {}) {
11
+ this.options = options;
12
+ for (const provider of providers) {
13
+ if (this.providers.has(provider.descriptor.providerId))
14
+ throw new Error('Duplicate login provider.');
15
+ this.providers.set(provider.descriptor.providerId, provider);
16
+ }
17
+ }
18
+ listProviders() {
19
+ return [...this.providers.values()].map(provider => ({ ...provider.descriptor, loginFlows: [...provider.descriptor.loginFlows] }));
20
+ }
21
+ async beginLogin(options) {
22
+ if (this.closed)
23
+ throw new Error('Login service is closed.');
24
+ const provider = this.providers.get(options.providerId);
25
+ if (!provider?.descriptor.loginFlows.includes(options.flow))
26
+ throw new Error('This provider does not support the requested login flow.');
27
+ if (this.pending + this.handles.size >= 8)
28
+ throw new Error('Too many pending logins. Complete or cancel an existing login first.');
29
+ this.pending++;
30
+ try {
31
+ const handle = await provider.beginLogin(options);
32
+ if (this.closed) {
33
+ await handle.close();
34
+ throw new Error('Login service is closed.');
35
+ }
36
+ this.handles.add(handle);
37
+ // Keep cancellation/close ownership until the consumer has persisted the secret result.
38
+ return {
39
+ prompt: handle.prompt,
40
+ completion: handle.completion,
41
+ cancel: () => handle.cancel(),
42
+ close: async () => { await handle.close(); this.handles.delete(handle); },
43
+ };
44
+ }
45
+ catch {
46
+ throw new Error('Provider login could not be started.');
47
+ }
48
+ finally {
49
+ this.pending--;
50
+ }
51
+ }
52
+ close() { return this.closing ??= this.closeOwnedResources(); }
53
+ async closeOwnedResources() {
54
+ this.closed = true;
55
+ const results = await Promise.allSettled([...this.handles].map(handle => handle.close()));
56
+ const disposed = this.options.disposeProviders === false ? [] : await Promise.allSettled([...this.providers.values()].map(provider => provider.dispose()));
57
+ if ([...results, ...disposed].some(result => result.status === 'rejected'))
58
+ throw new Error('Provider login cleanup failed.');
59
+ this.handles.clear();
60
+ }
61
+ }
62
+ /** A hosted or terminal UI sees only the prompt and saved-account outcome. */
63
+ export const beginSavedOpenAiLogin = async (save, options, fetcher) => {
64
+ if (options.providerId !== 'openai' || options.flow !== 'device')
65
+ throw new Error('This harness supports OpenAI device login.');
66
+ const service = new AuthSwitchLogin([new plugins.flexAccounts.OpenAiProviderAdapter({ fetch: fetcher })]);
67
+ try {
68
+ const handle = await service.beginLogin({ providerId: 'openai', flow: 'device' });
69
+ const completion = handle.completion.then(save).catch(() => ({
70
+ outcome: { lines: [], problems: ['Login did not complete or its saved credential could not be verified. The active login was preserved.'] },
71
+ })).finally(() => service.close());
72
+ return { prompt: handle.prompt, completion, cancel: async () => { await handle.cancel(); }, close: () => service.close() };
73
+ }
74
+ catch {
75
+ await service.close();
76
+ throw new Error('Provider login could not be started.');
77
+ }
78
+ };
79
+ /** Convert a verified OpenAI login for native OpenCode without exposing it in public account DTOs. */
80
+ export const openCodeCredentialFromLogin = (credential) => {
81
+ try {
82
+ const auth = plugins.flexAccounts.toOpenAiChatGptAuthCredentials(credential);
83
+ const payload = credential.accessToken.split('.')[1];
84
+ let expires = 0;
85
+ if (payload && payload.length <= 48 * 1024) {
86
+ try {
87
+ const claims = JSON.parse(Buffer.from(payload, 'base64url').toString('utf8'));
88
+ expires = typeof claims?.exp === 'number' ? claims.exp * 1000 : 0;
89
+ }
90
+ catch { /* Opaque access tokens are valid; native OpenCode refreshes an unknown expiry. */ }
91
+ }
92
+ return {
93
+ type: 'oauth', access: credential.accessToken, refresh: credential.refreshToken,
94
+ expires: Number.isSafeInteger(expires) && expires >= 0 ? expires : 0,
95
+ ...(auth.accountId ? { accountId: auth.accountId } : {}),
96
+ };
97
+ }
98
+ catch {
99
+ throw new Error('OpenAI login credential is invalid.');
100
+ }
101
+ };
102
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5sb2dpbi5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzL2NsYXNzZXMubG9naW4udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFpQnhDLDhGQUE4RjtBQUM5RixNQUFNLE9BQU8sZUFBZTtJQU95RjtJQU5sRyxTQUFTLEdBQUcsSUFBSSxHQUFHLEVBQThCLENBQUM7SUFDM0QsT0FBTyxHQUFHLENBQUMsQ0FBQztJQUNaLE1BQU0sR0FBRyxLQUFLLENBQUM7SUFDZixPQUFPLENBQWlCO0lBQ2YsT0FBTyxHQUFHLElBQUksR0FBRyxFQUFvQixDQUFDO0lBRXZELFlBQVksWUFBa0MsQ0FBQyxJQUFJLE9BQU8sQ0FBQyxZQUFZLENBQUMscUJBQXFCLEVBQUUsQ0FBQyxFQUFtQixVQUFtQyxFQUFFO1FBQXJDLFlBQU8sR0FBUCxPQUFPLENBQThCO1FBQ3RKLEtBQUssTUFBTSxRQUFRLElBQUksU0FBUyxFQUFFLENBQUM7WUFDakMsSUFBSSxJQUFJLENBQUMsU0FBUyxDQUFDLEdBQUcsQ0FBQyxRQUFRLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQztnQkFBRSxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7WUFDckcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLFVBQVUsQ0FBQyxVQUFVLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDL0QsQ0FBQztJQUNILENBQUM7SUFDTSxhQUFhO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsTUFBTSxFQUFFLENBQUMsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQyxDQUFDLEVBQUUsR0FBRyxRQUFRLENBQUMsVUFBVSxFQUFFLFVBQVUsRUFBRSxDQUFDLEdBQUcsUUFBUSxDQUFDLFVBQVUsQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FB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
@@ -0,0 +1,34 @@
1
+ import { FileHarness, type IFileAccount, type IFileHarnessSnapshot } from './classes.fileharness.js';
2
+ import { CredentialStore } from './classes.credentialstore.js';
3
+ import type { IHarnessAccountStatus, IHarnessLoginOptions, IHarnessLoginProvider } from './interfaces.harness.js';
4
+ export interface IOpenCodeHarnessOptions {
5
+ dataHome?: string;
6
+ stashRoot?: string;
7
+ env?: NodeJS.ProcessEnv;
8
+ fetch?: typeof fetch;
9
+ /** Process inspection dependency, injectable for isolated installations and tests. */
10
+ checkStopped?: () => void;
11
+ }
12
+ /** OpenCode owns one login per provider. Replacing a slot never replaces the whole provider set. */
13
+ export declare class OpenCodeHarness extends FileHarness {
14
+ readonly id = "opencode";
15
+ readonly label = "OpenCode";
16
+ readonly loginHint = "Use authswitch opencode login for OpenAI; use opencode auth login for other providers.";
17
+ readonly loginProviders: IHarnessLoginProvider[];
18
+ protected readonly store: CredentialStore;
19
+ private readonly file;
20
+ private readonly env;
21
+ private readonly status;
22
+ private readonly checkStopped;
23
+ private readonly fetcher?;
24
+ constructor(options?: IOpenCodeHarnessOptions);
25
+ protected beforeMutation(): void;
26
+ /** Public identity only, for reconciling a host's OpenAI association after native refresh/restart. */
27
+ activeOpenAiAccountId(): string | undefined;
28
+ beginLogin(options?: IHarnessLoginOptions): Promise<import("./interfaces.harness.js").IHarnessLoginHandle>;
29
+ private openAiInfo;
30
+ protected inspect(credential: Record<string, unknown>, slotId: string): IFileAccount;
31
+ protected snapshot(): IFileHarnessSnapshot;
32
+ protected apply(slotId: string, previous: IFileAccount | undefined, target: IFileAccount | undefined): void;
33
+ readAccountStatus(id: string): Promise<IHarnessAccountStatus>;
34
+ }