synabun 2.0.5 → 2.0.7
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 +40 -0
- package/README.md +2 -1
- package/THIRD-PARTY-LICENSES.md +13 -0
- package/docs/whatsapp.md +151 -16
- package/hooks/claude-code/shared.mjs +6 -3
- package/lib/child-path.js +303 -0
- package/lib/claude-hooks.js +2 -1
- package/lib/data-home-migration.js +2 -0
- package/lib/desktop-app.js +265 -0
- package/lib/external-tools.js +7 -3
- package/lib/log-redact.js +102 -0
- package/lib/packaged-runtime.js +138 -11
- package/mcp-server/dist/http.d.ts +3 -1
- package/mcp-server/dist/http.d.ts.map +1 -1
- package/mcp-server/dist/http.js +15 -4
- package/mcp-server/dist/http.js.map +1 -1
- package/mcp-server/dist/index.d.ts.map +1 -1
- package/mcp-server/dist/index.js +9 -6
- package/mcp-server/dist/index.js.map +1 -1
- package/mcp-server/dist/services/budget-judgments.d.ts +108 -0
- package/mcp-server/dist/services/budget-judgments.d.ts.map +1 -0
- package/mcp-server/dist/services/budget-judgments.js +153 -0
- package/mcp-server/dist/services/budget-judgments.js.map +1 -0
- package/mcp-server/dist/services/codex-config-heal.d.ts +5 -1
- package/mcp-server/dist/services/codex-config-heal.d.ts.map +1 -1
- package/mcp-server/dist/services/codex-config-heal.js +41 -4
- package/mcp-server/dist/services/codex-config-heal.js.map +1 -1
- package/mcp-server/dist/services/identity.d.ts +11 -0
- package/mcp-server/dist/services/identity.d.ts.map +1 -1
- package/mcp-server/dist/services/identity.js +24 -0
- package/mcp-server/dist/services/identity.js.map +1 -1
- package/mcp-server/dist/services/neural-interface.d.ts +13 -0
- package/mcp-server/dist/services/neural-interface.d.ts.map +1 -1
- package/mcp-server/dist/services/neural-interface.js +34 -2
- package/mcp-server/dist/services/neural-interface.js.map +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts +1 -1
- package/mcp-server/dist/services/typesafe-config.d.ts.map +1 -1
- package/mcp-server/dist/services/typesafe-config.js +4 -1
- package/mcp-server/dist/services/typesafe-config.js.map +1 -1
- package/mcp-server/dist/tools/agents.d.ts +10 -7
- package/mcp-server/dist/tools/agents.d.ts.map +1 -1
- package/mcp-server/dist/tools/agents.js +34 -13
- package/mcp-server/dist/tools/agents.js.map +1 -1
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts +17 -0
- package/mcp-server/dist/tools/whatsapp-send-file.d.ts.map +1 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js +44 -0
- package/mcp-server/dist/tools/whatsapp-send-file.js.map +1 -0
- package/mcp-server/dist/tui.js +2 -1
- package/mcp-server/dist/tui.js.map +1 -1
- package/mcp-server/dist/version.d.ts +5 -0
- package/mcp-server/dist/version.d.ts.map +1 -0
- package/mcp-server/dist/version.js +21 -0
- package/mcp-server/dist/version.js.map +1 -0
- package/mcp-server/package-lock.json +2 -2
- package/mcp-server/package.json +1 -1
- package/mcp-server/run.mjs +15 -9
- package/mcp-server/src/http.ts +18 -3
- package/mcp-server/src/index.ts +9 -6
- package/mcp-server/src/services/budget-judgments.ts +183 -0
- package/mcp-server/src/services/codex-config-heal.ts +35 -4
- package/mcp-server/src/services/identity.ts +27 -0
- package/mcp-server/src/services/neural-interface.ts +34 -2
- package/mcp-server/src/services/typesafe-config.ts +4 -1
- package/mcp-server/src/tools/agents.ts +33 -14
- package/mcp-server/src/tools/whatsapp-send-file.ts +51 -0
- package/mcp-server/src/tui.ts +2 -1
- package/mcp-server/src/version.ts +22 -0
- package/neural-interface/i18n/en.json +627 -57
- package/neural-interface/i18n/pt-BR.json +626 -56
- package/neural-interface/lib/account-usage.js +163 -0
- package/neural-interface/lib/assistant-api.js +255 -52
- package/neural-interface/lib/assistant-brains/claude.js +15 -2
- package/neural-interface/lib/assistant-brains/codex.js +3 -0
- package/neural-interface/lib/assistant-brains/opencode.js +17 -4
- package/neural-interface/lib/assistant-budget-planner.js +390 -0
- package/neural-interface/lib/assistant-budget-split.js +408 -0
- package/neural-interface/lib/assistant-budget.js +94 -95
- package/neural-interface/lib/assistant-config.js +62 -14
- package/neural-interface/lib/assistant-dispatch.js +432 -125
- package/neural-interface/lib/assistant-jev.js +26 -3
- package/neural-interface/lib/assistant-persona.js +68 -11
- package/neural-interface/lib/assistant-plan-permissions.js +8 -1
- package/neural-interface/lib/assistant-route-accounts.js +14 -0
- package/neural-interface/lib/assistant-route-gate.js +19 -3
- package/neural-interface/lib/assistant-router.js +373 -42
- package/neural-interface/lib/assistant-runtime.js +307 -47
- package/neural-interface/lib/assistant-user-writer.js +4 -2
- package/neural-interface/lib/augmented-path.js +317 -53
- package/neural-interface/lib/claude-accounts.js +342 -31
- package/neural-interface/lib/claude-agent-bridge.js +90 -3
- package/neural-interface/lib/claude-executable.js +6 -1
- package/neural-interface/lib/claude-model-catalog.js +3 -3
- package/neural-interface/lib/claude-panel-auth.js +221 -0
- package/neural-interface/lib/claude-profile-api-key.js +62 -0
- package/neural-interface/lib/cli-install-api.js +137 -0
- package/neural-interface/lib/cli-install.js +797 -0
- package/neural-interface/lib/cli-path.js +130 -0
- package/neural-interface/lib/cli-resolver.js +744 -0
- package/neural-interface/lib/cli-update-planner.js +143 -7
- package/neural-interface/lib/codex-account-auth.js +178 -0
- package/neural-interface/lib/codex-accounts.js +489 -0
- package/neural-interface/lib/codex-capabilities.js +2 -1
- package/neural-interface/lib/codex-compat-rpc.js +8 -2
- package/neural-interface/lib/codex-mcp-approvals.js +5 -1
- package/neural-interface/lib/codex-panel-auth.js +62 -0
- package/neural-interface/lib/codex-session-settings.js +1 -1
- package/neural-interface/lib/codex-settings-schema.js +120 -0
- package/neural-interface/lib/desktop/config.js +3 -0
- package/neural-interface/lib/git-bash/bzip2.js +339 -0
- package/neural-interface/lib/git-bash/claude-settings.js +73 -0
- package/neural-interface/lib/git-bash/extract-worker.js +34 -0
- package/neural-interface/lib/git-bash/install.js +529 -0
- package/neural-interface/lib/git-bash/licenses/COPYING +360 -0
- package/neural-interface/lib/git-bash/licenses/LGPL-2.1 +511 -0
- package/neural-interface/lib/git-bash/manager.js +268 -0
- package/neural-interface/lib/git-bash/pins.js +206 -0
- package/neural-interface/lib/git-bash/pins.json +34 -0
- package/neural-interface/lib/git-bash/resolver.js +194 -0
- package/neural-interface/lib/git-read.js +34 -2
- package/neural-interface/lib/install-details.js +145 -0
- package/neural-interface/lib/mcp-installer.js +14 -2
- package/neural-interface/lib/native-loop-providers.js +16 -3
- package/neural-interface/lib/native-loop-runtime.js +9 -4
- package/neural-interface/lib/os-path.js +319 -0
- package/neural-interface/lib/provider-panel-api-key-auth.js +92 -0
- package/neural-interface/lib/provider-panel-terminal-auth.js +95 -0
- package/neural-interface/lib/pty-host/core.js +2 -1
- package/neural-interface/lib/pty-host/manager.js +27 -2
- package/neural-interface/lib/remote-policy.js +20 -11
- package/neural-interface/lib/session-title-generator.js +4 -3
- package/neural-interface/lib/system-about.js +340 -0
- package/neural-interface/lib/system-activity.js +66 -0
- package/neural-interface/lib/terminal-env.js +11 -3
- package/neural-interface/lib/terminal-path.js +55 -0
- package/neural-interface/lib/virtual-socket.js +12 -1
- package/neural-interface/lib/whatsapp/baileys-adapter.js +165 -45
- package/neural-interface/lib/whatsapp/bridge.js +78 -34
- package/neural-interface/lib/whatsapp/commands.js +13 -14
- package/neural-interface/lib/whatsapp/config.js +134 -20
- package/neural-interface/lib/whatsapp/fake-baileys.js +99 -14
- package/neural-interface/lib/whatsapp/host-core.js +168 -35
- package/neural-interface/lib/whatsapp/inbound.js +5 -3
- package/neural-interface/lib/whatsapp/local-file.js +524 -0
- package/neural-interface/lib/whatsapp/manager.js +92 -32
- package/neural-interface/lib/whatsapp/paths.js +11 -1
- package/neural-interface/lib/whatsapp/protocol.js +65 -5
- package/neural-interface/lib/whatsapp/redact.js +63 -0
- package/neural-interface/lib/whatsapp/service.js +343 -91
- package/neural-interface/lib/whatsapp/transcription.js +463 -0
- package/neural-interface/package-lock.json +2 -2
- package/neural-interface/package.json +1 -1
- package/neural-interface/public/index.html +2 -0
- package/neural-interface/public/index2d.html +2 -0
- package/neural-interface/public/offline.html +16 -1
- package/neural-interface/public/onboarding.html +96 -2
- package/neural-interface/public/shared/account-i18n.js +7 -0
- package/neural-interface/public/shared/account-menu.js +539 -0
- package/neural-interface/public/shared/account-usage.js +19 -0
- package/neural-interface/public/shared/account-view.js +335 -0
- package/neural-interface/public/shared/agent-runtime-options.js +28 -8
- package/neural-interface/public/shared/assistant/asst-accounts.js +182 -184
- package/neural-interface/public/shared/assistant/asst-api.js +32 -2
- package/neural-interface/public/shared/assistant/asst-brain-picker.js +124 -25
- package/neural-interface/public/shared/assistant/asst-budget.js +259 -303
- package/neural-interface/public/shared/assistant/asst-mascot.js +126 -7
- package/neural-interface/public/shared/assistant/asst-menu.js +15 -3
- package/neural-interface/public/shared/assistant/asst-panel.js +48 -14
- package/neural-interface/public/shared/assistant/asst-render.js +38 -7
- package/neural-interface/public/shared/assistant/asst-route.js +72 -14
- package/neural-interface/public/shared/assistant/asst-routes-editor.js +45 -6
- package/neural-interface/public/shared/assistant/asst-slash.js +1 -1
- package/neural-interface/public/shared/assistant/asst-state.js +1 -1
- package/neural-interface/public/shared/assistant/asst-styles.js +99 -17
- package/neural-interface/public/shared/cdx/cdx-commands.js +4 -1
- package/neural-interface/public/shared/cdx/cdx-features.js +22 -14
- package/neural-interface/public/shared/cdx/cdx-icons.js +2 -0
- package/neural-interface/public/shared/cdx/cdx-panel.js +48 -107
- package/neural-interface/public/shared/cdx/cdx-settings.js +231 -0
- package/neural-interface/public/shared/cdx/cdx-styles.js +128 -107
- package/neural-interface/public/shared/cdx/cdx-tabs.js +261 -664
- package/neural-interface/public/shared/cdx/cdx-ws.js +2 -0
- package/neural-interface/public/shared/claude-account-view.js +3 -0
- package/neural-interface/public/shared/cli-install-view.js +392 -0
- package/neural-interface/public/shared/cli-status.js +282 -22
- package/neural-interface/public/shared/cp/cp-events.js +2 -1
- package/neural-interface/public/shared/cp/cp-styles.js +46 -0
- package/neural-interface/public/shared/desktop-bridge.js +39 -0
- package/neural-interface/public/shared/desktop-titlebar-page.js +59 -0
- package/neural-interface/public/shared/desktop-titlebar-view.js +122 -0
- package/neural-interface/public/shared/desktop-titlebar.js +153 -0
- package/neural-interface/public/shared/desktop-update-view.js +462 -0
- package/neural-interface/public/shared/editor/editor-panel.js +1 -1
- package/neural-interface/public/shared/explorer/fx-main.js +1 -1
- package/neural-interface/public/shared/git-bash-view.js +145 -0
- package/neural-interface/public/shared/html-shell.js +1 -0
- package/neural-interface/public/shared/i18n.js +19 -1
- package/neural-interface/public/shared/install-details-view.js +86 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-panel.js +32 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-send.js +17 -0
- package/neural-interface/public/shared/ocp-v2/ocp-v2-styles.js +118 -0
- package/neural-interface/public/shared/pwa-install-page.js +3 -1
- package/neural-interface/public/shared/settings/settings-about-pane.js +271 -0
- package/neural-interface/public/shared/settings/settings-about.js +254 -0
- package/neural-interface/public/shared/settings/settings-ia.js +15 -0
- package/neural-interface/public/shared/showcase-privacy.js +489 -0
- package/neural-interface/public/shared/storage.js +30 -3
- package/neural-interface/public/shared/styles.css +278 -31
- package/neural-interface/public/shared/synabun-mascot.js +48 -2
- package/neural-interface/public/shared/ui-claude-panel.js +212 -213
- package/neural-interface/public/shared/ui-cli-banner.js +355 -0
- package/neural-interface/public/shared/ui-git-bash.js +124 -0
- package/neural-interface/public/shared/ui-judgments.js +10 -1
- package/neural-interface/public/shared/ui-loading.js +30 -6
- package/neural-interface/public/shared/ui-menubar.js +13 -3
- package/neural-interface/public/shared/ui-navbar.js +3 -1
- package/neural-interface/public/shared/ui-provider-auth.js +104 -0
- package/neural-interface/public/shared/ui-provider-terminal-auth.js +223 -0
- package/neural-interface/public/shared/ui-sessions.js +9 -3
- package/neural-interface/public/shared/ui-settings.js +55 -3
- package/neural-interface/public/shared/ui-sidepanel-sessions.js +3 -1
- package/neural-interface/public/shared/ui-sync.js +6 -0
- package/neural-interface/public/shared/ui-terminal.js +17 -0
- package/neural-interface/public/shared/ui-tool-updates.js +5 -0
- package/neural-interface/public/shared/ui-update.js +594 -5
- package/neural-interface/public/shared/ui-whatsapp.js +21 -6
- package/neural-interface/public/shared/whatsapp/wa-view.js +51 -8
- package/neural-interface/public/shared/worker-end.js +2 -0
- package/neural-interface/public/sw.js +1 -1
- package/neural-interface/public/variant/2d/main.js +10 -1
- package/neural-interface/public/variant/3d/main.js +10 -1
- package/neural-interface/server.js +1219 -608
- package/package.json +4 -1
- package/setup.js +9 -8
|
@@ -1,21 +1,27 @@
|
|
|
1
1
|
// ═══════════════════════════════════════════
|
|
2
2
|
// SynaBun Assistant — account profiles (Claude + Codex)
|
|
3
3
|
// ═══════════════════════════════════════════
|
|
4
|
-
//
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// One manager for both providers, from the same server state as the side
|
|
5
|
+
// panels' header account menus (lib/claude-accounts.js, lib/codex-accounts.js
|
|
6
|
+
// describe()): every account with what it runs on and who it is, its "Uses"
|
|
7
|
+
// switch when it holds both credentials, each credential's sign-in or sign-out,
|
|
8
|
+
// an API key pasted into it, the worker choice, rename and remove. Adding an
|
|
9
|
+
// account makes it at once; its row then offers the two ways to sign it in:
|
|
10
|
+
// the provider's own login in a SynaBun terminal (`claude auth login` /
|
|
11
|
+
// `codex login` under the account's folder), or an API key.
|
|
8
12
|
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
13
|
+
import { on } from '../state.js';
|
|
14
|
+
import {
|
|
15
|
+
fetchClaudeAccounts, fetchCodexAccounts, getCachedClaudeAccounts, getCachedCodexAccounts, getClaudeWorkerAccountId, getCodexWorkerAccountId,
|
|
16
|
+
} from '../agent-runtime-options.js';
|
|
11
17
|
import { getProviderMeta } from '../provider-icons.js';
|
|
12
18
|
import {
|
|
13
|
-
createClaudeAccount, deleteClaudeAccount, loginClaudeAccount, patchClaudeAccount,
|
|
14
|
-
deleteCodexAccount, patchCodexAccount,
|
|
19
|
+
createClaudeAccount, deleteClaudeAccount, loginClaudeAccount, patchClaudeAccount, setClaudeWorkerAccount, signOutClaudeAccount,
|
|
20
|
+
createCodexAccount, deleteCodexAccount, loginCodexAccount, patchCodexAccount, setCodexWorkerAccount, signOutCodexAccount,
|
|
15
21
|
} from './asst-api.js';
|
|
22
|
+
import { accountBadge, accountIdentity, accountName, accountText, accountUsable, apiKeyErrorText, credentialRows, modeChoices } from '../account-view.js';
|
|
23
|
+
import { providerApiKeyRequest } from '../ui-provider-terminal-auth.js';
|
|
16
24
|
|
|
17
|
-
const LOGIN_TIMEOUT_MS = 10 * 60 * 1000;
|
|
18
|
-
const CODEX_POLL_MS = 3000;
|
|
19
25
|
const ICON_X = '<svg viewBox="0 0 24 24"><line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/></svg>';
|
|
20
26
|
|
|
21
27
|
function el(tag, className, text) {
|
|
@@ -36,84 +42,44 @@ function tf(t) {
|
|
|
36
42
|
};
|
|
37
43
|
}
|
|
38
44
|
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
if (msg?.provider && msg.provider !== provider) return;
|
|
54
|
-
done = true;
|
|
55
|
-
off();
|
|
56
|
-
clearTimeout(timer);
|
|
57
|
-
resolve(true);
|
|
58
|
-
});
|
|
59
|
-
const timer = setTimeout(() => { if (!done) { done = true; off(); resolve(false); } }, timeoutMs);
|
|
60
|
-
});
|
|
61
|
-
}
|
|
45
|
+
// What each provider's account calls on the server (assistant API + the panels' owner-guarded routes).
|
|
46
|
+
const PROVIDER_API = {
|
|
47
|
+
'claude-code': {
|
|
48
|
+
view: 'claude', list: getCachedClaudeAccounts, refresh: () => fetchClaudeAccounts(true), worker: getClaudeWorkerAccountId,
|
|
49
|
+
create: createClaudeAccount, login: loginClaudeAccount, patch: patchClaudeAccount, remove: deleteClaudeAccount,
|
|
50
|
+
setWorker: setClaudeWorkerAccount, signOut: signOutClaudeAccount, keyProvider: 'claude', changed: 'sync:claude:accounts-changed',
|
|
51
|
+
},
|
|
52
|
+
codex: {
|
|
53
|
+
view: 'codex', list: getCachedCodexAccounts, refresh: () => fetchCodexAccounts(true), worker: getCodexWorkerAccountId,
|
|
54
|
+
create: createCodexAccount, login: loginCodexAccount, patch: patchCodexAccount, remove: deleteCodexAccount,
|
|
55
|
+
setWorker: setCodexWorkerAccount, signOut: signOutCodexAccount, keyProvider: 'codex', changed: 'sync:codex:accounts-changed',
|
|
56
|
+
},
|
|
57
|
+
};
|
|
58
|
+
const apiFor = (provider) => PROVIDER_API[provider === 'codex' ? 'codex' : 'claude-code'];
|
|
62
59
|
|
|
63
60
|
/**
|
|
64
|
-
* Add-account flow
|
|
65
|
-
*
|
|
61
|
+
* Add-account flow: the account is made at once; how it signs in (the provider's own login, or an API key)
|
|
62
|
+
* is chosen on its row next. Returns { ok, choose: true, account }.
|
|
66
63
|
*/
|
|
67
64
|
export async function startAddAccount(provider, label, ui = {}) {
|
|
68
65
|
const t = tf(ui.t);
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
if (login?.terminalSessionId) {
|
|
77
|
-
emit('terminal:expect-managed');
|
|
78
|
-
emit('terminal:attach-floating', { terminalSessionId: login.terminalSessionId, profile: login.profile || 'claude-code', snapToPanel: true });
|
|
79
|
-
}
|
|
80
|
-
ui.setStatus?.(t('assistant.accounts.waitingLogin', 'Finish the login in the terminal window. Waiting…'));
|
|
81
|
-
const changed = await waitForAccountsChanged('claude-code');
|
|
82
|
-
const accounts = await refreshFor('claude-code');
|
|
83
|
-
const fresh = accounts.find(a => a.id === account.id) || account;
|
|
84
|
-
return { ok: changed || !!fresh?.email, account: fresh, timedOut: !changed };
|
|
85
|
-
}
|
|
86
|
-
if (provider === 'codex') {
|
|
87
|
-
const started = await startCodexAccountAdd(name);
|
|
88
|
-
const accountId = started?.accountId || started?.account?.id;
|
|
89
|
-
const login = started?.login || {};
|
|
90
|
-
ui.showLogin?.({ authUrl: login.authUrl || login.url || '', userCode: login.userCode || login.code || '' });
|
|
91
|
-
ui.setStatus?.(t('assistant.accounts.waitingDevice', 'Complete the sign-in in your browser. Waiting…'));
|
|
92
|
-
const deadline = Date.now() + LOGIN_TIMEOUT_MS;
|
|
93
|
-
let changedEarly = false;
|
|
94
|
-
const offChanged = on('sync:assistant:accounts-changed', (msg) => { if (!msg?.provider || msg.provider === 'codex') changedEarly = true; });
|
|
95
|
-
try {
|
|
96
|
-
while (Date.now() < deadline) {
|
|
97
|
-
if (ui.isCancelled?.()) return { ok: false, cancelled: true };
|
|
98
|
-
const accounts = await fetchCodexAccounts(true).catch(() => []);
|
|
99
|
-
const found = accounts.find(a => a.id === accountId);
|
|
100
|
-
if (found && (found.email || found.loggedIn === true || found.status === 'ready' || changedEarly)) return { ok: true, account: found };
|
|
101
|
-
await new Promise(r => setTimeout(r, CODEX_POLL_MS));
|
|
102
|
-
}
|
|
103
|
-
} finally {
|
|
104
|
-
offChanged();
|
|
105
|
-
}
|
|
106
|
-
return { ok: false, timedOut: true, account: { id: accountId, label: name } };
|
|
107
|
-
}
|
|
108
|
-
throw new Error(`Unsupported provider: ${provider}`);
|
|
66
|
+
const api = apiFor(provider);
|
|
67
|
+
const name = String(label || '').trim();
|
|
68
|
+
const created = await api.create(name || undefined);
|
|
69
|
+
const account = created?.account || created;
|
|
70
|
+
if (!account?.id) throw new Error(t('assistant.accounts.createFailed', 'Account could not be created'));
|
|
71
|
+
const accounts = await api.refresh();
|
|
72
|
+
return { ok: true, choose: true, account: accounts.find((a) => a.id === account.id) || account };
|
|
109
73
|
}
|
|
110
74
|
|
|
111
75
|
/**
|
|
112
76
|
* Accounts manager modal. hooks: { t, onChanged(provider), onSelect(accountId) }
|
|
113
|
-
* Returns { el, close }.
|
|
77
|
+
* Returns { el, close, renderList, openAdd }.
|
|
114
78
|
*/
|
|
115
79
|
export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChanged, onSelect } = {}) {
|
|
116
80
|
const t = tf(tRaw);
|
|
81
|
+
const api = apiFor(provider);
|
|
82
|
+
const p = api.view;
|
|
117
83
|
const meta = getProviderMeta(provider);
|
|
118
84
|
const overlay = el('div', 'asst-modal-overlay');
|
|
119
85
|
overlay.setAttribute('role', 'dialog');
|
|
@@ -124,8 +90,8 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
|
|
|
124
90
|
<div class="asst-modal-head"><span class="asst-icon" style="color:${esc(meta.color)}">${meta.icon}</span><span>${esc(t('assistant.accounts.title', '{provider} accounts', { provider: meta.label }))}</span><button type="button" class="asst-iconbtn asst-modal-close" aria-label="${esc(t('common.close', 'Close'))}">${ICON_X}</button></div>
|
|
125
91
|
<div class="asst-modal-body">
|
|
126
92
|
<div class="asst-modal-note">${esc(provider === 'codex'
|
|
127
|
-
? t('assistant.accounts.
|
|
128
|
-
: t('assistant.accounts.
|
|
93
|
+
? t('assistant.accounts.noteCodex2', 'Each account has its own CODEX_HOME (sign-in, sessions) and runs on its ChatGPT subscription or its API key. "Default" is your ambient ~/.codex.')
|
|
94
|
+
: t('assistant.accounts.noteClaude2', 'Each account has its own CLAUDE_CONFIG_DIR (settings, sign-in, sessions) and runs on its Claude subscription or its API key. "Default" is your ambient ~/.claude.'))}</div>
|
|
129
95
|
<div class="asst-account-list"></div>
|
|
130
96
|
<div class="asst-account-add"></div>
|
|
131
97
|
</div>
|
|
@@ -140,12 +106,12 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
|
|
|
140
106
|
|
|
141
107
|
const list = modal.querySelector('.asst-account-list');
|
|
142
108
|
const addBox = modal.querySelector('.asst-account-add');
|
|
143
|
-
let cancelled = false;
|
|
144
109
|
let busy = false;
|
|
110
|
+
let offChanged = null;
|
|
145
111
|
|
|
146
112
|
function close() {
|
|
147
|
-
cancelled = true;
|
|
148
113
|
document.removeEventListener('keydown', onKey, true);
|
|
114
|
+
offChanged?.();
|
|
149
115
|
overlay.remove();
|
|
150
116
|
}
|
|
151
117
|
function onKey(e) {
|
|
@@ -157,94 +123,138 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
|
|
|
157
123
|
modal.querySelector('.asst-modal-close').addEventListener('click', close);
|
|
158
124
|
modal.querySelector('.asst-account-done').addEventListener('click', close);
|
|
159
125
|
|
|
126
|
+
// Which account is fresh (just added: its row offers the two ways to sign in), which row has its API-key
|
|
127
|
+
// form open, and the last thing a row said.
|
|
128
|
+
const ui = { fresh: '', keyOpen: '', notice: null };
|
|
129
|
+
async function openSignIn(acc) {
|
|
130
|
+
const res = await api.login(acc.id);
|
|
131
|
+
const sessionId = res?.login?.terminalSessionId || res?.terminalSessionId;
|
|
132
|
+
if (sessionId) {
|
|
133
|
+
const { openProviderLoginTerminal } = await import('../ui-terminal.js');
|
|
134
|
+
await openProviderLoginTerminal(sessionId, `${p === 'codex' ? 'Codex' : 'Claude'} sign-in · ${accountName(acc, p)}`);
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
function notice(id, text) { ui.notice = text ? { id, text } : null; renderList(); }
|
|
138
|
+
async function act(acc, work, done = '') {
|
|
139
|
+
try {
|
|
140
|
+
await work();
|
|
141
|
+
ui.notice = done ? { id: acc.id, text: done } : null;
|
|
142
|
+
await api.refresh();
|
|
143
|
+
onChanged?.(provider);
|
|
144
|
+
} catch (err) { ui.notice = { id: acc.id, text: err?.message || String(err) }; }
|
|
145
|
+
if (overlay.isConnected) renderList();
|
|
146
|
+
}
|
|
147
|
+
function button(row, text, onClick, kind = 'secondary') {
|
|
148
|
+
const b = el('button', `asst-btn asst-btn-${kind}`, text);
|
|
149
|
+
b.type = 'button';
|
|
150
|
+
b.addEventListener('click', async () => { b.disabled = true; try { await onClick(); } finally { b.disabled = false; } });
|
|
151
|
+
row.appendChild(b);
|
|
152
|
+
return b;
|
|
153
|
+
}
|
|
154
|
+
function renderActions(acc, actionsRow, row) {
|
|
155
|
+
const worker = api.worker() === acc.id;
|
|
156
|
+
const label = accountName(acc, p);
|
|
157
|
+
if (onSelect) {
|
|
158
|
+
const use = button(actionsRow, t('assistant.accounts.useBrain', 'Use for the brain'), async () => { onSelect(acc.id); close(); });
|
|
159
|
+
use.disabled = !accountUsable(acc);
|
|
160
|
+
}
|
|
161
|
+
if (!worker) {
|
|
162
|
+
const workersSet = provider === 'codex'
|
|
163
|
+
? t('assistant.accounts.codexWorkersSet', 'Codex workers now use {label} when a dispatch names no account.', { label })
|
|
164
|
+
: t('assistant.accounts.workersSet', 'Claude Code workers now use {label} when a dispatch names no account.', { label });
|
|
165
|
+
const w = button(actionsRow, t('assistant.accounts.useWorkers', 'Use for workers'), () => act(acc, () => api.setWorker(acc.id), workersSet));
|
|
166
|
+
w.disabled = !accountUsable(acc);
|
|
167
|
+
}
|
|
168
|
+
for (const m of modeChoices(acc, p)) {
|
|
169
|
+
if (m.current) continue;
|
|
170
|
+
button(actionsRow, `${accountText('uses', {}, p)}: ${m.label}`, () => act(acc, () => api.patch(acc.id, { mode: m.mode }),
|
|
171
|
+
accountText(m.mode === 'apiKey' ? 'modeSetApiKey' : 'modeSetSubscription', { label }, p)));
|
|
172
|
+
}
|
|
173
|
+
for (const c of credentialRows(acc, p)) {
|
|
174
|
+
if (c.action === 'signIn') button(actionsRow, c.actionText, () => act(acc, () => openSignIn(acc), accountText('signInPending', {}, p)), ui.fresh === acc.id ? 'primary' : 'secondary');
|
|
175
|
+
if (c.action === 'addKey') button(actionsRow, c.actionText, async () => { ui.keyOpen = acc.id; ui.notice = null; renderList(); });
|
|
176
|
+
if (c.action === 'signOut') button(actionsRow, `${c.actionText} · ${c.name}`, async () => {
|
|
177
|
+
if (!window.confirm(accountText('confirmSignOut', { label }, p))) return;
|
|
178
|
+
await act(acc, () => api.signOut(acc.id, 'subscription'), accountText('signedOutNote', { label }, p));
|
|
179
|
+
});
|
|
180
|
+
if (c.action === 'removeKey') button(actionsRow, c.actionText, async () => {
|
|
181
|
+
if (!window.confirm(accountText('confirmRemoveKey', { label }, p))) return;
|
|
182
|
+
await act(acc, () => api.signOut(acc.id, 'apiKey'), accountText('keyRemovedNote', { label }, p));
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
if (ui.keyOpen === acc.id) {
|
|
186
|
+
const form = el('form', 'asst-account-form');
|
|
187
|
+
const input = document.createElement('input');
|
|
188
|
+
input.type = 'password'; input.autocomplete = 'off'; input.spellcheck = false; input.required = true;
|
|
189
|
+
input.className = 'asst-dd-input'; input.placeholder = accountText('keyPlaceholder', {}, p);
|
|
190
|
+
input.setAttribute('aria-label', accountText('keyLabel', { label }, p));
|
|
191
|
+
const save = el('button', 'asst-btn asst-btn-primary', accountText('save', {}, p)); save.type = 'submit';
|
|
192
|
+
const cancel = el('button', 'asst-btn asst-btn-secondary', accountText('cancel', {}, p)); cancel.type = 'button';
|
|
193
|
+
cancel.addEventListener('click', () => { input.value = ''; ui.keyOpen = ''; renderList(); });
|
|
194
|
+
input.addEventListener('keydown', (e) => e.stopPropagation());
|
|
195
|
+
form.addEventListener('submit', async (e) => {
|
|
196
|
+
e.preventDefault();
|
|
197
|
+
let key = input.value; input.value = '';
|
|
198
|
+
if (!key) return;
|
|
199
|
+
save.disabled = cancel.disabled = input.disabled = true;
|
|
200
|
+
notice(acc.id, accountText('checkingKey', {}, p));
|
|
201
|
+
try {
|
|
202
|
+
await providerApiKeyRequest(api.keyProvider, acc.id, key);
|
|
203
|
+
ui.keyOpen = ''; ui.fresh = '';
|
|
204
|
+
ui.notice = { id: acc.id, text: accountText('keySavedNote', { label }, p) };
|
|
205
|
+
await api.refresh();
|
|
206
|
+
onChanged?.(provider);
|
|
207
|
+
} catch (err) { ui.notice = { id: acc.id, text: apiKeyErrorText(p, err?.code) }; }
|
|
208
|
+
finally { key = null; }
|
|
209
|
+
if (overlay.isConnected) renderList();
|
|
210
|
+
});
|
|
211
|
+
form.append(input, save, cancel);
|
|
212
|
+
row.appendChild(form);
|
|
213
|
+
setTimeout(() => input.focus(), 0);
|
|
214
|
+
}
|
|
215
|
+
if (ui.notice?.id === acc.id) row.appendChild(el('div', 'asst-account-msg', ui.notice.text));
|
|
216
|
+
}
|
|
217
|
+
|
|
160
218
|
function renderList() {
|
|
161
|
-
const accounts =
|
|
219
|
+
const accounts = api.list();
|
|
162
220
|
list.innerHTML = '';
|
|
163
221
|
if (!accounts.length) { list.appendChild(el('div', 'asst-modal-note', t('assistant.accounts.empty', 'No accounts yet.'))); return; }
|
|
164
222
|
for (const acc of accounts) {
|
|
165
|
-
const row = el('div',
|
|
223
|
+
const row = el('div', `asst-account-row ${p}`);
|
|
166
224
|
row.dataset.id = acc.id;
|
|
167
225
|
const main = el('div', 'asst-account-main');
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
226
|
+
const head = el('div', 'asst-account-head');
|
|
227
|
+
head.appendChild(el('span', 'asst-account-label', accountName(acc, p)));
|
|
228
|
+
const badge = accountBadge(acc, p);
|
|
229
|
+
const chip = el('span', 'asst-account-badge', badge.text);
|
|
230
|
+
chip.dataset.tone = badge.tone;
|
|
231
|
+
head.appendChild(chip);
|
|
232
|
+
main.appendChild(head);
|
|
233
|
+
const worker = api.worker() === acc.id;
|
|
234
|
+
const sub = [accountIdentity(acc) || (acc.signedIn === false ? accountText('notSignedIn', {}, p) : accountText('checking', {}, p)), worker ? t('assistant.accounts.workerTag', 'workers use it') : ''].filter(Boolean).join(' · ');
|
|
235
|
+
main.appendChild(el('div', 'asst-account-sub', sub));
|
|
236
|
+
const creds = el('div', 'asst-account-creds');
|
|
237
|
+
for (const c of credentialRows(acc, p)) {
|
|
238
|
+
const line = el('div', 'asst-account-cred');
|
|
239
|
+
line.appendChild(el('span', 'asst-account-cred-k', c.name));
|
|
240
|
+
line.appendChild(el('span', '', `${c.text}${c.inUse ? ` · ${accountText('inUse', {}, p)}` : ''}`));
|
|
241
|
+
creds.appendChild(line);
|
|
178
242
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
try {
|
|
185
|
-
const res = await loginClaudeAccount(acc.id);
|
|
186
|
-
if (res?.terminalSessionId) {
|
|
187
|
-
emit('terminal:expect-managed');
|
|
188
|
-
emit('terminal:attach-floating', { terminalSessionId: res.terminalSessionId, profile: res.profile || 'claude-code', snapToPanel: true });
|
|
189
|
-
}
|
|
190
|
-
await waitForAccountsChanged('claude-code');
|
|
191
|
-
await refreshFor(provider);
|
|
192
|
-
onChanged?.(provider);
|
|
193
|
-
renderList();
|
|
194
|
-
} catch (err) {
|
|
195
|
-
addBox.textContent = err?.message || String(err);
|
|
196
|
-
} finally { login.disabled = false; }
|
|
197
|
-
});
|
|
198
|
-
row.appendChild(login);
|
|
199
|
-
}
|
|
200
|
-
const rename = el('button', 'asst-btn asst-btn-secondary', t('common.rename', 'Rename'));
|
|
201
|
-
rename.type = 'button';
|
|
202
|
-
rename.addEventListener('click', () => {
|
|
203
|
-
const input = document.createElement('input');
|
|
204
|
-
input.type = 'text';
|
|
205
|
-
input.className = 'asst-dd-input';
|
|
206
|
-
input.value = acc.label || '';
|
|
207
|
-
main.replaceWith(input);
|
|
208
|
-
input.focus();
|
|
209
|
-
input.select();
|
|
210
|
-
const commit = async () => {
|
|
211
|
-
const value = input.value.trim();
|
|
212
|
-
if (value && value !== acc.label) {
|
|
213
|
-
try {
|
|
214
|
-
if (provider === 'codex') await patchCodexAccount(acc.id, { label: value });
|
|
215
|
-
else await patchClaudeAccount(acc.id, { label: value });
|
|
216
|
-
await refreshFor(provider);
|
|
217
|
-
onChanged?.(provider);
|
|
218
|
-
} catch (err) { addBox.textContent = err?.message || String(err); }
|
|
219
|
-
}
|
|
220
|
-
renderList();
|
|
221
|
-
};
|
|
222
|
-
input.addEventListener('blur', commit, { once: true });
|
|
223
|
-
input.addEventListener('keydown', (e) => {
|
|
224
|
-
e.stopPropagation();
|
|
225
|
-
if (e.key === 'Enter') { e.preventDefault(); input.blur(); }
|
|
226
|
-
if (e.key === 'Escape') { input.value = acc.label || ''; input.blur(); }
|
|
227
|
-
});
|
|
228
|
-
});
|
|
229
|
-
row.appendChild(rename);
|
|
243
|
+
main.appendChild(creds);
|
|
244
|
+
row.appendChild(main);
|
|
245
|
+
const actions = el('div', 'asst-account-actions');
|
|
246
|
+
row.appendChild(actions);
|
|
247
|
+
renderActions(acc, actions, row);
|
|
230
248
|
if (acc.id !== 'default' && !acc.isDefault) {
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
remove.disabled = true;
|
|
236
|
-
try {
|
|
237
|
-
if (provider === 'codex') await deleteCodexAccount(acc.id);
|
|
238
|
-
else await deleteClaudeAccount(acc.id);
|
|
239
|
-
await refreshFor(provider);
|
|
240
|
-
onChanged?.(provider);
|
|
241
|
-
renderList();
|
|
242
|
-
} catch (err) {
|
|
243
|
-
addBox.textContent = err?.status === 409 ? t('assistant.accounts.inUseError', 'That account is in use by a running session.') : (err?.message || String(err));
|
|
244
|
-
remove.disabled = false;
|
|
245
|
-
}
|
|
249
|
+
button(actions, t('common.rename', 'Rename'), async () => {
|
|
250
|
+
const value = window.prompt(t('assistant.accounts.renamePrompt', 'Name for {label}', { label: accountName(acc, p) }), acc.label || '');
|
|
251
|
+
if (!value || !value.trim() || value.trim() === acc.label) return;
|
|
252
|
+
await act(acc, () => api.patch(acc.id, { label: value.trim() }));
|
|
246
253
|
});
|
|
247
|
-
|
|
254
|
+
button(actions, t('common.remove', 'Remove'), async () => {
|
|
255
|
+
if (!window.confirm(accountText('confirmRemove', { label: accountName(acc, p) }, p))) return;
|
|
256
|
+
await act(acc, () => api.remove(acc.id));
|
|
257
|
+
}, 'danger');
|
|
248
258
|
}
|
|
249
259
|
list.appendChild(row);
|
|
250
260
|
}
|
|
@@ -260,46 +270,29 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
|
|
|
260
270
|
input.placeholder = t('assistant.accounts.labelPlaceholder', 'Label (e.g. Work)');
|
|
261
271
|
input.setAttribute('aria-label', input.placeholder);
|
|
262
272
|
const actions = el('div', 'asst-control-actions');
|
|
263
|
-
const go = el('button', 'asst-btn asst-btn-primary',
|
|
273
|
+
const go = el('button', 'asst-btn asst-btn-primary', t('assistant.accounts.create', 'Add account'));
|
|
264
274
|
go.type = 'button';
|
|
265
275
|
const cancel = el('button', 'asst-btn asst-btn-secondary', t('common.cancel', 'Cancel'));
|
|
266
276
|
cancel.type = 'button';
|
|
267
277
|
const status = el('div', 'asst-modal-note');
|
|
268
|
-
const loginInfo = el('div', 'asst-login-box');
|
|
269
|
-
loginInfo.hidden = true;
|
|
270
278
|
actions.append(go, cancel);
|
|
271
|
-
form.append(input, actions, status
|
|
279
|
+
form.append(input, actions, status);
|
|
272
280
|
addBox.appendChild(form);
|
|
273
281
|
input.focus();
|
|
274
282
|
input.addEventListener('keydown', (e) => { e.stopPropagation(); if (e.key === 'Enter') go.click(); });
|
|
275
|
-
cancel.addEventListener('click', () => {
|
|
283
|
+
cancel.addEventListener('click', () => { addBox.innerHTML = ''; });
|
|
276
284
|
go.addEventListener('click', async () => {
|
|
277
285
|
if (busy) return;
|
|
278
286
|
busy = true;
|
|
279
|
-
cancelled = false;
|
|
280
287
|
go.disabled = true;
|
|
281
288
|
input.disabled = true;
|
|
282
289
|
try {
|
|
283
|
-
const result = await startAddAccount(provider, input.value, {
|
|
284
|
-
t: tRaw,
|
|
285
|
-
setStatus: (text) => { status.textContent = text; },
|
|
286
|
-
isCancelled: () => cancelled,
|
|
287
|
-
showLogin: ({ authUrl, userCode }) => {
|
|
288
|
-
loginInfo.hidden = false;
|
|
289
|
-
loginInfo.innerHTML = `${authUrl ? `<a class="asst-btn asst-btn-primary" href="${esc(authUrl)}" target="_blank" rel="noopener">${esc(t('assistant.accounts.openLogin', 'Open sign-in page'))}</a>` : ''}${userCode ? `<div>${esc(t('assistant.accounts.enterCode', 'Enter this code:'))} <span class="asst-login-code">${esc(userCode)}</span></div>` : ''}`;
|
|
290
|
-
},
|
|
291
|
-
});
|
|
292
|
-
await refreshFor(provider);
|
|
290
|
+
const result = await startAddAccount(provider, input.value, { t: tRaw });
|
|
293
291
|
onChanged?.(provider);
|
|
292
|
+
ui.fresh = result.account.id;
|
|
293
|
+
ui.notice = { id: result.account.id, text: accountText('freshPrompt', { label: accountName(result.account, p) }, p) };
|
|
294
|
+
addBox.innerHTML = '';
|
|
294
295
|
renderList();
|
|
295
|
-
if (result.ok) {
|
|
296
|
-
addBox.innerHTML = '';
|
|
297
|
-
if (onSelect && result.account?.id) onSelect(result.account.id);
|
|
298
|
-
} else if (result.cancelled) {
|
|
299
|
-
addBox.innerHTML = '';
|
|
300
|
-
} else {
|
|
301
|
-
status.textContent = t('assistant.accounts.loginTimeout', 'Login was not confirmed. The account was created — use "Log in" to retry.');
|
|
302
|
-
}
|
|
303
296
|
} catch (err) {
|
|
304
297
|
status.textContent = err?.message || String(err);
|
|
305
298
|
} finally {
|
|
@@ -312,7 +305,12 @@ export function openAccountsManager({ provider = 'claude-code', t: tRaw, onChang
|
|
|
312
305
|
|
|
313
306
|
modal.querySelector('.asst-account-add-btn').addEventListener('click', renderAddForm);
|
|
314
307
|
renderList();
|
|
315
|
-
|
|
308
|
+
api.refresh().then(() => { if (overlay.isConnected) renderList(); }).catch(() => {});
|
|
309
|
+
// Another window or surface changed an account (signed in, a key, its mode): the list follows.
|
|
310
|
+
offChanged = on(api.changed, () => {
|
|
311
|
+
if (!overlay.isConnected) { offChanged?.(); return; }
|
|
312
|
+
api.refresh().then(() => { if (overlay.isConnected && !ui.keyOpen) renderList(); }).catch(() => {});
|
|
313
|
+
});
|
|
316
314
|
|
|
317
315
|
return { el: overlay, close, renderList, openAdd: renderAddForm };
|
|
318
316
|
}
|
|
@@ -75,9 +75,9 @@ export function putRouting(patch, version) {
|
|
|
75
75
|
return jsonFetch('/api/assistant/routing', jsonBody({ version, routing: patch || {} }, 'PUT'));
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
// ── Budget (
|
|
78
|
+
// ── Budget (one saved per-session amount) ─────────────────────
|
|
79
79
|
|
|
80
|
-
/** → { ok, version, budget, defaults,
|
|
80
|
+
/** → { ok, version, budget, defaults, bounds, session|null, pricing, enforcement } */
|
|
81
81
|
export function getBudget(sessionId = null) {
|
|
82
82
|
return jsonFetch(`/api/assistant/budget${sessionId ? `?sessionId=${enc(sessionId)}` : ''}`);
|
|
83
83
|
}
|
|
@@ -255,8 +255,23 @@ export function loginClaudeAccount(id) {
|
|
|
255
255
|
return jsonFetch(`/api/assistant/claude/accounts/${enc(id)}/login`, jsonBody({}));
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
+
/** The account a Claude Code worker uses when its dispatch names none ('default' or null = Default). */
|
|
259
|
+
export function setClaudeWorkerAccount(accountId) {
|
|
260
|
+
return jsonFetch('/api/assistant/claude/worker-account', jsonBody({ accountId: accountId || null }, 'PUT'));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/** Remove one of an account's credentials: 'subscription' (Claude Code's own sign-out) or 'apiKey'. */
|
|
264
|
+
export function signOutClaudeAccount(id, credential) {
|
|
265
|
+
return jsonFetch(`/api/claude/accounts/${enc(id)}/auth/logout`, jsonBody({ credential }));
|
|
266
|
+
}
|
|
267
|
+
|
|
258
268
|
// ── Codex accounts ───────────────────────────
|
|
259
269
|
|
|
270
|
+
export function createCodexAccount(label) {
|
|
271
|
+
return jsonFetch('/api/assistant/codex/accounts', jsonBody({ label }));
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
/** Older callers: create the account and open its ChatGPT sign-in at once. */
|
|
260
275
|
export function startCodexAccountAdd(label) {
|
|
261
276
|
return jsonFetch('/api/assistant/codex/accounts/add-start', jsonBody({ label }));
|
|
262
277
|
}
|
|
@@ -268,3 +283,18 @@ export function patchCodexAccount(id, patch) {
|
|
|
268
283
|
export function deleteCodexAccount(id) {
|
|
269
284
|
return jsonFetch(`/api/assistant/codex/accounts/${enc(id)}`, { method: 'DELETE' });
|
|
270
285
|
}
|
|
286
|
+
|
|
287
|
+
/** `codex login` under the account's CODEX_HOME, in a SynaBun terminal. */
|
|
288
|
+
export function loginCodexAccount(id) {
|
|
289
|
+
return jsonFetch(`/api/assistant/codex/accounts/${enc(id)}/login`, jsonBody({}));
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
/** The account a Codex worker uses when its dispatch names none ('default' or null = Default). */
|
|
293
|
+
export function setCodexWorkerAccount(accountId) {
|
|
294
|
+
return jsonFetch('/api/assistant/codex/worker-account', jsonBody({ accountId: accountId || null }, 'PUT'));
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/** Remove one of an account's credentials: 'subscription' (Codex's own sign-out) or 'apiKey'. */
|
|
298
|
+
export function signOutCodexAccount(id, credential) {
|
|
299
|
+
return jsonFetch(`/api/codex/accounts/${enc(id)}/auth/logout`, jsonBody({ credential }));
|
|
300
|
+
}
|