sidekick-shared 0.27.5 → 0.27.6
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/CHANGELOG.md +30 -0
- package/README.md +35 -34
- package/dist/accountHealth.d.ts +14 -0
- package/dist/accountHealth.js +61 -14
- package/dist/accountLaunch.d.ts +6 -0
- package/dist/accountLaunch.js +61 -4
- package/dist/accountLease.d.ts +5 -0
- package/dist/accountLease.js +98 -0
- package/dist/accountManager.d.ts +7 -0
- package/dist/accountManager.js +226 -89
- package/dist/accountSync.d.ts +1 -5
- package/dist/accountSync.js +22 -6
- package/dist/accountSyncTypes.d.ts +9 -0
- package/dist/accounts.d.ts +75 -18
- package/dist/accounts.js +712 -189
- package/dist/claudeCredentialDoctor.d.ts +50 -0
- package/dist/claudeCredentialDoctor.js +277 -0
- package/dist/claudeCredentialLedger.d.ts +15 -0
- package/dist/claudeCredentialLedger.js +130 -0
- package/dist/claudeCredentials.d.ts +20 -3
- package/dist/claudeCredentials.js +50 -3
- package/dist/claudeLiveGuard.d.ts +33 -0
- package/dist/claudeLiveGuard.js +46 -0
- package/dist/claudeProfiles.d.ts +14 -0
- package/dist/claudeProfiles.js +22 -0
- package/dist/claudeRefreshLock.d.ts +15 -0
- package/dist/claudeRefreshLock.js +145 -0
- package/dist/codexAuth.d.ts +4 -0
- package/dist/codexAuth.js +18 -0
- package/dist/codexCredentialDoctor.d.ts +33 -0
- package/dist/codexCredentialDoctor.js +302 -0
- package/dist/codexCredentialStore.d.ts +29 -0
- package/dist/codexCredentialStore.js +213 -0
- package/dist/codexKeepAlive.d.ts +2 -0
- package/dist/codexKeepAlive.js +116 -0
- package/dist/codexPaths.d.ts +8 -2
- package/dist/codexPaths.js +51 -7
- package/dist/codexProfiles.d.ts +37 -31
- package/dist/codexProfiles.js +842 -671
- package/dist/credentialIO.d.ts +67 -7
- package/dist/credentialIO.js +211 -47
- package/dist/ensureDefaultAccounts.js +1 -8
- package/dist/index.d.ts +14 -4
- package/dist/index.js +29 -6
- package/dist/keepAlive.d.ts +2 -1
- package/dist/keepAlive.js +116 -29
- package/dist/liveCredentialGuard.d.ts +28 -0
- package/dist/liveCredentialGuard.js +36 -0
- package/dist/processDetection.d.ts +10 -3
- package/dist/processDetection.js +44 -11
- package/dist/schemas/accountManager.d.ts +22 -0
- package/dist/schemas/accountManager.js +4 -0
- package/dist/schemas/assistantTurn.d.ts +2 -2
- package/dist/terminalSync.d.ts +12 -2
- package/dist/terminalSync.js +27 -2
- package/package.json +1 -1
package/dist/keepAlive.d.ts
CHANGED
|
@@ -39,6 +39,7 @@ export declare function keepAliveCommand(provider: AccountProviderId): {
|
|
|
39
39
|
};
|
|
40
40
|
/**
|
|
41
41
|
* Serialised, bounded refresh of every inactive account that is `expiring`
|
|
42
|
-
* (or `unknown` for Claude). Never touches the live account
|
|
42
|
+
* (or `unknown` for Claude). Never touches the live account or any copy of
|
|
43
|
+
* its chain.
|
|
43
44
|
*/
|
|
44
45
|
export declare function refreshInactiveAccounts(options?: RefreshInactiveAccountsOptions): Promise<RefreshInactiveAccountsResult>;
|
package/dist/keepAlive.js
CHANGED
|
@@ -7,33 +7,50 @@ exports.refreshInactiveAccounts = refreshInactiveAccounts;
|
|
|
7
7
|
* providers' OAuth endpoints itself: it runs the official CLI inside the
|
|
8
8
|
* profile's isolated home and lets the CLI refresh (and rotate) the token
|
|
9
9
|
* where it belongs, then re-reads the store to record the new expiry.
|
|
10
|
+
*
|
|
11
|
+
* A refresh rotates the refresh token, so keep-alive only runs where the
|
|
12
|
+
* profile home holds the one live copy of its chain: never the live account,
|
|
13
|
+
* never a copy whose refresh token equals live's, never a copy taken from the
|
|
14
|
+
* live store that no switch has handed back yet, and never a stale copy when
|
|
15
|
+
* the backup is newer. The check and a lease are taken under the swap lock, so
|
|
16
|
+
* no switch can install that account while its CLI is refreshing.
|
|
10
17
|
*/
|
|
18
|
+
const codexKeepAlive_1 = require("./codexKeepAlive");
|
|
19
|
+
const codexProfiles_1 = require("./codexProfiles");
|
|
20
|
+
const codexPaths_1 = require("./codexPaths");
|
|
21
|
+
const codexCredentialStore_1 = require("./codexCredentialStore");
|
|
22
|
+
const codexAuth_1 = require("./codexAuth");
|
|
11
23
|
const child_process_1 = require("child_process");
|
|
12
24
|
const accountHealth_1 = require("./accountHealth");
|
|
13
25
|
const accountLaunch_1 = require("./accountLaunch");
|
|
26
|
+
const accounts_1 = require("./accounts");
|
|
14
27
|
/** The command each CLI runs to load (and refresh) its stored login. */
|
|
15
28
|
function keepAliveCommand(provider) {
|
|
16
29
|
if (provider === 'codex')
|
|
17
|
-
return { command: 'codex', args: ['
|
|
30
|
+
return { command: 'codex', args: ['app-server', '-c', 'cli_auth_credentials_store="file"'] };
|
|
18
31
|
const override = process.env.SIDEKICK_CLAUDE_KEEPALIVE_ARGS?.trim();
|
|
19
32
|
return { command: 'claude', args: override ? override.split(/\s+/) : ['auth', 'status'] };
|
|
20
33
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
34
|
+
/** How long a keep-alive lease outlives the CLI timeout before it lapses on its own. */
|
|
35
|
+
const LEASE_GRACE_MS = 30_000;
|
|
36
|
+
const defaultRunner = (command, args, env, timeoutMs) => command === 'codex'
|
|
37
|
+
? (0, codexKeepAlive_1.runCodexKeepAlive)(command, args, env, timeoutMs)
|
|
38
|
+
: new Promise((resolve) => {
|
|
39
|
+
try {
|
|
40
|
+
(0, child_process_1.execFile)(command, args, { encoding: 'utf8', env, timeout: timeoutMs, killSignal: 'SIGKILL', windowsHide: true }, (error, stdout) => {
|
|
41
|
+
const status = error
|
|
42
|
+
? (error.code ?? null)
|
|
43
|
+
: 0;
|
|
44
|
+
resolve({
|
|
45
|
+
status: typeof status === 'number' ? status : null,
|
|
46
|
+
stdout: String(stdout ?? ''),
|
|
47
|
+
});
|
|
30
48
|
});
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
});
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
resolve({ status: null, stdout: '' });
|
|
52
|
+
}
|
|
53
|
+
});
|
|
37
54
|
function eligible(view, includeFresh) {
|
|
38
55
|
if (view.health.isLive)
|
|
39
56
|
return 'live account; the CLI refreshes it in normal use';
|
|
@@ -49,7 +66,8 @@ function eligible(view, includeFresh) {
|
|
|
49
66
|
}
|
|
50
67
|
/**
|
|
51
68
|
* Serialised, bounded refresh of every inactive account that is `expiring`
|
|
52
|
-
* (or `unknown` for Claude). Never touches the live account
|
|
69
|
+
* (or `unknown` for Claude). Never touches the live account or any copy of
|
|
70
|
+
* its chain.
|
|
53
71
|
*/
|
|
54
72
|
async function refreshInactiveAccounts(options = {}) {
|
|
55
73
|
const result = { refreshed: [], skipped: [], failed: [] };
|
|
@@ -62,10 +80,15 @@ async function refreshInactiveAccounts(options = {}) {
|
|
|
62
80
|
result.skipped.push({ id: view.id, providerId: view.providerId, reason });
|
|
63
81
|
continue;
|
|
64
82
|
}
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
83
|
+
const isClaude = view.providerId === 'claude-code';
|
|
84
|
+
const beginLease = isClaude ? accounts_1.beginClaudeKeepAlive : codexProfiles_1.beginCodexKeepAlive;
|
|
85
|
+
const finishLease = isClaude ? accounts_1.finishClaudeKeepAlive : codexProfiles_1.finishCodexKeepAlive;
|
|
86
|
+
if (options.dryRun) {
|
|
87
|
+
const blocker = (isClaude ? accounts_1.getClaudeKeepAliveBlocker : codexProfiles_1.getCodexKeepAliveBlocker)(view.id);
|
|
88
|
+
if (blocker) {
|
|
89
|
+
result.skipped.push({ id: view.id, providerId: view.providerId, reason: blocker });
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
69
92
|
}
|
|
70
93
|
const { command, args } = keepAliveCommand(view.providerId);
|
|
71
94
|
if (options.dryRun) {
|
|
@@ -76,16 +99,71 @@ async function refreshInactiveAccounts(options = {}) {
|
|
|
76
99
|
});
|
|
77
100
|
continue;
|
|
78
101
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
102
|
+
{
|
|
103
|
+
const begin = beginLease(view.id, timeoutMs + LEASE_GRACE_MS);
|
|
104
|
+
if (!begin.ok) {
|
|
105
|
+
result.skipped.push({ id: view.id, providerId: view.providerId, reason: begin.reason });
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
let released = false;
|
|
110
|
+
const release = () => {
|
|
111
|
+
if (!released) {
|
|
112
|
+
released = true;
|
|
113
|
+
finishLease(view.id);
|
|
114
|
+
}
|
|
115
|
+
};
|
|
82
116
|
try {
|
|
83
|
-
const
|
|
117
|
+
const launch = (0, accountLaunch_1.getAccountLaunchEnv)(view.providerId, view.id, {
|
|
118
|
+
materialize: true,
|
|
119
|
+
restoreBackup: false,
|
|
120
|
+
});
|
|
121
|
+
if (launch.error) {
|
|
122
|
+
release();
|
|
123
|
+
result.skipped.push({ id: view.id, providerId: view.providerId, reason: launch.error });
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (!isClaude &&
|
|
127
|
+
(0, codexCredentialStore_1.canonicalCodexPath)(launch.home) === (0, codexCredentialStore_1.canonicalCodexPath)((0, codexPaths_1.getSystemCodexHome)())) {
|
|
128
|
+
result.skipped.push({
|
|
129
|
+
id: view.id,
|
|
130
|
+
providerId: view.providerId,
|
|
131
|
+
reason: 'the account became live before refresh',
|
|
132
|
+
});
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
const before = isClaude ? null : (0, codexCredentialStore_1.readCodexCredentialStore)(launch.home);
|
|
136
|
+
const env = { ...process.env, ...launch.env };
|
|
137
|
+
for (const name of launch.envUnset)
|
|
138
|
+
delete env[name];
|
|
139
|
+
if (!isClaude)
|
|
140
|
+
for (const name of [
|
|
141
|
+
'OPENAI_API_KEY',
|
|
142
|
+
'CODEX_API_KEY',
|
|
143
|
+
'CODEX_ACCESS_TOKEN',
|
|
144
|
+
'OPENAI_FEDERATION_RULE_ID',
|
|
145
|
+
'OPENAI_IDENTITY_TOKEN_FILE',
|
|
146
|
+
'OPENAI_WORKLOAD_IDENTITY_CONTEXT',
|
|
147
|
+
])
|
|
148
|
+
delete env[name];
|
|
149
|
+
let run;
|
|
150
|
+
try {
|
|
151
|
+
run = await runner(command, args, env, timeoutMs);
|
|
152
|
+
}
|
|
153
|
+
finally {
|
|
154
|
+
release();
|
|
155
|
+
}
|
|
84
156
|
const after = (0, accountHealth_1.getAccountHealth)(view.providerId, view.id, {
|
|
85
157
|
probe: 'store',
|
|
86
158
|
now: options.now,
|
|
87
159
|
});
|
|
88
|
-
|
|
160
|
+
const codexAfter = isClaude ? null : (0, codexCredentialStore_1.readCodexCredentialStore)(launch.home);
|
|
161
|
+
const advanced = isClaude ||
|
|
162
|
+
(before?.status === 'ok' &&
|
|
163
|
+
codexAfter?.status === 'ok' &&
|
|
164
|
+
(0, codexAuth_1.identitiesMatch)((0, codexAuth_1.readAuthIdentityFromRaw)(before.snapshot.authRaw), (0, codexAuth_1.readAuthIdentityFromRaw)(codexAfter.snapshot.authRaw)) &&
|
|
165
|
+
(0, codexAuth_1.compareCodexAuthFreshness)(codexAfter.snapshot.authRaw, before.snapshot.authRaw) > 0);
|
|
166
|
+
if (after.state === 'fresh' && advanced && (isClaude || run.status === 0)) {
|
|
89
167
|
result.refreshed.push({ id: view.id, providerId: view.providerId });
|
|
90
168
|
}
|
|
91
169
|
else {
|
|
@@ -93,13 +171,22 @@ async function refreshInactiveAccounts(options = {}) {
|
|
|
93
171
|
id: view.id,
|
|
94
172
|
providerId: view.providerId,
|
|
95
173
|
error: run.status === 0
|
|
96
|
-
?
|
|
97
|
-
|
|
174
|
+
? isClaude
|
|
175
|
+
? `${command} ran but the stored credential is still ${after.state}.`
|
|
176
|
+
: `${command} ran but no verified credential advance was observed (health: ${after.state}).`
|
|
177
|
+
: `${command} exited with status ${run.status ?? 'unknown'}.${isClaude ? '' : ' Codex app-server refresh requires a compatible Codex CLI; update it and retry.'}`,
|
|
98
178
|
});
|
|
99
179
|
}
|
|
100
180
|
}
|
|
101
181
|
catch (err) {
|
|
102
|
-
result.failed.push({
|
|
182
|
+
result.failed.push({
|
|
183
|
+
id: view.id,
|
|
184
|
+
providerId: view.providerId,
|
|
185
|
+
error: isClaude ? String(err) : 'Codex keep-alive could not complete safely.',
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
finally {
|
|
189
|
+
release();
|
|
103
190
|
}
|
|
104
191
|
}
|
|
105
192
|
return result;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/** Pure policy shared by provider-specific live credential installers. */
|
|
2
|
+
export type LiveCredentialWriteIntent = 'switch' | 'relogin' | 'repair' | 'rollback';
|
|
3
|
+
export type LiveCredentialWriteRefusal = 'live-unreadable' | 'invalid-candidate' | 'same-account' | 'different-account' | 'same-link' | 'not-captured' | 'not-newer' | 'live-changed';
|
|
4
|
+
export type LiveCredentialWriteDecision = {
|
|
5
|
+
allow: true;
|
|
6
|
+
} | {
|
|
7
|
+
allow: false;
|
|
8
|
+
code: LiveCredentialWriteRefusal;
|
|
9
|
+
reason: string;
|
|
10
|
+
};
|
|
11
|
+
export interface LiveCredentialWriteFacts {
|
|
12
|
+
provider: string;
|
|
13
|
+
intent: LiveCredentialWriteIntent;
|
|
14
|
+
liveStatus: 'ok' | 'absent' | 'corrupt' | 'error';
|
|
15
|
+
candidateValid: boolean;
|
|
16
|
+
liveHasCredential: boolean;
|
|
17
|
+
liveAccountId: string | null;
|
|
18
|
+
candidateAccountId: string;
|
|
19
|
+
sameLink: boolean;
|
|
20
|
+
strictlyNewer: boolean;
|
|
21
|
+
capturedOutgoing?: boolean;
|
|
22
|
+
matchesWritten: boolean;
|
|
23
|
+
/** Compatibility with Claude's established missing/corrupt rollback policy. */
|
|
24
|
+
allowNonOkRollback?: boolean;
|
|
25
|
+
rejectCorrupt?: boolean;
|
|
26
|
+
requireDifferentLinkForAdvance?: boolean;
|
|
27
|
+
}
|
|
28
|
+
export declare function decideLiveCredentialWrite(f: LiveCredentialWriteFacts): LiveCredentialWriteDecision;
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.decideLiveCredentialWrite = decideLiveCredentialWrite;
|
|
4
|
+
function decideLiveCredentialWrite(f) {
|
|
5
|
+
const refuse = (code, reason) => ({ allow: false, code, reason });
|
|
6
|
+
if (f.liveStatus === 'error' || (f.rejectCorrupt && f.liveStatus === 'corrupt')) {
|
|
7
|
+
return refuse('live-unreadable', `The live ${f.provider} login could not be read, so it was left untouched.`);
|
|
8
|
+
}
|
|
9
|
+
if (f.intent === 'rollback') {
|
|
10
|
+
return f.matchesWritten || (f.allowNonOkRollback && f.liveStatus !== 'ok')
|
|
11
|
+
? { allow: true }
|
|
12
|
+
: refuse('live-changed', `The live ${f.provider} login changed after the switch wrote it; it was kept.`);
|
|
13
|
+
}
|
|
14
|
+
if (!f.candidateValid)
|
|
15
|
+
return refuse('invalid-candidate', `The saved credential is not a ${f.provider} login.`);
|
|
16
|
+
if (f.intent === 'switch') {
|
|
17
|
+
if (f.liveAccountId !== null && f.liveAccountId === f.candidateAccountId) {
|
|
18
|
+
return refuse('same-account', 'That account is already the live login.');
|
|
19
|
+
}
|
|
20
|
+
if (f.sameLink)
|
|
21
|
+
return refuse('same-link', 'The saved login is the same refresh token the live login holds; sign in to that account again.');
|
|
22
|
+
if (f.liveHasCredential && !f.capturedOutgoing) {
|
|
23
|
+
return refuse('not-captured', 'The outgoing live login was not saved first, so it was left untouched.');
|
|
24
|
+
}
|
|
25
|
+
return { allow: true };
|
|
26
|
+
}
|
|
27
|
+
if (f.liveAccountId !== null && f.liveAccountId !== f.candidateAccountId) {
|
|
28
|
+
return refuse('different-account', `The live ${f.provider} login belongs to another account; switch accounts instead.`);
|
|
29
|
+
}
|
|
30
|
+
if (!f.liveHasCredential)
|
|
31
|
+
return { allow: true };
|
|
32
|
+
if (!f.strictlyNewer || (f.requireDifferentLinkForAdvance && f.sameLink)) {
|
|
33
|
+
return refuse('not-newer', `The live ${f.provider} login is already at least as new; it was kept.`);
|
|
34
|
+
}
|
|
35
|
+
return { allow: true };
|
|
36
|
+
}
|
|
@@ -14,9 +14,6 @@ export interface RunningAccountConsumer {
|
|
|
14
14
|
/** The user-facing sentence both UIs print for this consumer. */
|
|
15
15
|
reachability: string;
|
|
16
16
|
}
|
|
17
|
-
/** Sync sibling of {@link findRunningProcesses}; blocks up to 4 s. */
|
|
18
|
-
export declare function findRunningProcessesSync(names: string[]): RunningProcess[];
|
|
19
|
-
export declare function findRunningProcesses(names: string[]): Promise<RunningProcess[]>;
|
|
20
17
|
export declare const ACCOUNT_CONSUMER_REACHABILITY: Record<AccountConsumerKind, {
|
|
21
18
|
switched: boolean;
|
|
22
19
|
reachability: string;
|
|
@@ -30,3 +27,13 @@ export declare function detectRunningAccountConsumers(provider?: 'claude-code' |
|
|
|
30
27
|
export declare function detectRunningAccountConsumersSync(provider?: 'claude-code' | 'codex'): RunningAccountConsumer[];
|
|
31
28
|
/** Build a consumer entry for a kind the host detects itself (e.g. its own extension host). */
|
|
32
29
|
export declare function describeAccountConsumer(kind: AccountConsumerKind, pids?: number[]): RunningAccountConsumer;
|
|
30
|
+
/** Compatibility wrappers keep the established best-effort list API. */
|
|
31
|
+
export declare function findRunningProcessesSync(names: string[]): RunningProcess[];
|
|
32
|
+
export declare function findRunningProcesses(names: string[]): Promise<RunningProcess[]>;
|
|
33
|
+
export interface AccountConsumerScan {
|
|
34
|
+
ok: boolean;
|
|
35
|
+
consumers: RunningAccountConsumer[];
|
|
36
|
+
}
|
|
37
|
+
/** Safety decisions must distinguish a failed process scan from an empty one. */
|
|
38
|
+
export declare function inspectRunningAccountConsumersSync(provider: 'claude-code' | 'codex'): AccountConsumerScan;
|
|
39
|
+
export declare function inspectRunningAccountConsumers(provider: 'claude-code' | 'codex'): Promise<AccountConsumerScan>;
|
package/dist/processDetection.js
CHANGED
|
@@ -34,11 +34,13 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.ACCOUNT_CONSUMER_REACHABILITY = void 0;
|
|
37
|
-
exports.findRunningProcessesSync = findRunningProcessesSync;
|
|
38
|
-
exports.findRunningProcesses = findRunningProcesses;
|
|
39
37
|
exports.detectRunningAccountConsumers = detectRunningAccountConsumers;
|
|
40
38
|
exports.detectRunningAccountConsumersSync = detectRunningAccountConsumersSync;
|
|
41
39
|
exports.describeAccountConsumer = describeAccountConsumer;
|
|
40
|
+
exports.findRunningProcessesSync = findRunningProcessesSync;
|
|
41
|
+
exports.findRunningProcesses = findRunningProcesses;
|
|
42
|
+
exports.inspectRunningAccountConsumersSync = inspectRunningAccountConsumersSync;
|
|
43
|
+
exports.inspectRunningAccountConsumers = inspectRunningAccountConsumers;
|
|
42
44
|
/**
|
|
43
45
|
* Cross-platform detection of running CLI/app processes that hold provider
|
|
44
46
|
* credentials in memory. Bounded, never throws, never spawns a shell.
|
|
@@ -47,6 +49,7 @@ const child_process_1 = require("child_process");
|
|
|
47
49
|
const path = __importStar(require("path"));
|
|
48
50
|
const PROBE_TIMEOUT_MS = 4000;
|
|
49
51
|
const CLAUDE_NPM_ENTRY = /claude-code[\\/]cli\.js/;
|
|
52
|
+
const CODEX_NPM_ENTRY = /(?:@openai[\\/]codex|codex[\\/]bin)[\\/].*codex\.js/;
|
|
50
53
|
function parseUnixTable(stdout) {
|
|
51
54
|
const rows = [];
|
|
52
55
|
for (const line of stdout.split('\n')) {
|
|
@@ -87,6 +90,15 @@ function matchRows(rows, names) {
|
|
|
87
90
|
CLAUDE_NPM_ENTRY.test(row.args)) {
|
|
88
91
|
name = 'claude';
|
|
89
92
|
}
|
|
93
|
+
if (!name &&
|
|
94
|
+
wanted.has('codex') &&
|
|
95
|
+
/^node(\.exe)?$/i.test(base) &&
|
|
96
|
+
CODEX_NPM_ENTRY.test(row.args))
|
|
97
|
+
name = 'codex';
|
|
98
|
+
if (!name &&
|
|
99
|
+
wanted.has('Codex') &&
|
|
100
|
+
/(?:^|[\\/])Codex\.app[\\/]/.test(row.command + ' ' + row.args))
|
|
101
|
+
name = 'Codex';
|
|
90
102
|
if (name)
|
|
91
103
|
found.push({ pid: row.pid, name, command: row.command });
|
|
92
104
|
}
|
|
@@ -101,9 +113,9 @@ function parseOutput(stdout) {
|
|
|
101
113
|
return process.platform === 'win32' ? parseWindowsCsv(stdout) : parseUnixTable(stdout);
|
|
102
114
|
}
|
|
103
115
|
/** Sync sibling of {@link findRunningProcesses}; blocks up to 4 s. */
|
|
104
|
-
function
|
|
116
|
+
function inspectProcessesSync(names) {
|
|
105
117
|
if (names.length === 0)
|
|
106
|
-
return [];
|
|
118
|
+
return { ok: true, processes: [] };
|
|
107
119
|
try {
|
|
108
120
|
const { command, args } = probeCommand();
|
|
109
121
|
const result = (0, child_process_1.spawnSync)(command, args, {
|
|
@@ -114,16 +126,16 @@ function findRunningProcessesSync(names) {
|
|
|
114
126
|
windowsHide: true,
|
|
115
127
|
});
|
|
116
128
|
if (result.error || result.status !== 0)
|
|
117
|
-
return [];
|
|
118
|
-
return matchRows(parseOutput(String(result.stdout ?? '')), names);
|
|
129
|
+
return { ok: false, processes: [] };
|
|
130
|
+
return { ok: true, processes: matchRows(parseOutput(String(result.stdout ?? '')), names) };
|
|
119
131
|
}
|
|
120
132
|
catch {
|
|
121
|
-
return [];
|
|
133
|
+
return { ok: false, processes: [] };
|
|
122
134
|
}
|
|
123
135
|
}
|
|
124
|
-
function
|
|
136
|
+
function inspectProcesses(names) {
|
|
125
137
|
if (names.length === 0)
|
|
126
|
-
return Promise.resolve([]);
|
|
138
|
+
return Promise.resolve({ ok: true, processes: [] });
|
|
127
139
|
return new Promise((resolve) => {
|
|
128
140
|
try {
|
|
129
141
|
const { command, args } = probeCommand();
|
|
@@ -134,11 +146,14 @@ function findRunningProcesses(names) {
|
|
|
134
146
|
windowsHide: true,
|
|
135
147
|
maxBuffer: 16 * 1024 * 1024,
|
|
136
148
|
}, (error, stdout) => {
|
|
137
|
-
resolve(
|
|
149
|
+
resolve({
|
|
150
|
+
ok: !error,
|
|
151
|
+
processes: error ? [] : matchRows(parseOutput(String(stdout ?? '')), names),
|
|
152
|
+
});
|
|
138
153
|
});
|
|
139
154
|
}
|
|
140
155
|
catch {
|
|
141
|
-
resolve([]);
|
|
156
|
+
resolve({ ok: false, processes: [] });
|
|
142
157
|
}
|
|
143
158
|
});
|
|
144
159
|
}
|
|
@@ -208,3 +223,21 @@ function detectRunningAccountConsumersSync(provider) {
|
|
|
208
223
|
function describeAccountConsumer(kind, pids = []) {
|
|
209
224
|
return toConsumer(kind, pids);
|
|
210
225
|
}
|
|
226
|
+
/** Compatibility wrappers keep the established best-effort list API. */
|
|
227
|
+
function findRunningProcessesSync(names) {
|
|
228
|
+
return inspectProcessesSync(names).processes;
|
|
229
|
+
}
|
|
230
|
+
async function findRunningProcesses(names) {
|
|
231
|
+
return (await inspectProcesses(names)).processes;
|
|
232
|
+
}
|
|
233
|
+
/** Safety decisions must distinguish a failed process scan from an empty one. */
|
|
234
|
+
function inspectRunningAccountConsumersSync(provider) {
|
|
235
|
+
const kinds = kindsForProvider(provider);
|
|
236
|
+
const result = inspectProcessesSync(kinds.map((kind) => CONSUMER_PROCESS_NAMES[kind]));
|
|
237
|
+
return { ok: result.ok, consumers: groupConsumers(result.processes, kinds) };
|
|
238
|
+
}
|
|
239
|
+
async function inspectRunningAccountConsumers(provider) {
|
|
240
|
+
const kinds = kindsForProvider(provider);
|
|
241
|
+
const result = await inspectProcesses(kinds.map((kind) => CONSUMER_PROCESS_NAMES[kind]));
|
|
242
|
+
return { ok: result.ok, consumers: groupConsumers(result.processes, kinds) };
|
|
243
|
+
}
|
|
@@ -143,6 +143,7 @@ export declare const accountHealthSidecarSchema: z.ZodObject<{
|
|
|
143
143
|
"api-key": "api-key";
|
|
144
144
|
oauth: "oauth";
|
|
145
145
|
}>>;
|
|
146
|
+
refreshFp: z.ZodOptional<z.ZodString>;
|
|
146
147
|
source: z.ZodEnum<{
|
|
147
148
|
login: "login";
|
|
148
149
|
"live-sync": "live-sync";
|
|
@@ -310,6 +311,13 @@ export declare const providerSyncReportSchema: z.ZodObject<{
|
|
|
310
311
|
folded: z.ZodOptional<z.ZodString>;
|
|
311
312
|
repointed: z.ZodOptional<z.ZodString>;
|
|
312
313
|
merged: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
314
|
+
demoted: z.ZodOptional<z.ZodString>;
|
|
315
|
+
repaired: z.ZodOptional<z.ZodString>;
|
|
316
|
+
journal: z.ZodOptional<z.ZodEnum<{
|
|
317
|
+
finished: "finished";
|
|
318
|
+
"rolled-back": "rolled-back";
|
|
319
|
+
cleared: "cleared";
|
|
320
|
+
}>>;
|
|
313
321
|
skipped: z.ZodOptional<z.ZodString>;
|
|
314
322
|
warnings: z.ZodArray<z.ZodString>;
|
|
315
323
|
}, z.core.$strip>;
|
|
@@ -322,6 +330,13 @@ export declare const syncReportSchema: z.ZodObject<{
|
|
|
322
330
|
folded: z.ZodOptional<z.ZodString>;
|
|
323
331
|
repointed: z.ZodOptional<z.ZodString>;
|
|
324
332
|
merged: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
333
|
+
demoted: z.ZodOptional<z.ZodString>;
|
|
334
|
+
repaired: z.ZodOptional<z.ZodString>;
|
|
335
|
+
journal: z.ZodOptional<z.ZodEnum<{
|
|
336
|
+
finished: "finished";
|
|
337
|
+
"rolled-back": "rolled-back";
|
|
338
|
+
cleared: "cleared";
|
|
339
|
+
}>>;
|
|
325
340
|
skipped: z.ZodOptional<z.ZodString>;
|
|
326
341
|
warnings: z.ZodArray<z.ZodString>;
|
|
327
342
|
}, z.core.$strip>;
|
|
@@ -333,6 +348,13 @@ export declare const syncReportSchema: z.ZodObject<{
|
|
|
333
348
|
folded: z.ZodOptional<z.ZodString>;
|
|
334
349
|
repointed: z.ZodOptional<z.ZodString>;
|
|
335
350
|
merged: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
351
|
+
demoted: z.ZodOptional<z.ZodString>;
|
|
352
|
+
repaired: z.ZodOptional<z.ZodString>;
|
|
353
|
+
journal: z.ZodOptional<z.ZodEnum<{
|
|
354
|
+
finished: "finished";
|
|
355
|
+
"rolled-back": "rolled-back";
|
|
356
|
+
cleared: "cleared";
|
|
357
|
+
}>>;
|
|
336
358
|
skipped: z.ZodOptional<z.ZodString>;
|
|
337
359
|
warnings: z.ZodArray<z.ZodString>;
|
|
338
360
|
}, z.core.$strip>;
|
|
@@ -107,6 +107,7 @@ exports.accountHealthSidecarSchema = zod_1.z.object({
|
|
|
107
107
|
lastRefreshAt: zod_1.z.number().optional(),
|
|
108
108
|
hasRefreshToken: zod_1.z.boolean().optional(),
|
|
109
109
|
authMode: zod_1.z.enum(['chatgpt', 'api-key', 'oauth']).optional(),
|
|
110
|
+
refreshFp: zod_1.z.string().optional(),
|
|
110
111
|
source: exports.accountHealthSourceSchema,
|
|
111
112
|
});
|
|
112
113
|
exports.accountHealthSchema = zod_1.z.object({
|
|
@@ -178,6 +179,9 @@ exports.providerSyncReportSchema = zod_1.z.object({
|
|
|
178
179
|
folded: zod_1.z.string().optional(),
|
|
179
180
|
repointed: zod_1.z.string().optional(),
|
|
180
181
|
merged: zod_1.z.array(zod_1.z.string()).optional(),
|
|
182
|
+
demoted: zod_1.z.string().optional(),
|
|
183
|
+
repaired: zod_1.z.string().optional(),
|
|
184
|
+
journal: zod_1.z.enum(['finished', 'rolled-back', 'cleared']).optional(),
|
|
181
185
|
skipped: zod_1.z.string().optional(),
|
|
182
186
|
warnings: zod_1.z.array(zod_1.z.string()),
|
|
183
187
|
});
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
import { z } from 'zod';
|
|
8
8
|
export declare const assistantTurnEventTypeSchema: z.ZodEnum<{
|
|
9
9
|
error: "error";
|
|
10
|
-
text: "text";
|
|
11
10
|
status: "status";
|
|
11
|
+
text: "text";
|
|
12
12
|
tool_use: "tool_use";
|
|
13
13
|
tool_result: "tool_result";
|
|
14
14
|
progress: "progress";
|
|
@@ -18,8 +18,8 @@ export declare const assistantTurnEventTypeSchema: z.ZodEnum<{
|
|
|
18
18
|
export declare const assistantTurnEventSchema: z.ZodObject<{
|
|
19
19
|
eventType: z.ZodEnum<{
|
|
20
20
|
error: "error";
|
|
21
|
-
text: "text";
|
|
22
21
|
status: "status";
|
|
22
|
+
text: "text";
|
|
23
23
|
tool_use: "tool_use";
|
|
24
24
|
tool_result: "tool_result";
|
|
25
25
|
progress: "progress";
|
package/dist/terminalSync.d.ts
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import type { AccountProviderId } from './accountRegistry';
|
|
2
2
|
/**
|
|
3
|
-
* Write a POSIX launcher script that runs the provider CLI
|
|
4
|
-
*
|
|
3
|
+
* Write a POSIX launcher script that runs the provider CLI as a saved account.
|
|
4
|
+
* The script defers to `sidekick accounts shell` at run time, which resolves
|
|
5
|
+
* the right home then: the account's profile home while it is inactive, the
|
|
6
|
+
* live home while it is the live login (a session pinned to the profile home
|
|
7
|
+
* would otherwise be a second copy of the live login). Unix only; on Windows
|
|
8
|
+
* use `sidekick accounts env --shell powershell`.
|
|
9
|
+
*/
|
|
10
|
+
export declare function writeAccountLauncher(name: string, provider: AccountProviderId, accountId: string): void;
|
|
11
|
+
/**
|
|
12
|
+
* @deprecated Pins a launcher to one profile home; when that account becomes
|
|
13
|
+
* the live login the launcher runs a second copy of it. Use
|
|
14
|
+
* {@link writeAccountLauncher}.
|
|
5
15
|
*/
|
|
6
16
|
export declare function writeLauncher(name: string, provider: AccountProviderId, profileHome: string): void;
|
|
7
17
|
export declare function removeLauncher(name: string): void;
|
package/dist/terminalSync.js
CHANGED
|
@@ -33,6 +33,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
33
33
|
};
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.writeAccountLauncher = writeAccountLauncher;
|
|
36
37
|
exports.writeLauncher = writeLauncher;
|
|
37
38
|
exports.removeLauncher = removeLauncher;
|
|
38
39
|
const fs = __importStar(require("fs"));
|
|
@@ -79,9 +80,33 @@ function assertNoLauncherCollision(name, targetPath) {
|
|
|
79
80
|
}
|
|
80
81
|
}
|
|
81
82
|
}
|
|
83
|
+
function shellSingleQuote(value) {
|
|
84
|
+
return `'${value.replace(/'/g, `'\\''`)}'`;
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Write a POSIX launcher script that runs the provider CLI as a saved account.
|
|
88
|
+
* The script defers to `sidekick accounts shell` at run time, which resolves
|
|
89
|
+
* the right home then: the account's profile home while it is inactive, the
|
|
90
|
+
* live home while it is the live login (a session pinned to the profile home
|
|
91
|
+
* would otherwise be a second copy of the live login). Unix only; on Windows
|
|
92
|
+
* use `sidekick accounts env --shell powershell`.
|
|
93
|
+
*/
|
|
94
|
+
function writeAccountLauncher(name, provider, accountId) {
|
|
95
|
+
assertValidLauncherName(name);
|
|
96
|
+
const launcherPath = getLauncherPath(name);
|
|
97
|
+
assertNoLauncherCollision(name, launcherPath);
|
|
98
|
+
const script = [
|
|
99
|
+
'#!/bin/sh',
|
|
100
|
+
LAUNCHER_MARKER,
|
|
101
|
+
`exec sidekick accounts shell --provider ${provider} ${shellSingleQuote(accountId)} -- ${providerBinary(provider)} "$@"`,
|
|
102
|
+
'',
|
|
103
|
+
].join('\n');
|
|
104
|
+
(0, atomic_1.atomicWriteFileSync)(launcherPath, script, 0o755);
|
|
105
|
+
}
|
|
82
106
|
/**
|
|
83
|
-
*
|
|
84
|
-
*
|
|
107
|
+
* @deprecated Pins a launcher to one profile home; when that account becomes
|
|
108
|
+
* the live login the launcher runs a second copy of it. Use
|
|
109
|
+
* {@link writeAccountLauncher}.
|
|
85
110
|
*/
|
|
86
111
|
function writeLauncher(name, provider, profileHome) {
|
|
87
112
|
assertValidLauncherName(name);
|