@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,142 @@
1
+ import * as plugins from './plugins.js';
2
+ import { CodexHarness } from './classes.codexharness.js';
3
+ import { OpenCodeHarness } from './classes.opencodeharness.js';
4
+ import { ClaudeCodeHarness } from './classes.claudecodeharness.js';
5
+ import { readAccountList } from './classes.accountlist.js';
6
+ import { assertAuthSwitchMutation, authSwitchEnvironmentId, runAuthSwitchMutation } from './classes.operations.js';
7
+ const publicOutcome = (outcome) => ({ lines: [...outcome.lines], problems: [...outcome.problems] });
8
+ const publicResult = (result) => result.status === 'complete'
9
+ ? { status: 'complete', outcome: publicOutcome(result.outcome) }
10
+ : result.status === 'busy' ? { status: 'busy', message: result.message } : { status: 'unavailable' };
11
+ const publicPrompt = (prompt) => prompt.flow === 'device'
12
+ ? { flow: 'device', verificationUrl: prompt.verificationUrl, userCode: prompt.userCode }
13
+ : { flow: 'browser', authUrl: prompt.authUrl };
14
+ export const assertAuthSwitchServiceRequest = value => {
15
+ if (!value || typeof value !== 'object' || Array.isArray(value))
16
+ throw new Error('Invalid authswitch request.');
17
+ const request = value;
18
+ const keys = request.action === 'login' ? ['harnessId', 'providerId', 'flow'] : request.action === 'list' ? ['harnessId']
19
+ : request.action === 'mutate' ? ['coordination'] : ['operationId'];
20
+ if (request.protocolVersion !== 1 || !['list', 'login', 'mutate', 'get', 'cancel'].includes(String(request.action))
21
+ || Object.keys(request).some(key => !['protocolVersion', 'action', ...keys].includes(key)))
22
+ throw new Error('Unsupported authswitch request.');
23
+ if (request.action === 'mutate') {
24
+ const coordination = request.coordination;
25
+ if (!coordination || coordination.protocolVersion !== 1 || typeof coordination.waitForIdle !== 'boolean'
26
+ || typeof coordination.contextId !== 'string' || !/^[a-f0-9]{64}$/.test(coordination.contextId)
27
+ || Object.keys(coordination).some(key => !['protocolVersion', 'contextId', 'mutation', 'waitForIdle'].includes(key)))
28
+ throw new Error('Invalid coordination request.');
29
+ assertAuthSwitchMutation(coordination.mutation);
30
+ }
31
+ else if (request.action === 'get' || request.action === 'cancel') {
32
+ if (typeof request.operationId !== 'string' || !/^[a-f0-9-]{36}$/.test(request.operationId))
33
+ throw new Error('Invalid operation ID.');
34
+ }
35
+ else if ((request.harnessId !== undefined || request.action === 'login')
36
+ && (typeof request.harnessId !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(request.harnessId)))
37
+ throw new Error('Invalid harness ID.');
38
+ if (request.action === 'login' && (typeof request.providerId !== 'string' || !/^[a-z][a-z0-9-]{0,63}$/.test(request.providerId)
39
+ || !['device', 'browser'].includes(String(request.flow))))
40
+ throw new Error('Invalid login provider or flow.');
41
+ };
42
+ /** Hosted account manager. Operations outlive HTTP connections and are retained briefly for polling. */
43
+ export class AuthSwitchService {
44
+ harnesses;
45
+ coordinator;
46
+ operations = new Map();
47
+ closed = false;
48
+ constructor(harnesses = [new CodexHarness(), new OpenCodeHarness(), new ClaudeCodeHarness()], coordinator) {
49
+ this.harnesses = harnesses;
50
+ this.coordinator = coordinator;
51
+ }
52
+ harness(id) {
53
+ const harness = this.harnesses.find(item => item.id === id);
54
+ if (!harness)
55
+ throw new Error('Unknown harness.');
56
+ return harness;
57
+ }
58
+ snapshot(operation) { return structuredClone(operation.status); }
59
+ async request(request) {
60
+ assertAuthSwitchServiceRequest(request);
61
+ if (this.closed)
62
+ throw new Error('Account manager is closed.');
63
+ for (const [id, operation] of this.operations) {
64
+ if (operation.finishedAt !== undefined && Date.now() - operation.finishedAt > 10 * 60_000)
65
+ this.operations.delete(id);
66
+ }
67
+ if (request.action === 'get' || request.action === 'cancel') {
68
+ const operation = this.operations.get(request.operationId);
69
+ if (!operation)
70
+ throw new Error('Operation expired or belongs to another controller. Check account status before retrying.');
71
+ if (request.action === 'cancel') {
72
+ if (operation.status.state === 'pending' && !operation.status.prompt)
73
+ throw new Error('Only a pending login can be cancelled.');
74
+ operation.cancelled = true;
75
+ await operation.login?.cancel();
76
+ }
77
+ return this.snapshot(operation);
78
+ }
79
+ if (this.operations.size >= 64 || [...this.operations.values()].filter(item => item.status.state === 'pending').length >= 8) {
80
+ throw new Error('Account manager operation limit reached. Finish pending operations before starting another.');
81
+ }
82
+ const operation = { status: { id: plugins.crypto.randomUUID(), contextId: authSwitchEnvironmentId(), state: 'pending' }, task: Promise.resolve(), cancelled: false };
83
+ this.operations.set(operation.status.id, operation);
84
+ operation.task = Promise.resolve().then(async () => {
85
+ switch (request.action) {
86
+ case 'list': {
87
+ operation.status.accounts = await readAccountList(request.harnessId ? [this.harness(request.harnessId)] : this.harnesses);
88
+ operation.status.loginCapabilities = this.harnesses.filter(item => item.beginLogin).map(item => ({ harnessId: item.id,
89
+ providers: (item.loginProviders ?? []).map(provider => ({ providerId: provider.providerId, label: provider.label, flows: [...provider.flows] })) }));
90
+ break;
91
+ }
92
+ case 'mutate': {
93
+ if (request.coordination.contextId !== authSwitchEnvironmentId()) {
94
+ operation.status.result = { status: 'complete', outcome: { lines: [], problems: ['AGL and authswitch use different credential locations. Use matching credential environment settings before switching.'] } };
95
+ break;
96
+ }
97
+ const harness = this.harness(request.coordination.mutation.harnessId);
98
+ const coordinated = this.coordinator ? await this.coordinator(request.coordination) : { status: 'unavailable' };
99
+ operation.status.result = publicResult(coordinated.status === 'unavailable'
100
+ ? { status: 'complete', outcome: await runAuthSwitchMutation(harness, request.coordination.mutation) } : coordinated);
101
+ break;
102
+ }
103
+ case 'login': {
104
+ const harness = this.harness(request.harnessId);
105
+ if (!harness.beginLogin)
106
+ throw new Error('This harness does not support hosted login.');
107
+ if (!harness.loginProviders?.some(provider => provider.providerId === request.providerId && provider.flows.includes(request.flow)))
108
+ throw new Error('This harness does not support that login flow.');
109
+ const login = await harness.beginLogin({ providerId: request.providerId, flow: request.flow });
110
+ operation.login = login;
111
+ operation.status.prompt = publicPrompt(login.prompt);
112
+ if (operation.cancelled || this.closed)
113
+ await login.cancel();
114
+ try {
115
+ const result = await login.completion;
116
+ operation.status.result = { status: 'complete', outcome: publicOutcome(result.outcome) };
117
+ operation.status.account = result.account ? { id: result.account.id, label: result.account.label, slotId: result.account.slotId } : undefined;
118
+ }
119
+ finally {
120
+ await login.close();
121
+ operation.login = undefined;
122
+ }
123
+ break;
124
+ }
125
+ }
126
+ operation.status.state = 'complete';
127
+ }).catch(() => {
128
+ operation.status.state = 'failed';
129
+ operation.status.error = 'Account operation failed. Check account and runtime status before retrying.';
130
+ }).finally(() => { operation.finishedAt = Date.now(); });
131
+ return this.snapshot(operation);
132
+ }
133
+ async close() {
134
+ this.closed = true;
135
+ await Promise.allSettled([...this.operations.values()].map(async (operation) => {
136
+ operation.cancelled = true;
137
+ await operation.login?.cancel();
138
+ }));
139
+ await Promise.all([...this.operations.values()].map(operation => operation.task));
140
+ }
141
+ }
142
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBQ3hDLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sOEJBQThCLENBQUM7QUFDL0QsT0FBTyxFQUFFLGlCQUFpQixFQUFFLE1BQU0sZ0NBQWdDLENBQUM7QUFDbkUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDBCQUEwQixDQUFDO0FBQzNELE9BQU8sRUFBRSx3QkFBd0IsRUFBRSx1QkFBdUIsRUFBRSxxQkFBcUIsRUFBd0csTUFBTSx5QkFBeUIsQ0FBQztBQStCek4sTUFBTSxhQUFhLEdBQUcsQ0FBQyxPQUF3QixFQUFtQixFQUFFLENBQUMsQ0FBQyxFQUFFLEtBQUssRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxFQUFFLFFBQVEsRUFBRSxDQUFDLEdBQUcsT0FBTyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUMsQ0FBQztBQUN0SSxNQUFNLFlBQVksR0FBRyxDQUFDLE1BQXFDLEVBQWlDLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxLQUFLLFVBQVU7SUFDekgsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxPQUFPLEVBQUUsYUFBYSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRTtJQUNoRSxDQUFDLENBQUMsTUFBTSxDQUFDLE1BQU0sS0FBSyxNQUFNLENBQUMsQ0FBQyxDQUFDLEVBQUUsTUFBTSxFQUFFLE1BQU0sRUFBRSxPQUFPLEVBQUUsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FBQyxFQUFFLE1BQU0sRUFBRSxhQUFhLEVBQUUsQ0FBQztBQUN2RyxNQUFNLFlBQVksR0FBRyxDQUFDLE1B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
@@ -0,0 +1,63 @@
1
+ import type { ICodexIdentity, IRemoteControlEnrollment, IStashEntry, THarnessName } from './interfaces.js';
2
+ /**
3
+ * Filesystem-backed store for Codex credentials and enrollment metadata.
4
+ * Other harness adapters own their storage format; this is not a universal auth schema.
5
+ *
6
+ * A stash is deliberately a directory of files rather than a database: the thing
7
+ * being stored *is* a credential file, the store must survive with no services
8
+ * running, and it must be greppable and removable by hand when something goes
9
+ * wrong. Everything is written owner-only.
10
+ */
11
+ export declare class StashStore {
12
+ readonly rootDir: string;
13
+ readonly harness: THarnessName;
14
+ constructor(harnessArg: THarnessName, rootDirArg?: string);
15
+ /**
16
+ * Turns an account email into a directory name that is safe on every
17
+ * filesystem while staying readable, so `ls ~/.authswitch/codex` is useful.
18
+ */
19
+ slugFor(emailArg: string): string;
20
+ entryDir(emailArg: string): string;
21
+ has(emailArg: string): boolean;
22
+ /**
23
+ * Writes a credential and its remote-control enrollments under the account email,
24
+ * replacing any existing stash for the same account.
25
+ *
26
+ * Both files go through an atomic temp-and-rename, and the metadata is written
27
+ * last: a crash mid-write therefore leaves either the previous complete stash
28
+ * or a credential whose metadata is still the old one, never a directory that
29
+ * `list()` skips because its metadata never arrived. The caller is expected to
30
+ * verify with `readBack()` before destroying the original.
31
+ */
32
+ write(identityArg: ICodexIdentity, rawAuthArg: string, enrollmentsArg: IRemoteControlEnrollment[], codexHomeArg: string): IStashEntry;
33
+ /**
34
+ * Reads a stash back and confirms it matches what was meant to be written.
35
+ * Callers use this before clearing the active credential, so a stash is only
36
+ * ever trusted once it has been proven readable.
37
+ */
38
+ readBack(emailArg: string, expectedAuthArg: string): boolean;
39
+ readMeta(emailArg: string): IStashEntry | null;
40
+ readAuth(emailArg: string): string | null;
41
+ /** Every stash, newest first. Unreadable directories are skipped, not fatal. */
42
+ list(): IStashEntry[];
43
+ /**
44
+ * Directories under the stash root that hold a credential but no readable
45
+ * metadata -- the shape an interrupted write would leave behind. Reported by
46
+ * `doctor` so they are visible rather than silently skipped by `list()`.
47
+ */
48
+ incomplete(): string[];
49
+ /**
50
+ * Resolves a user-supplied account reference to a stashed email.
51
+ *
52
+ * Accepts the exact email, the directory slug, the local part, or a prefix.
53
+ * Deliberately not a substring match: this reference selects which credential
54
+ * becomes active, so an incidental substring hit would activate an account the
55
+ * user never named.
56
+ */
57
+ resolve(referenceArg: string): {
58
+ email: string;
59
+ } | {
60
+ candidates: string[];
61
+ };
62
+ remove(emailArg: string): boolean;
63
+ }
@@ -0,0 +1,192 @@
1
+ import * as plugins from './plugins.js';
2
+ import { writeSecretFileAtomically } from './helpers.js';
3
+ const AUTH_FILE_NAME = 'auth.json';
4
+ const META_FILE_NAME = 'stash.json';
5
+ /**
6
+ * Filesystem-backed store for Codex credentials and enrollment metadata.
7
+ * Other harness adapters own their storage format; this is not a universal auth schema.
8
+ *
9
+ * A stash is deliberately a directory of files rather than a database: the thing
10
+ * being stored *is* a credential file, the store must survive with no services
11
+ * running, and it must be greppable and removable by hand when something goes
12
+ * wrong. Everything is written owner-only.
13
+ */
14
+ export class StashStore {
15
+ rootDir;
16
+ harness;
17
+ constructor(harnessArg, rootDirArg) {
18
+ if (!/^[a-z][a-z0-9-]*$/.test(harnessArg)) {
19
+ throw new Error('invalid harness namespace');
20
+ }
21
+ this.harness = harnessArg;
22
+ const base = rootDirArg ??
23
+ process.env.AUTHSWITCH_HOME ??
24
+ plugins.path.join(plugins.os.homedir(), '.authswitch');
25
+ this.rootDir = plugins.path.join(base, harnessArg);
26
+ }
27
+ /**
28
+ * Turns an account email into a directory name that is safe on every
29
+ * filesystem while staying readable, so `ls ~/.authswitch/codex` is useful.
30
+ */
31
+ slugFor(emailArg) {
32
+ const slug = emailArg
33
+ .toLowerCase()
34
+ .replace(/[^a-z0-9._@+-]+/g, '_')
35
+ .replace(/^[._]+|[._]+$/g, '');
36
+ if (slug.length === 0) {
37
+ throw new Error(`cannot derive a stash name from "${emailArg}"`);
38
+ }
39
+ return slug;
40
+ }
41
+ entryDir(emailArg) {
42
+ return plugins.path.join(this.rootDir, this.slugFor(emailArg));
43
+ }
44
+ has(emailArg) {
45
+ return plugins.fs.existsSync(plugins.path.join(this.entryDir(emailArg), META_FILE_NAME));
46
+ }
47
+ /**
48
+ * Writes a credential and its remote-control enrollments under the account email,
49
+ * replacing any existing stash for the same account.
50
+ *
51
+ * Both files go through an atomic temp-and-rename, and the metadata is written
52
+ * last: a crash mid-write therefore leaves either the previous complete stash
53
+ * or a credential whose metadata is still the old one, never a directory that
54
+ * `list()` skips because its metadata never arrived. The caller is expected to
55
+ * verify with `readBack()` before destroying the original.
56
+ */
57
+ write(identityArg, rawAuthArg, enrollmentsArg, codexHomeArg) {
58
+ const previous = this.readMeta(identityArg.email);
59
+ if (previous && (previous.email !== identityArg.email || previous.accountId !== identityArg.accountId || previous.kind !== identityArg.kind)) {
60
+ throw new Error('a different Codex account already occupies this email-based stash; refusing to replace its credential');
61
+ }
62
+ const dir = this.entryDir(identityArg.email);
63
+ plugins.fs.mkdirSync(this.rootDir, { recursive: true, mode: 0o700 });
64
+ plugins.fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
65
+ // mkdirSync's mode is subject to the umask and is ignored for a directory
66
+ // that already exists, so tighten both levels explicitly.
67
+ plugins.fs.chmodSync(this.rootDir, 0o700);
68
+ plugins.fs.chmodSync(dir, 0o700);
69
+ const entry = {
70
+ email: identityArg.email,
71
+ kind: identityArg.kind,
72
+ accountId: identityArg.accountId,
73
+ planType: identityArg.planType,
74
+ userId: identityArg.userId,
75
+ stashedAt: new Date().toISOString(),
76
+ codexHome: codexHomeArg,
77
+ enrollments: enrollmentsArg,
78
+ };
79
+ writeSecretFileAtomically(plugins.path.join(dir, AUTH_FILE_NAME), rawAuthArg);
80
+ writeSecretFileAtomically(plugins.path.join(dir, META_FILE_NAME), `${JSON.stringify(entry, null, 2)}\n`);
81
+ return entry;
82
+ }
83
+ /**
84
+ * Reads a stash back and confirms it matches what was meant to be written.
85
+ * Callers use this before clearing the active credential, so a stash is only
86
+ * ever trusted once it has been proven readable.
87
+ */
88
+ readBack(emailArg, expectedAuthArg) {
89
+ const meta = this.readMeta(emailArg);
90
+ const auth = this.readAuth(emailArg);
91
+ return meta !== null && auth === expectedAuthArg;
92
+ }
93
+ readMeta(emailArg) {
94
+ const metaPath = plugins.path.join(this.entryDir(emailArg), META_FILE_NAME);
95
+ if (!plugins.fs.existsSync(metaPath)) {
96
+ return null;
97
+ }
98
+ try {
99
+ return JSON.parse(plugins.fs.readFileSync(metaPath, 'utf8'));
100
+ }
101
+ catch {
102
+ return null;
103
+ }
104
+ }
105
+ readAuth(emailArg) {
106
+ const authPath = plugins.path.join(this.entryDir(emailArg), AUTH_FILE_NAME);
107
+ if (!plugins.fs.existsSync(authPath)) {
108
+ return null;
109
+ }
110
+ return plugins.fs.readFileSync(authPath, 'utf8');
111
+ }
112
+ /** Every stash, newest first. Unreadable directories are skipped, not fatal. */
113
+ list() {
114
+ if (!plugins.fs.existsSync(this.rootDir)) {
115
+ return [];
116
+ }
117
+ const entries = [];
118
+ for (const nameArg of plugins.fs.readdirSync(this.rootDir)) {
119
+ const metaPath = plugins.path.join(this.rootDir, nameArg, META_FILE_NAME);
120
+ if (!plugins.fs.existsSync(metaPath)) {
121
+ continue;
122
+ }
123
+ try {
124
+ entries.push(JSON.parse(plugins.fs.readFileSync(metaPath, 'utf8')));
125
+ }
126
+ catch {
127
+ continue;
128
+ }
129
+ }
130
+ return entries.sort((leftArg, rightArg) => rightArg.stashedAt.localeCompare(leftArg.stashedAt));
131
+ }
132
+ /**
133
+ * Directories under the stash root that hold a credential but no readable
134
+ * metadata -- the shape an interrupted write would leave behind. Reported by
135
+ * `doctor` so they are visible rather than silently skipped by `list()`.
136
+ */
137
+ incomplete() {
138
+ if (!plugins.fs.existsSync(this.rootDir)) {
139
+ return [];
140
+ }
141
+ return plugins.fs.readdirSync(this.rootDir).filter((nameArg) => {
142
+ const dir = plugins.path.join(this.rootDir, nameArg);
143
+ if (!plugins.fs.statSync(dir).isDirectory()) {
144
+ return false;
145
+ }
146
+ const hasAuth = plugins.fs.existsSync(plugins.path.join(dir, AUTH_FILE_NAME));
147
+ const hasMeta = plugins.fs.existsSync(plugins.path.join(dir, META_FILE_NAME));
148
+ return hasAuth && !hasMeta;
149
+ });
150
+ }
151
+ /**
152
+ * Resolves a user-supplied account reference to a stashed email.
153
+ *
154
+ * Accepts the exact email, the directory slug, the local part, or a prefix.
155
+ * Deliberately not a substring match: this reference selects which credential
156
+ * becomes active, so an incidental substring hit would activate an account the
157
+ * user never named.
158
+ */
159
+ resolve(referenceArg) {
160
+ const needle = referenceArg.toLowerCase();
161
+ const all = this.list();
162
+ const exact = all.find((entryArg) => entryArg.email.toLowerCase() === needle);
163
+ if (exact) {
164
+ return { email: exact.email };
165
+ }
166
+ const bySlug = all.find((entryArg) => this.slugFor(entryArg.email) === needle);
167
+ if (bySlug) {
168
+ return { email: bySlug.email };
169
+ }
170
+ const byLocalPart = all.filter((entryArg) => entryArg.email.toLowerCase().split('@')[0] === needle);
171
+ if (byLocalPart.length === 1) {
172
+ return { email: byLocalPart[0].email };
173
+ }
174
+ if (byLocalPart.length > 1) {
175
+ return { candidates: byLocalPart.map((entryArg) => entryArg.email) };
176
+ }
177
+ const byPrefix = all.filter((entryArg) => entryArg.email.toLowerCase().startsWith(needle));
178
+ if (byPrefix.length === 1) {
179
+ return { email: byPrefix[0].email };
180
+ }
181
+ return { candidates: byPrefix.map((entryArg) => entryArg.email) };
182
+ }
183
+ remove(emailArg) {
184
+ const dir = this.entryDir(emailArg);
185
+ if (!plugins.fs.existsSync(dir)) {
186
+ return false;
187
+ }
188
+ plugins.fs.rmSync(dir, { recursive: true, force: true });
189
+ return true;
190
+ }
191
+ }
192
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zdGFzaHN0b3JlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHMvY2xhc3Nlcy5zdGFzaHN0b3JlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxPQUFPLE1BQU0sY0FBYyxDQUFDO0FBT3hDLE9BQU8sRUFBRSx5QkFBeUIsRUFBRSxNQUFNLGNBQWMsQ0FBQztBQUV6RCxNQUFNLGNBQWMsR0FBRyxXQUFXLENBQUM7QUFDbkMsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFDO0FBRXBDOzs7Ozs7OztHQVFHO0FBQ0gsTUFBTSxPQUFPLFVBQVU7SUFDTCxPQUFPLENBQVM7SUFDaEIsT0FBTyxDQUFlO0lBRXRDLFlBQVksVUFBd0IsRUFBRSxVQUFtQjtRQUN2RCxJQUFJLENBQUMsbUJBQW1CLENBQUMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDMUMsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO1FBQy9DLENBQUM7UUFDRCxJQUFJLENBQUMsT0FBTyxHQUFHLFVBQVUsQ0FBQztRQUMxQixNQUFNLElBQUksR0FDUixVQUFVO1lBQ1YsT0FBTyxDQUFDLEdBQUcsQ0FBQyxlQUFlO1lBQzNCLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsT0FBTyxFQUFFLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFDekQsSUFBSSxDQUFDLE9BQU8sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVEOzs7T0FHRztJQUNJLE9BQU8sQ0FBQyxRQUFnQjtRQUM3QixNQUFNLElBQUksR0FBRyxRQUFRO2FBQ2xCLFdBQVcsRUFBRTthQUNiLE9BQU8sQ0FBQyxrQkFBa0IsRUFBRSxHQUFHLENBQUM7YUFDaEMsT0FBTyxDQUFDLGdCQUFnQixFQUFFLEVBQUUsQ0FBQyxDQUFDO1FB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
@@ -0,0 +1,11 @@
1
+ import * as plugins from './plugins.js';
2
+ import type { IAuthHarness } from './interfaces.harness.js';
3
+ import { AuthSwitchOperations } from './classes.operations.js';
4
+ /** Owns account-management actions; terminal rendering and interaction belong to smartconsole. */
5
+ export declare class AuthSwitchTui {
6
+ private readonly harnesses;
7
+ private readonly out;
8
+ private readonly operations;
9
+ constructor(harnesses: readonly IAuthHarness[], out: plugins.smartconsole.SmartConsole, operations?: AuthSwitchOperations);
10
+ run(preferredArg?: IAuthHarness): Promise<number>;
11
+ }