@adecore/agents-react 0.30.0 → 0.31.1
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/dist/agents/AgentIcon.js +4 -3
- package/dist/agents/accounts.d.ts +2 -0
- package/dist/agents/accounts.js +6 -0
- package/dist/agents/agent-marks.d.ts +8 -0
- package/dist/agents/agent-marks.js +12 -0
- package/dist/agents/provider-paths.js +3 -2
- package/dist/host.d.ts +4 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/locales/en/agent-providers.d.ts +40 -0
- package/dist/locales/en/agent-providers.js +42 -2
- package/dist/locales/nl/agent-providers.d.ts +40 -0
- package/dist/locales/nl/agent-providers.js +42 -2
- package/dist/providers/AccountDetail.d.ts +4 -3
- package/dist/providers/AccountDetail.js +6 -5
- package/dist/providers/AddAccountForm.d.ts +3 -2
- package/dist/providers/AddAccountForm.js +2 -2
- package/dist/providers/CliDetail.d.ts +3 -3
- package/dist/providers/CliDetail.js +3 -3
- package/dist/providers/InstallPage.d.ts +9 -0
- package/dist/providers/InstallPage.js +74 -0
- package/dist/providers/ProvidersPane.d.ts +3 -1
- package/dist/providers/ProvidersPane.js +25 -14
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/install-steps.d.ts +14 -0
- package/dist/providers/install-steps.js +19 -0
- package/dist/providers/parts.js +2 -1
- package/dist/theme.css +3 -0
- package/dist/usage/format.js +6 -2
- package/dist/usage/limit-groups.js +2 -1
- package/package.json +8 -8
- package/src/agents/AgentIcon.tsx +12 -3
- package/src/agents/accounts.ts +13 -0
- package/src/agents/agent-marks.ts +26 -0
- package/src/agents/provider-paths.ts +3 -2
- package/src/host.ts +11 -1
- package/src/index.ts +1 -0
- package/src/locales/en/agent-providers.ts +42 -2
- package/src/locales/nl/agent-providers.ts +42 -2
- package/src/providers/AccountDetail.tsx +34 -26
- package/src/providers/AddAccountForm.tsx +8 -3
- package/src/providers/CliDetail.tsx +5 -5
- package/src/providers/InstallPage.tsx +221 -0
- package/src/providers/ProvidersPane.tsx +36 -19
- package/src/providers/index.ts +1 -0
- package/src/providers/install-steps.ts +35 -0
- package/src/providers/parts.tsx +2 -1
- package/src/theme.css +3 -0
- package/src/usage/format.ts +6 -2
- package/src/usage/limit-groups.ts +2 -1
package/dist/agents/AgentIcon.js
CHANGED
|
@@ -3,18 +3,19 @@ import clsx from 'clsx';
|
|
|
3
3
|
import { Bot } from 'lucide-react';
|
|
4
4
|
import { siClaude, siGithubcopilot, siGooglegemini } from 'simple-icons';
|
|
5
5
|
import { Icon } from '@adecore/ui';
|
|
6
|
+
import { hostAgentMark } from './agent-marks.js';
|
|
6
7
|
import { PROVIDER_PATHS } from './provider-paths.js';
|
|
7
8
|
// simple-icons removed OpenAI's mark at its request, so Codex reuses the usage page's path.
|
|
8
|
-
const
|
|
9
|
+
const BUILT_IN_MARKS = {
|
|
9
10
|
claude: siClaude,
|
|
10
11
|
codex: { title: 'Codex', path: PROVIDER_PATHS.codex },
|
|
11
12
|
gemini: siGooglegemini,
|
|
12
13
|
copilot: siGithubcopilot
|
|
13
14
|
};
|
|
14
15
|
export function AgentIcon({ kind, size = 14, className }) {
|
|
15
|
-
const mark =
|
|
16
|
+
const mark = hostAgentMark(kind) ?? BUILT_IN_MARKS[kind];
|
|
16
17
|
if (!mark) {
|
|
17
18
|
return _jsx(Icon, { icon: Bot, size: size, className: className });
|
|
18
19
|
}
|
|
19
|
-
return (_jsx("svg", { role: "img", "aria-label": mark.title, viewBox:
|
|
20
|
+
return (_jsx("svg", { role: "img", "aria-label": mark.title, viewBox: mark.viewBox ?? '0 0 24 24', width: size, height: size, fill: "currentColor", className: clsx('align-middle', className), children: _jsx("path", { d: mark.path }) }));
|
|
20
21
|
}
|
|
@@ -10,6 +10,8 @@ export interface AccountEntry {
|
|
|
10
10
|
}
|
|
11
11
|
export declare function accountsOfKind(accounts: ProviderAccounts | null, kind: AgentKind): AccountEntry[];
|
|
12
12
|
export declare function accountName(entry: Pick<AccountEntry, 'id' | 'account' | 'isDefault'>, providerName: string): string;
|
|
13
|
+
export type AccountLogin = 'terminal' | 'chat' | null;
|
|
14
|
+
export declare function accountLoginOf(accounts: ProviderAccounts | null | undefined, kind: AgentKind): AccountLogin;
|
|
13
15
|
export type AccountTone = 'muted' | 'needs-you' | 'error';
|
|
14
16
|
export declare const ACCOUNT_TONE_CLASSES: Record<AccountTone, string>;
|
|
15
17
|
export declare function accountStatusLine(status: ProviderAccountStatus | null, canLogIn: boolean): {
|
package/dist/agents/accounts.js
CHANGED
|
@@ -26,6 +26,12 @@ export function accountsOfKind(accounts, kind) {
|
|
|
26
26
|
export function accountName(entry, providerName) {
|
|
27
27
|
return entry.account.label ?? (entry.isDefault ? providerName : entry.id);
|
|
28
28
|
}
|
|
29
|
+
export function accountLoginOf(accounts, kind) {
|
|
30
|
+
if (accounts?.loginCommands?.[kind] !== undefined) {
|
|
31
|
+
return 'terminal';
|
|
32
|
+
}
|
|
33
|
+
return accounts?.chatLogins?.includes(kind) === true ? 'chat' : null;
|
|
34
|
+
}
|
|
29
35
|
export const ACCOUNT_TONE_CLASSES = {
|
|
30
36
|
muted: 'text-text-muted',
|
|
31
37
|
'needs-you': 'text-status-needs-you',
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { AgentKind } from '@adecore/agent-contracts';
|
|
2
|
+
export interface AgentMark {
|
|
3
|
+
title: string;
|
|
4
|
+
path: string;
|
|
5
|
+
viewBox?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function configureAgentMarks(marks: Readonly<Partial<Record<AgentKind, AgentMark>>>): void;
|
|
8
|
+
export declare function hostAgentMark(kind: AgentKind): AgentMark | undefined;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
let hostMarks = {};
|
|
2
|
+
/*
|
|
3
|
+
* The marks of the kinds a host adds, and any it draws differently, set once before the first render. Every
|
|
4
|
+
* place the shared UI draws an agent's mark reads them; a kind with none keeps the built-in mark or the robot.
|
|
5
|
+
* A later call replaces the whole set.
|
|
6
|
+
*/
|
|
7
|
+
export function configureAgentMarks(marks) {
|
|
8
|
+
hostMarks = { ...marks };
|
|
9
|
+
}
|
|
10
|
+
export function hostAgentMark(kind) {
|
|
11
|
+
return hostMarks[kind];
|
|
12
|
+
}
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/*
|
|
2
|
-
* The marks of Anthropic and OpenAI. Lucide has no brand marks, so these are the icon rule's
|
|
2
|
+
* The marks of Anthropic and OpenAI, and a monogram for a provider with no mark of its own. Lucide has no brand marks, so these are the icon rule's
|
|
3
3
|
* exception for provider marks. One path each, in `currentColor`, so a row decides how loud the logo is.
|
|
4
4
|
*/
|
|
5
5
|
export const PROVIDER_PATHS = {
|
|
6
6
|
claude: 'M4.709 15.955l4.72-2.647.079-.23-.08-.128H9.2l-.79-.048-2.698-.073-2.339-.097-2.266-.122-.571-.121L0 11.784l.055-.352.48-.321.686.06 1.52.103 2.278.158 1.652.097 2.449.255h.389l.055-.157-.134-.098-.103-.097-2.358-1.596-2.552-1.688-1.336-.972-.724-.491-.364-.462-.158-1.008.656-.722.881.06.225.061.893.686 1.908 1.476 2.491 1.833.365.304.145-.103.019-.073-.164-.274-1.355-2.446-1.446-2.49-.644-1.032-.17-.619a2.97 2.97 0 01-.104-.729L6.283.134 6.696 0l.996.134.42.364.62 1.414 1.002 2.229 1.555 3.03.456.898.243.832.091.255h.158V9.01l.128-1.706.237-2.095.23-2.695.08-.76.377-.91.747-.492.584.28.48.685-.067.444-.286 1.851-.559 2.903-.364 1.942h.212l.243-.242.985-1.306 1.652-2.064.73-.82.85-.904.547-.431h1.033l.76 1.129-.34 1.166-1.064 1.347-.881 1.142-1.264 1.7-.79 1.36.073.11.188-.02 2.856-.606 1.543-.28 1.841-.315.833.388.091.395-.328.807-1.969.486-2.309.462-3.439.813-.042.03.048.061 1.549.146.662.036h1.622l3.02.225.79.522.474.638-.079.485-1.215.62-1.64-.389-3.829-.91-1.312-.329h-.182v.11l1.093 1.068 2.006 1.81 2.509 2.33.127.578-.322.455-.34-.049-2.205-1.657-.851-.747-1.926-1.62h-.128v.17l.444.649 2.345 3.521.122 1.08-.17.353-.607.212-.668-.122-1.374-1.925-1.415-2.167-1.143-1.943-.14.08-.674 7.254-.316.37-.729.28-.607-.461-.322-.747.322-1.476.389-1.924.315-1.53.286-1.9.17-.632-.012-.042-.14.018-1.434 1.967-2.18 2.945-1.726 1.845-.414.164-.717-.37.067-.662.401-.589 2.388-3.036 1.44-1.882.93-1.086-.006-.158h-.055L4.132 18.56l-1.13.146-.487-.456.061-.746.231-.243 1.914-1.316-.012.01z',
|
|
7
|
-
codex: 'M21.55 10.004a5.416 5.416 0 00-.478-4.501c-1.217-2.09-3.662-3.166-6.05-2.66A5.59 5.59 0 0010.831 1C8.39.995 6.224 2.546 5.473 4.838A5.553 5.553 0 001.76 7.496a5.487 5.487 0 00.691 6.5 5.416 5.416 0 00.477 4.502c1.217 2.09 3.662 3.165 6.05 2.66A5.586 5.586 0 0013.168 23c2.443.006 4.61-1.546 5.361-3.84a5.554 5.554 0 003.715-2.66 5.488 5.488 0 00-.693-6.497v.001zm-8.381 11.558a4.199 4.199 0 01-2.675-.954c.034-.018.093-.05.132-.074l4.44-2.53a.71.71 0 00.364-.623v-6.176l1.877 1.069c.02.01.033.029.036.05v5.115c-.003 2.274-1.87 4.118-4.174 4.123zM4.192 17.78a4.059 4.059 0 01-.498-2.763c.032.019.09.055.131.078l4.44 2.53c.225.13.504.13.73 0l5.42-3.088v2.138a.068.068 0 01-.027.057L9.9 19.288c-1.999 1.136-4.552.46-5.707-1.51h-.001zM3.023 8.216A4.15 4.15 0 015.198 6.41l-.002.151v5.06a.711.711 0 00.364.624l5.42 3.087-1.876 1.07a.067.067 0 01-.063.005l-4.489-2.559c-1.995-1.14-2.679-3.658-1.53-5.63h.001zm15.417 3.54l-5.42-3.088L14.896 7.6a.067.067 0 01.063-.006l4.489 2.557c1.998 1.14 2.683 3.662 1.529 5.633a4.163 4.163 0 01-2.174 1.807V12.38a.71.71 0 00-.363-.623zm1.867-2.773a6.04 6.04 0 00-.132-.078l-4.44-2.53a.731.731 0 00-.729 0l-5.42 3.088V7.325a.068.068 0 01.027-.057L14.1 4.713c2-1.137 4.555-.46 5.707 1.513.487.833.664 1.809.499 2.757h.001zm-11.741 3.81l-1.877-1.068a.065.065 0 01-.036-.051V6.559c.001-2.277 1.873-4.122 4.181-4.12.976 0 1.92.338 2.671.954-.034.018-.092.05-.131.073l-4.44 2.53a.71.71 0 00-.365.623l-.003 6.173v.001zm1.02-2.168L12 9.25l2.414 1.375v2.75L12 14.75l-2.415-1.375v-2.75z'
|
|
7
|
+
codex: 'M21.55 10.004a5.416 5.416 0 00-.478-4.501c-1.217-2.09-3.662-3.166-6.05-2.66A5.59 5.59 0 0010.831 1C8.39.995 6.224 2.546 5.473 4.838A5.553 5.553 0 001.76 7.496a5.487 5.487 0 00.691 6.5 5.416 5.416 0 00.477 4.502c1.217 2.09 3.662 3.165 6.05 2.66A5.586 5.586 0 0013.168 23c2.443.006 4.61-1.546 5.361-3.84a5.554 5.554 0 003.715-2.66 5.488 5.488 0 00-.693-6.497v.001zm-8.381 11.558a4.199 4.199 0 01-2.675-.954c.034-.018.093-.05.132-.074l4.44-2.53a.71.71 0 00.364-.623v-6.176l1.877 1.069c.02.01.033.029.036.05v5.115c-.003 2.274-1.87 4.118-4.174 4.123zM4.192 17.78a4.059 4.059 0 01-.498-2.763c.032.019.09.055.131.078l4.44 2.53c.225.13.504.13.73 0l5.42-3.088v2.138a.068.068 0 01-.027.057L9.9 19.288c-1.999 1.136-4.552.46-5.707-1.51h-.001zM3.023 8.216A4.15 4.15 0 015.198 6.41l-.002.151v5.06a.711.711 0 00.364.624l5.42 3.087-1.876 1.07a.067.067 0 01-.063.005l-4.489-2.559c-1.995-1.14-2.679-3.658-1.53-5.63h.001zm15.417 3.54l-5.42-3.088L14.896 7.6a.067.067 0 01.063-.006l4.489 2.557c1.998 1.14 2.683 3.662 1.529 5.633a4.163 4.163 0 01-2.174 1.807V12.38a.71.71 0 00-.363-.623zm1.867-2.773a6.04 6.04 0 00-.132-.078l-4.44-2.53a.731.731 0 00-.729 0l-5.42 3.088V7.325a.068.068 0 01.027-.057L14.1 4.713c2-1.137 4.555-.46 5.707 1.513.487.833.664 1.809.499 2.757h.001zm-11.741 3.81l-1.877-1.068a.065.065 0 01-.036-.051V6.559c.001-2.277 1.873-4.122 4.181-4.12.976 0 1.92.338 2.671.954-.034.018-.092.05-.131.073l-4.44 2.53a.71.71 0 00-.365.623l-.003 6.173v.001zm1.02-2.168L12 9.25l2.414 1.375v2.75L12 14.75l-2.415-1.375v-2.75z',
|
|
8
|
+
nanogpt: 'M5 20V4h2.6l8.8 11.2V4H19v16h-2.6L7.6 8.8V20z'
|
|
8
9
|
};
|
package/dist/host.d.ts
CHANGED
|
@@ -3,7 +3,7 @@ import type { Extension } from '@codemirror/state';
|
|
|
3
3
|
import type { EditorView } from '@codemirror/view';
|
|
4
4
|
import type { Highlighter, ThemeRegistration } from 'shiki';
|
|
5
5
|
import type { EditorEngine } from '@adecore/editor';
|
|
6
|
-
import type { AgentKind, ChatCheckpointDiff, ChatConfigurePayload, ChatGoalAction, ChatItem, ChatSubagentItem, ChatUiChoicePayload, ChatUiQueryPayload, ChatUiQueryReading, ChatUiLinkPayload, ChatUiLinkReading } from '@adecore/agent-contracts';
|
|
6
|
+
import type { AgentKind, ChatCheckpointDiff, ChatConfigurePayload, ChatGoalAction, ChatItem, ChatSubagentItem, ChatUiChoicePayload, ChatUiQueryPayload, ChatUiQueryReading, ChatUiLinkPayload, ChatUiLinkReading, ProviderPlatform } from '@adecore/agent-contracts';
|
|
7
7
|
import type { TimelineRow } from './chat/logic/timeline.js';
|
|
8
8
|
import type { FindReveal } from './chat/ui/find-reveal.js';
|
|
9
9
|
import type { PromptAction } from './prompts/logic/prompts.js';
|
|
@@ -249,6 +249,9 @@ export interface ChatHost {
|
|
|
249
249
|
}>;
|
|
250
250
|
openLogin: ((scopeId: string, kind: AgentKind, accountId: string, name: string) => Promise<void>) | null;
|
|
251
251
|
useLoginBlocked(scopeId: string): string | null;
|
|
252
|
+
runProviderCommand?(scopeId: string, kind: AgentKind, command: string): void;
|
|
253
|
+
useMachinePlatform?(scopeId: string): ProviderPlatform | null;
|
|
254
|
+
providerKeyNote?(variable: string): string | null;
|
|
252
255
|
useProjectLook(scopeId: string, projectId: string | null): {
|
|
253
256
|
name: string;
|
|
254
257
|
mark: ReactNode;
|
package/dist/index.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ export { type ChatActions, type FileRef, type ShellCodeBlockContext, type ChatPl
|
|
|
2
2
|
export { type ChatScope, ChatScopeContext, useChatScope } from './scope.js';
|
|
3
3
|
export { type ChatRequestMap, type ChatEventMap, type ChatTransportStatus, type ChatTransport, ChatTransportError, errorCode, isConnectionError } from './transport.js';
|
|
4
4
|
export { portTransport, type PortTransport } from './port-transport.js';
|
|
5
|
+
export { configureAgentMarks, type AgentMark } from './agents/agent-marks.js';
|
|
5
6
|
export { configureChatStorage, type ChatStorageRecord, type ChatStorageAdapter, type ChatStorageOptions } from './storage.js';
|
|
6
7
|
export { setLazyPrefetch, onLazyOpenError } from './lazy.js';
|
|
7
8
|
export { type MountedEntry, MountedRegistry } from './mounted-registry.js';
|
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ export { ChatHostProvider, useChatHost } from './host.js';
|
|
|
3
3
|
export { ChatScopeContext, useChatScope } from './scope.js';
|
|
4
4
|
export { ChatTransportError, errorCode, isConnectionError } from './transport.js';
|
|
5
5
|
export { portTransport } from './port-transport.js';
|
|
6
|
+
export { configureAgentMarks } from './agents/agent-marks.js';
|
|
6
7
|
export { configureChatStorage } from './storage.js';
|
|
7
8
|
export { setLazyPrefetch, onLazyOpenError } from './lazy.js';
|
|
8
9
|
export { MountedRegistry } from './mounted-registry.js';
|
|
@@ -22,6 +22,43 @@ declare const _default: {
|
|
|
22
22
|
none: string;
|
|
23
23
|
noAccounts: string;
|
|
24
24
|
};
|
|
25
|
+
install: {
|
|
26
|
+
notInstalled: string;
|
|
27
|
+
steps: string;
|
|
28
|
+
platform: string;
|
|
29
|
+
platforms: {
|
|
30
|
+
darwin: string;
|
|
31
|
+
linux: string;
|
|
32
|
+
win32: string;
|
|
33
|
+
};
|
|
34
|
+
copy: string;
|
|
35
|
+
copied: string;
|
|
36
|
+
run: string;
|
|
37
|
+
guide: string;
|
|
38
|
+
install: {
|
|
39
|
+
title: string;
|
|
40
|
+
none: string;
|
|
41
|
+
done: string;
|
|
42
|
+
doneNoVersion: string;
|
|
43
|
+
};
|
|
44
|
+
signIn: {
|
|
45
|
+
title: string;
|
|
46
|
+
command: string;
|
|
47
|
+
env: string;
|
|
48
|
+
chat: string;
|
|
49
|
+
or: string;
|
|
50
|
+
unknown: string;
|
|
51
|
+
};
|
|
52
|
+
start: {
|
|
53
|
+
title: string;
|
|
54
|
+
description: string;
|
|
55
|
+
};
|
|
56
|
+
footer: {
|
|
57
|
+
missing: string;
|
|
58
|
+
found: string;
|
|
59
|
+
};
|
|
60
|
+
fallback: string;
|
|
61
|
+
};
|
|
25
62
|
abilities: {
|
|
26
63
|
version: string;
|
|
27
64
|
chatAndTerminal: string;
|
|
@@ -66,6 +103,8 @@ declare const _default: {
|
|
|
66
103
|
signedOutDetail: string;
|
|
67
104
|
logIn: string;
|
|
68
105
|
logInAgain: string;
|
|
106
|
+
inChat: string;
|
|
107
|
+
inChatDetail: string;
|
|
69
108
|
};
|
|
70
109
|
folder: {
|
|
71
110
|
label: string;
|
|
@@ -106,6 +145,7 @@ declare const _default: {
|
|
|
106
145
|
add: {
|
|
107
146
|
title: string;
|
|
108
147
|
description: string;
|
|
148
|
+
chatDescription: string;
|
|
109
149
|
name: string;
|
|
110
150
|
namePlaceholder: string;
|
|
111
151
|
color: string;
|
|
@@ -18,10 +18,47 @@ export default {
|
|
|
18
18
|
addAccount: 'Add a {{provider}} account',
|
|
19
19
|
notInstalled: 'Not installed',
|
|
20
20
|
missing: 'Missing',
|
|
21
|
-
notInstalledNote: '
|
|
21
|
+
notInstalledNote: 'Install one on this machine to use it here.',
|
|
22
22
|
none: 'No agent CLIs found on this machine.',
|
|
23
23
|
noAccounts: 'This machine keeps no accounts yet. Update Ruimte there to add one.'
|
|
24
24
|
},
|
|
25
|
+
install: {
|
|
26
|
+
notInstalled: 'Not installed',
|
|
27
|
+
steps: 'Steps to set up {{provider}}',
|
|
28
|
+
platform: 'System',
|
|
29
|
+
platforms: {
|
|
30
|
+
darwin: 'macOS',
|
|
31
|
+
linux: 'Linux',
|
|
32
|
+
win32: 'Windows'
|
|
33
|
+
},
|
|
34
|
+
copy: 'Copy',
|
|
35
|
+
copied: 'Copied',
|
|
36
|
+
run: 'Run in a terminal',
|
|
37
|
+
guide: 'Install guide',
|
|
38
|
+
install: {
|
|
39
|
+
title: 'Install the CLI',
|
|
40
|
+
none: 'There is no install command for this system.',
|
|
41
|
+
done: 'Installed, version {{version}}.',
|
|
42
|
+
doneNoVersion: 'Installed.'
|
|
43
|
+
},
|
|
44
|
+
signIn: {
|
|
45
|
+
title: 'Sign in',
|
|
46
|
+
command: 'Run this in a terminal and follow its steps:',
|
|
47
|
+
env: 'Set <code>{{variable}}</code> in the environment the CLI starts in.',
|
|
48
|
+
chat: 'The first chat asks you to sign in.',
|
|
49
|
+
or: 'Or',
|
|
50
|
+
unknown: 'The CLI asks you to sign in the first time it runs.'
|
|
51
|
+
},
|
|
52
|
+
start: {
|
|
53
|
+
title: 'Start working',
|
|
54
|
+
description: 'Pick {{provider}} for your next chat or terminal.'
|
|
55
|
+
},
|
|
56
|
+
footer: {
|
|
57
|
+
missing: 'Not found on this machine yet. It is checked again when you come back to this window.',
|
|
58
|
+
found: 'Found on this machine.'
|
|
59
|
+
},
|
|
60
|
+
fallback: 'Install {{provider}} on this machine to use it here.'
|
|
61
|
+
},
|
|
25
62
|
abilities: {
|
|
26
63
|
version: 'Version {{version}}.',
|
|
27
64
|
chatAndTerminal: 'Chat and terminal.',
|
|
@@ -65,7 +102,9 @@ export default {
|
|
|
65
102
|
signedOut: 'Not logged in',
|
|
66
103
|
signedOutDetail: "Opens a terminal that runs the CLI's login with this folder.",
|
|
67
104
|
logIn: 'Log in',
|
|
68
|
-
logInAgain: 'Log in again'
|
|
105
|
+
logInAgain: 'Log in again',
|
|
106
|
+
inChat: 'Logs in from a chat',
|
|
107
|
+
inChatDetail: 'The first chat on this account asks you to log in, and the CLI keeps that login in this folder.'
|
|
69
108
|
},
|
|
70
109
|
folder: {
|
|
71
110
|
label: 'Folder',
|
|
@@ -106,6 +145,7 @@ export default {
|
|
|
106
145
|
add: {
|
|
107
146
|
title: 'Add a {{provider}} account',
|
|
108
147
|
description: 'Ruimte makes a folder for it on the machine, then opens a terminal where you log in.',
|
|
148
|
+
chatDescription: 'A folder is made for it on the machine. The first chat on it asks you to log in.',
|
|
109
149
|
name: 'Name',
|
|
110
150
|
namePlaceholder: 'Work',
|
|
111
151
|
color: 'Color',
|
|
@@ -22,6 +22,43 @@ declare const _default: {
|
|
|
22
22
|
none: string;
|
|
23
23
|
noAccounts: string;
|
|
24
24
|
};
|
|
25
|
+
install: {
|
|
26
|
+
notInstalled: string;
|
|
27
|
+
steps: string;
|
|
28
|
+
platform: string;
|
|
29
|
+
platforms: {
|
|
30
|
+
darwin: string;
|
|
31
|
+
linux: string;
|
|
32
|
+
win32: string;
|
|
33
|
+
};
|
|
34
|
+
copy: string;
|
|
35
|
+
copied: string;
|
|
36
|
+
run: string;
|
|
37
|
+
guide: string;
|
|
38
|
+
install: {
|
|
39
|
+
title: string;
|
|
40
|
+
none: string;
|
|
41
|
+
done: string;
|
|
42
|
+
doneNoVersion: string;
|
|
43
|
+
};
|
|
44
|
+
signIn: {
|
|
45
|
+
title: string;
|
|
46
|
+
command: string;
|
|
47
|
+
env: string;
|
|
48
|
+
chat: string;
|
|
49
|
+
or: string;
|
|
50
|
+
unknown: string;
|
|
51
|
+
};
|
|
52
|
+
start: {
|
|
53
|
+
title: string;
|
|
54
|
+
description: string;
|
|
55
|
+
};
|
|
56
|
+
footer: {
|
|
57
|
+
missing: string;
|
|
58
|
+
found: string;
|
|
59
|
+
};
|
|
60
|
+
fallback: string;
|
|
61
|
+
};
|
|
25
62
|
abilities: {
|
|
26
63
|
version: string;
|
|
27
64
|
chatAndTerminal: string;
|
|
@@ -66,6 +103,8 @@ declare const _default: {
|
|
|
66
103
|
signedOutDetail: string;
|
|
67
104
|
logIn: string;
|
|
68
105
|
logInAgain: string;
|
|
106
|
+
inChat: string;
|
|
107
|
+
inChatDetail: string;
|
|
69
108
|
};
|
|
70
109
|
folder: {
|
|
71
110
|
label: string;
|
|
@@ -106,6 +145,7 @@ declare const _default: {
|
|
|
106
145
|
add: {
|
|
107
146
|
title: string;
|
|
108
147
|
description: string;
|
|
148
|
+
chatDescription: string;
|
|
109
149
|
name: string;
|
|
110
150
|
namePlaceholder: string;
|
|
111
151
|
color: string;
|
|
@@ -18,10 +18,47 @@ export default {
|
|
|
18
18
|
addAccount: 'Een {{provider}}-account toevoegen',
|
|
19
19
|
notInstalled: 'Niet geïnstalleerd',
|
|
20
20
|
missing: 'Ontbreekt',
|
|
21
|
-
notInstalledNote: 'Installeer er een
|
|
21
|
+
notInstalledNote: 'Installeer er een op deze machine om hem hier te gebruiken.',
|
|
22
22
|
none: "Geen agent-CLI's gevonden op deze machine.",
|
|
23
23
|
noAccounts: 'Deze machine houdt nog geen accounts bij. Werk Ruimte daar bij om er een toe te voegen.'
|
|
24
24
|
},
|
|
25
|
+
install: {
|
|
26
|
+
notInstalled: 'Niet geïnstalleerd',
|
|
27
|
+
steps: '{{provider}} instellen in stappen',
|
|
28
|
+
platform: 'Systeem',
|
|
29
|
+
platforms: {
|
|
30
|
+
darwin: 'macOS',
|
|
31
|
+
linux: 'Linux',
|
|
32
|
+
win32: 'Windows'
|
|
33
|
+
},
|
|
34
|
+
copy: 'Kopiëren',
|
|
35
|
+
copied: 'Gekopieerd',
|
|
36
|
+
run: 'In een terminal uitvoeren',
|
|
37
|
+
guide: 'Installatiegids',
|
|
38
|
+
install: {
|
|
39
|
+
title: 'Installeer de CLI',
|
|
40
|
+
none: 'Er is geen installatiecommando voor dit systeem.',
|
|
41
|
+
done: 'Geïnstalleerd, versie {{version}}.',
|
|
42
|
+
doneNoVersion: 'Geïnstalleerd.'
|
|
43
|
+
},
|
|
44
|
+
signIn: {
|
|
45
|
+
title: 'Log in',
|
|
46
|
+
command: 'Voer dit uit in een terminal en volg de stappen:',
|
|
47
|
+
env: 'Zet <code>{{variable}}</code> in de omgeving waarin de CLI start.',
|
|
48
|
+
chat: 'De eerste chat vraagt je om in te loggen.',
|
|
49
|
+
or: 'Of',
|
|
50
|
+
unknown: 'De CLI vraagt je om in te loggen als hij voor het eerst draait.'
|
|
51
|
+
},
|
|
52
|
+
start: {
|
|
53
|
+
title: 'Aan de slag',
|
|
54
|
+
description: 'Kies {{provider}} voor je volgende chat of terminal.'
|
|
55
|
+
},
|
|
56
|
+
footer: {
|
|
57
|
+
missing: 'Nog niet gevonden op deze machine. Er wordt opnieuw gekeken als je terugkomt in dit venster.',
|
|
58
|
+
found: 'Gevonden op deze machine.'
|
|
59
|
+
},
|
|
60
|
+
fallback: 'Installeer {{provider}} op deze machine om hem hier te gebruiken.'
|
|
61
|
+
},
|
|
25
62
|
abilities: {
|
|
26
63
|
version: 'Versie {{version}}.',
|
|
27
64
|
chatAndTerminal: 'Chat en terminal.',
|
|
@@ -65,7 +102,9 @@ export default {
|
|
|
65
102
|
signedOut: 'Niet ingelogd',
|
|
66
103
|
signedOutDetail: 'Opent een terminal die de login van de CLI met deze map draait.',
|
|
67
104
|
logIn: 'Inloggen',
|
|
68
|
-
logInAgain: 'Opnieuw inloggen'
|
|
105
|
+
logInAgain: 'Opnieuw inloggen',
|
|
106
|
+
inChat: 'Logt in vanuit een chat',
|
|
107
|
+
inChatDetail: 'De eerste chat op dit account vraagt je in te loggen, en de CLI bewaart die login in deze map.'
|
|
69
108
|
},
|
|
70
109
|
folder: {
|
|
71
110
|
label: 'Map',
|
|
@@ -106,6 +145,7 @@ export default {
|
|
|
106
145
|
add: {
|
|
107
146
|
title: 'Een {{provider}}-account toevoegen',
|
|
108
147
|
description: 'Ruimte maakt er een map voor op de machine en opent dan een terminal waarin je inlogt.',
|
|
148
|
+
chatDescription: 'Er komt een map voor op de machine. De eerste chat erop vraagt je in te loggen.',
|
|
109
149
|
name: 'Naam',
|
|
110
150
|
namePlaceholder: 'Werk',
|
|
111
151
|
color: 'Kleur',
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import type { ProviderInfo } from '@adecore/agent-contracts';
|
|
2
|
-
import { type AccountEntry } from '../agents/accounts.js';
|
|
2
|
+
import { type AccountEntry, type AccountLogin } from '../agents/accounts.js';
|
|
3
3
|
interface AccountDetailProps {
|
|
4
4
|
provider: ProviderInfo;
|
|
5
5
|
entry: AccountEntry;
|
|
6
|
-
|
|
6
|
+
login: AccountLogin;
|
|
7
|
+
canOpenLogin: boolean;
|
|
7
8
|
loginBlocked: string | null;
|
|
8
9
|
secretsAvailable: boolean;
|
|
9
10
|
onRemoved(): void;
|
|
10
11
|
}
|
|
11
|
-
export declare function AccountDetail({ provider, entry,
|
|
12
|
+
export declare function AccountDetail({ provider, entry, login, canOpenLogin, loginBlocked, secretsAvailable, onRemoved }: AccountDetailProps): import("react").JSX.Element;
|
|
12
13
|
export {};
|
|
@@ -32,7 +32,7 @@ function NameField({ value, label, onSave }) {
|
|
|
32
32
|
} }));
|
|
33
33
|
}
|
|
34
34
|
/* One account: how it looks in a picker, who is signed in, where its folder is, its variables. */
|
|
35
|
-
export function AccountDetail({ provider, entry,
|
|
35
|
+
export function AccountDetail({ provider, entry, login, canOpenLogin, loginBlocked, secretsAvailable, onRemoved }) {
|
|
36
36
|
const { t } = useTranslation('agent-providers');
|
|
37
37
|
const scope = useChatScope();
|
|
38
38
|
const host = useChatHost();
|
|
@@ -46,9 +46,10 @@ export function AccountDetail({ provider, entry, canLogIn, loginBlocked, secrets
|
|
|
46
46
|
copyText(folder);
|
|
47
47
|
host.notify({ kind: 'success', title: t('account.folderCopied'), description: folder });
|
|
48
48
|
};
|
|
49
|
+
const trouble = status !== null && TROUBLE.has(status.state) && status.message ? status.message : null;
|
|
49
50
|
const loginDetail = () => {
|
|
50
|
-
if (
|
|
51
|
-
return
|
|
51
|
+
if (trouble !== null) {
|
|
52
|
+
return trouble;
|
|
52
53
|
}
|
|
53
54
|
if (!signedIn) {
|
|
54
55
|
return t('account.login.signedOutDetail');
|
|
@@ -59,11 +60,11 @@ export function AccountDetail({ provider, entry, canLogIn, loginBlocked, secrets
|
|
|
59
60
|
return (_jsxs(_Fragment, { children: [_jsx(DetailHeader, { mark: _jsx("span", { className: "grid h-6 shrink-0 place-items-center", children: _jsx(AccountDot, { color: account.color, className: "size-3" }) }), title: name, subtitle: _jsxs(_Fragment, { children: [_jsx(CliMark, { kind: provider.kind, size: 12, className: "text-text-muted" }), t('account.kind', { provider: provider.name })] }), actions: folder !== '' && (_jsx(Button, { variant: "secondary", onClick: showFolder, children: t('account.showFolder') })) }), _jsxs(SettingsSection, { children: [_jsx(SettingsRow, { label: t('account.enabled.label'), description: t('account.enabled.description'), control: _jsx(Switch, { checked: account.enabled !== false, label: t('account.enabled.label'), onCheckedChange: (checked) => {
|
|
60
61
|
const { enabled: _enabled, ...rest } = account;
|
|
61
62
|
void saveAccount(scope, host, id, checked ? rest : { ...rest, enabled: false });
|
|
62
|
-
} }) }), _jsx(SettingsRow, { label: t('account.name'), control: _jsx(NameField, { value: name, label: t('account.name'), onSave: (label) => void saveAccount(scope, host, id, { ...account, label }) }, name) }), _jsx(SettingsRow, { label: t('account.color'), control: _jsx(AccountColors, { value: account.color, label: t('account.color'), onChange: (color) => void saveAccount(scope, host, id, { ...account, color }) }) })] }),
|
|
63
|
+
} }) }), _jsx(SettingsRow, { label: t('account.name'), control: _jsx(NameField, { value: name, label: t('account.name'), onSave: (label) => void saveAccount(scope, host, id, { ...account, label }) }, name) }), _jsx(SettingsRow, { label: t('account.color'), control: _jsx(AccountColors, { value: account.color, label: t('account.color'), onChange: (color) => void saveAccount(scope, host, id, { ...account, color }) }) })] }), (login === 'chat' || (login === 'terminal' && canOpenLogin)) && (_jsxs(SettingsSection, { title: t('account.login.title'), children: [login === 'chat' ? (_jsx(SettingsRow, { label: t('account.login.inChat'), description: trouble ?? t('account.login.inChatDetail') })) : (_jsx(SettingsRow, { label: signedIn
|
|
63
64
|
? status?.email
|
|
64
65
|
? t('account.login.signedInAs', { email: status.email })
|
|
65
66
|
: t('account.login.signedIn')
|
|
66
|
-
: t('account.login.signedOut'), description: loginBlocked === null ? loginDetail() : `${loginDetail()} ${loginBlocked}`, control: loginBlocked === null ? (loginButton) : (_jsx(Tooltip, { label: loginBlocked, children: _jsx("span", { className: "inline-flex", children: loginButton }) })) }), _jsxs(SettingsRow, { label: t('account.folder.label'), children: [_jsx(Input, { mono: true, className: "h-8.5", value: folder, readOnly: true, "aria-label": t('account.folder.label') }), _jsx("p", { className: "-mt-1 text-xs text-text-muted", children: variable ? (_jsx(Trans, { t: t, i18nKey: "account.folder.detail", values: { variable }, components: { code: _jsx("code", { className: "font-mono text-code" }) } })) : (t('account.folder.detailPlain')) })] })] })), _jsx(AccountVariables, { id: id, account: account, secretsAvailable: secretsAvailable }, `${id}:${JSON.stringify(account.env ?? [])}`), _jsx(SettingsSection, { children: _jsx(SettingsRow, { label: t('account.remove.label'), description: isDefault ? t('account.remove.defaultNote') : t('account.remove.description'), control: _jsx(Button, { variant: "danger-outline", disabled: isDefault, onClick: () => setConfirming(true), children: t('account.remove.button') }) }) }), _jsx(ConfirmDialog, { open: confirming, onOpenChange: setConfirming, title: t('account.remove.confirmTitle', { account: name }), description: t('account.remove.confirmDescription', { folder }), confirmLabel: t('account.remove.confirm'), onConfirm: async () => {
|
|
67
|
+
: t('account.login.signedOut'), description: loginBlocked === null ? loginDetail() : `${loginDetail()} ${loginBlocked}`, control: loginBlocked === null ? (loginButton) : (_jsx(Tooltip, { label: loginBlocked, children: _jsx("span", { className: "inline-flex", children: loginButton }) })) })), _jsxs(SettingsRow, { label: t('account.folder.label'), children: [_jsx(Input, { mono: true, className: "h-8.5", value: folder, readOnly: true, "aria-label": t('account.folder.label') }), _jsx("p", { className: "-mt-1 text-xs text-text-muted", children: variable ? (_jsx(Trans, { t: t, i18nKey: "account.folder.detail", values: { variable }, components: { code: _jsx("code", { className: "font-mono text-code" }) } })) : (t('account.folder.detailPlain')) })] })] })), _jsx(AccountVariables, { id: id, account: account, secretsAvailable: secretsAvailable }, `${id}:${JSON.stringify(account.env ?? [])}`), _jsx(SettingsSection, { children: _jsx(SettingsRow, { label: t('account.remove.label'), description: isDefault ? t('account.remove.defaultNote') : t('account.remove.description'), control: _jsx(Button, { variant: "danger-outline", disabled: isDefault, onClick: () => setConfirming(true), children: t('account.remove.button') }) }) }), _jsx(ConfirmDialog, { open: confirming, onOpenChange: setConfirming, title: t('account.remove.confirmTitle', { account: name }), description: t('account.remove.confirmDescription', { folder }), confirmLabel: t('account.remove.confirm'), onConfirm: async () => {
|
|
67
68
|
await removeAccount(scope, host, id, provider.kind);
|
|
68
69
|
onRemoved();
|
|
69
70
|
} })] }));
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { ProviderInfo } from '@adecore/agent-contracts';
|
|
2
|
-
import { type AccountEntry } from '../agents/accounts.js';
|
|
2
|
+
import { type AccountEntry, type AccountLogin } from '../agents/accounts.js';
|
|
3
3
|
interface AddAccountFormProps {
|
|
4
4
|
provider: ProviderInfo;
|
|
5
5
|
entries: AccountEntry[];
|
|
6
|
+
login: AccountLogin;
|
|
6
7
|
onCancel(): void;
|
|
7
8
|
onAdded(id: string, name: string, made: boolean): void;
|
|
8
9
|
}
|
|
9
|
-
export declare function AddAccountForm({ provider, entries, onCancel, onAdded }: AddAccountFormProps): import("react").JSX.Element;
|
|
10
|
+
export declare function AddAccountForm({ provider, entries, login, onCancel, onAdded }: AddAccountFormProps): import("react").JSX.Element;
|
|
10
11
|
export {};
|
|
@@ -16,7 +16,7 @@ import { providerAccountsOf } from '../state/provider-accounts.js';
|
|
|
16
16
|
* A name and a color, asked before anything exists, so the account is made once with both. By default
|
|
17
17
|
* the machine makes the folder; under Advanced a person points at a folder of their own instead.
|
|
18
18
|
*/
|
|
19
|
-
export function AddAccountForm({ provider, entries, onCancel, onAdded }) {
|
|
19
|
+
export function AddAccountForm({ provider, entries, login, onCancel, onAdded }) {
|
|
20
20
|
const { t } = useTranslation('agent-providers');
|
|
21
21
|
const scope = useChatScope();
|
|
22
22
|
const { accents } = useChatHost();
|
|
@@ -51,5 +51,5 @@ export function AddAccountForm({ provider, entries, onCancel, onAdded }) {
|
|
|
51
51
|
setBusy(false);
|
|
52
52
|
}
|
|
53
53
|
};
|
|
54
|
-
return (_jsxs("form", { className: "contents", onSubmit: (event) => void submit(event), children: [_jsx(DetailHeader, { mark: _jsx(CliTile, { kind: provider.kind }), title: t('add.title', { provider: provider.name }), subtitle: t('add.description') }), _jsxs(SettingsSection, { children: [_jsx(SettingsRow, { label: t('add.name'), control: _jsx(Input, { className: "w-55 max-w-full", value: name, maxLength: 80, autoFocus: true, placeholder: t('add.namePlaceholder'), "aria-label": t('add.name'), onChange: (event) => setName(event.target.value) }) }), _jsx(SettingsRow, { label: t('add.color'), control: _jsx(AccountColors, { value: color, label: t('add.color'), onChange: setColor }) })] }), _jsxs("div", { className: "flex min-w-0 flex-col gap-2.5", children: [_jsxs("button", { type: "button", "aria-expanded": advanced, className: "flex items-center gap-1.5 self-start text-sm font-medium text-text-muted hover:text-text", onClick: () => setAdvanced((open) => !open), children: [_jsx(Icon, { icon: ChevronRight, size: 14, className: clsx('transition-transform', advanced && 'rotate-90') }), t('add.advanced')] }), advanced && (_jsx(SettingsSection, { children: _jsx(SettingsRow, { label: t('add.link.label'), description: t('add.link.description'), children: _jsx(Input, { mono: true, value: folder, spellCheck: false, autoComplete: "off", placeholder: t('add.link.placeholder'), "aria-label": t('add.link.label'), onChange: (event) => setFolder(event.target.value) }) }) }))] }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center justify-end gap-2", children: [error !== null && (_jsx(FormError, { render: _jsx("span", {}), className: "mr-auto break-words", children: error || t('add.failed') })), _jsx(Button, { onClick: onCancel, children: t('common.cancel') }), _jsx(Button, { type: "submit", variant: "primary", disabled: label === '' || busy, children: linking ? t('add.linkButton') : t('add.create') })] })] }));
|
|
54
|
+
return (_jsxs("form", { className: "contents", onSubmit: (event) => void submit(event), children: [_jsx(DetailHeader, { mark: _jsx(CliTile, { kind: provider.kind }), title: t('add.title', { provider: provider.name }), subtitle: login === 'chat' ? t('add.chatDescription') : t('add.description') }), _jsxs(SettingsSection, { children: [_jsx(SettingsRow, { label: t('add.name'), control: _jsx(Input, { className: "w-55 max-w-full", value: name, maxLength: 80, autoFocus: true, placeholder: t('add.namePlaceholder'), "aria-label": t('add.name'), onChange: (event) => setName(event.target.value) }) }), _jsx(SettingsRow, { label: t('add.color'), control: _jsx(AccountColors, { value: color, label: t('add.color'), onChange: setColor }) })] }), _jsxs("div", { className: "flex min-w-0 flex-col gap-2.5", children: [_jsxs("button", { type: "button", "aria-expanded": advanced, className: "flex items-center gap-1.5 self-start text-sm font-medium text-text-muted hover:text-text", onClick: () => setAdvanced((open) => !open), children: [_jsx(Icon, { icon: ChevronRight, size: 14, className: clsx('transition-transform', advanced && 'rotate-90') }), t('add.advanced')] }), advanced && (_jsx(SettingsSection, { children: _jsx(SettingsRow, { label: t('add.link.label'), description: t('add.link.description'), children: _jsx(Input, { mono: true, value: folder, spellCheck: false, autoComplete: "off", placeholder: t('add.link.placeholder'), "aria-label": t('add.link.label'), onChange: (event) => setFolder(event.target.value) }) }) }))] }), _jsxs("div", { className: "flex min-w-0 flex-wrap items-center justify-end gap-2", children: [error !== null && (_jsx(FormError, { render: _jsx("span", {}), className: "mr-auto break-words", children: error || t('add.failed') })), _jsx(Button, { onClick: onCancel, children: t('common.cancel') }), _jsx(Button, { type: "submit", variant: "primary", disabled: label === '' || busy, children: linking ? t('add.linkButton') : t('add.create') })] })] }));
|
|
55
55
|
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import type { ProviderInfo } from '@adecore/agent-contracts';
|
|
2
|
-
import { type AccountEntry } from '../agents/accounts.js';
|
|
2
|
+
import { type AccountEntry, type AccountLogin } from '../agents/accounts.js';
|
|
3
3
|
interface CliDetailProps {
|
|
4
4
|
provider: ProviderInfo;
|
|
5
5
|
entries: AccountEntry[] | null;
|
|
6
6
|
defaults: boolean;
|
|
7
|
-
|
|
7
|
+
login: AccountLogin;
|
|
8
8
|
onAddAccount(): void;
|
|
9
9
|
onPickAccount(id: string): void;
|
|
10
10
|
}
|
|
11
|
-
export declare function CliDetail({ provider, entries, defaults,
|
|
11
|
+
export declare function CliDetail({ provider, entries, defaults, login, onAddAccount, onPickAccount }: CliDetailProps): import("react").JSX.Element;
|
|
12
12
|
export {};
|
|
@@ -21,7 +21,7 @@ function ModelOptionRows({ provider, model, options }) {
|
|
|
21
21
|
return (_jsx(_Fragment, { children: model.options.map((option) => (_jsx(SettingsRow, { indent: true, muted: true, label: option.label, control: _jsx(ModelOptionControl, { option: option, options: options, layout: "row", onChange: (value) => setOption(option.id, value) }) }, option.id))) }));
|
|
22
22
|
}
|
|
23
23
|
/* One CLI: what it is, what a new chat of it starts with unless `defaults` is off, and its accounts. */
|
|
24
|
-
export function CliDetail({ provider, entries, defaults,
|
|
24
|
+
export function CliDetail({ provider, entries, defaults, login, onAddAccount, onPickAccount }) {
|
|
25
25
|
const { t } = useTranslation('agent-providers');
|
|
26
26
|
const { id: scopeId } = useChatScope();
|
|
27
27
|
const preferences = useChatPreferences();
|
|
@@ -31,7 +31,7 @@ export function CliDetail({ provider, entries, defaults, canAddAccount, onAddAcc
|
|
|
31
31
|
const picked = accountFor(preferences, scopeId, provider.kind, machineAccounts) ?? provider.kind;
|
|
32
32
|
// An account that is off is out of every picker, unless it is the one picked already.
|
|
33
33
|
const choosable = (entries ?? []).filter((entry) => entry.account.enabled !== false || entry.id === picked);
|
|
34
|
-
const
|
|
34
|
+
const canAddAccount = login !== null;
|
|
35
35
|
return (_jsxs(_Fragment, { children: [_jsx(DetailHeader, { mark: _jsx(CliTile, { kind: provider.kind }), title: provider.name, subtitle: `${provider.version ? `${t('abilities.version', { version: provider.version })} ` : ''}${providerAbilities(provider)}`, actions: canAddAccount && (_jsxs(Button, { variant: "secondary", className: "whitespace-nowrap", onClick: onAddAccount, children: [_jsx(Icon, { icon: Plus, size: 14 }), t('cli.addAccount')] })) }), defaults && (_jsxs(SettingsSection, { title: t('cli.defaults.title'), description: t('cli.defaults.description'), children: [choosable.length > 0 && (_jsx(SettingsRow, { searchId: "providers.defaults.account", label: t('cli.defaults.account'), control: _jsx(Select, { value: picked, label: t('cli.defaults.accountFor', { provider: provider.name }), align: "end", items: choosable.map((entry) => ({
|
|
36
36
|
value: entry.id,
|
|
37
37
|
label: accountName(entry, provider.name),
|
|
@@ -48,7 +48,7 @@ export function CliDetail({ provider, entries, defaults, canAddAccount, onAddAcc
|
|
|
48
48
|
model: value,
|
|
49
49
|
options: carryOptions(selection?.options ?? {}, provider.models.find((entry) => entry.slug === value))
|
|
50
50
|
}) }) })), model && _jsx(ModelOptionRows, { provider: provider.kind, model: model, options: selection?.options ?? {} }), choosable.length === 0 && provider.models.length === 0 && _jsx(SettingsRow, { muted: true, label: t('cli.defaults.usesCliDefault') })] })), entries === null ? (_jsx("p", { className: "text-xs text-text-faint", children: t('list.noAccounts') })) : (_jsx(SettingsSection, { title: t('cli.accounts'), footer: canAddAccount ? undefined : t('cli.onlyDefault', { provider: provider.name }), children: entries.map((entry) => {
|
|
51
|
-
const status = accountStatusLine(entry.status,
|
|
51
|
+
const status = accountStatusLine(entry.status, login === 'terminal');
|
|
52
52
|
return (_jsxs("button", { type: "button", className: "flex w-full min-w-0 items-center gap-3 px-4.5 py-3 text-left first:rounded-t-xl last:rounded-b-xl hover:bg-surface-hover", onClick: () => onPickAccount(entry.id), children: [_jsx(AccountDot, { color: entry.account.color }), _jsx("span", { className: "min-w-0 grow truncate text-sm text-text", children: accountName(entry, provider.name) }), _jsx("span", { className: `shrink-0 text-xs ${ACCOUNT_TONE_CLASSES[status.tone]}`, children: status.text }), _jsx(Icon, { icon: ChevronRight, size: 14, className: "shrink-0 text-text-faint" })] }, entry.id));
|
|
53
53
|
}) }))] }));
|
|
54
54
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { ProviderInfo } from '@adecore/agent-contracts';
|
|
2
|
+
import { type ProviderInstallStep } from './install-steps.js';
|
|
3
|
+
interface InstallPageProps {
|
|
4
|
+
provider: ProviderInfo;
|
|
5
|
+
signedIn: boolean;
|
|
6
|
+
extra: ProviderInstallStep | null;
|
|
7
|
+
}
|
|
8
|
+
export declare function InstallPage({ provider, signedIn, extra }: InstallPageProps): import("react").JSX.Element;
|
|
9
|
+
export {};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { Trans, useTranslation } from 'react-i18next';
|
|
5
|
+
import { Check, Copy, ExternalLink, SquareTerminal } from 'lucide-react';
|
|
6
|
+
import { Button, copyText, Icon, Pill, Segmented } from '@adecore/ui';
|
|
7
|
+
import { useChatHost } from '../host.js';
|
|
8
|
+
import { useChatScope } from '../scope.js';
|
|
9
|
+
import { installPlatforms, installStepStates, pagePlatform } from './install-steps.js';
|
|
10
|
+
import { CliMark } from './parts.js';
|
|
11
|
+
const noPlatform = () => null;
|
|
12
|
+
function CommandBlock({ command }) {
|
|
13
|
+
const { t } = useTranslation('agent-providers');
|
|
14
|
+
const [copied, setCopied] = useState(null);
|
|
15
|
+
return (_jsxs("div", { className: "flex min-w-0 items-center gap-2 rounded-lg border border-border bg-surface-sunken py-1 pr-1 pl-3", children: [_jsx("code", { className: "min-w-0 grow font-mono text-code break-all text-text select-text", children: command }), _jsxs(Button, { size: "xs", onClick: () => {
|
|
16
|
+
copyText(command);
|
|
17
|
+
setCopied(command);
|
|
18
|
+
}, children: [_jsx(Icon, { icon: copied === command ? Check : Copy, size: 12 }), copied === command ? t('install.copied') : t('install.copy')] })] }));
|
|
19
|
+
}
|
|
20
|
+
function Step({ index, state, title, children }) {
|
|
21
|
+
return (_jsxs("li", { "aria-current": state === 'current' ? 'step' : undefined, "data-state": state, className: clsx('flex min-w-0 gap-3 rounded-xl border p-4', state === 'current' ? 'border-accent' : 'border-border'), children: [_jsx("span", { className: clsx('grid size-6 shrink-0 place-items-center rounded-full text-xs font-medium', state === 'done' && 'bg-positive text-positive-text', state === 'current' && 'border border-accent text-accent', state === 'later' && 'bg-text/7 text-text-faint'), children: state === 'done' ? _jsx(Icon, { icon: Check, size: 14 }) : index + 1 }), _jsxs("div", { className: "flex min-w-0 grow flex-col gap-3", children: [_jsx("h4", { className: clsx('text-sm leading-6 font-medium', state === 'later' ? 'text-text-muted' : 'text-text'), children: title }), children] })] }));
|
|
22
|
+
}
|
|
23
|
+
function SignInWay({ way, canRun, onRun }) {
|
|
24
|
+
const { t } = useTranslation('agent-providers');
|
|
25
|
+
const { providerKeyNote } = useChatHost();
|
|
26
|
+
switch (way.kind) {
|
|
27
|
+
case 'command':
|
|
28
|
+
return (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [_jsx("p", { className: "text-xs text-text-muted", children: t('install.signIn.command') }), _jsx(CommandBlock, { command: way.command }), canRun && (_jsxs(Button, { variant: "secondary", size: "sm", className: "self-start", onClick: () => onRun(way.command), children: [_jsx(Icon, { icon: SquareTerminal, size: 14 }), t('install.run')] }))] }));
|
|
29
|
+
case 'env': {
|
|
30
|
+
const note = providerKeyNote?.(way.variable) ?? null;
|
|
31
|
+
return (_jsxs("p", { className: "text-xs text-text-muted", children: [_jsx(Trans, { t: t, i18nKey: "install.signIn.env", values: { variable: way.variable }, components: { code: _jsx("code", { className: "font-mono text-code text-text" }) } }), note !== null && ` ${note}`] }));
|
|
32
|
+
}
|
|
33
|
+
case 'chat':
|
|
34
|
+
return _jsx("p", { className: "text-xs text-text-muted", children: t('install.signIn.chat') });
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/* How to get a CLI that is not on the machine yet, step by step, until it is there and signed in. */
|
|
38
|
+
export function InstallPage({ provider, signedIn, extra }) {
|
|
39
|
+
const { t } = useTranslation('agent-providers');
|
|
40
|
+
const { id: scopeId } = useChatScope();
|
|
41
|
+
const host = useChatHost();
|
|
42
|
+
const useMachinePlatform = host.useMachinePlatform ?? noPlatform;
|
|
43
|
+
const machine = useMachinePlatform(scopeId) ?? pagePlatform();
|
|
44
|
+
const { offered, initial } = installPlatforms(provider, machine);
|
|
45
|
+
// Only a person's pick is kept, so a machine whose system arrives late still opens on its own.
|
|
46
|
+
const [chosen, setPlatform] = useState(null);
|
|
47
|
+
const platform = chosen ?? initial;
|
|
48
|
+
const install = provider.install;
|
|
49
|
+
const run = host.runProviderCommand;
|
|
50
|
+
const onRun = (command) => run?.(scopeId, provider.kind, command);
|
|
51
|
+
const command = platform === null ? undefined : install?.commands[platform];
|
|
52
|
+
const steps = [];
|
|
53
|
+
steps.push({
|
|
54
|
+
title: t('install.install.title'),
|
|
55
|
+
done: provider.installed,
|
|
56
|
+
body: provider.installed ? (_jsx("p", { className: "text-xs text-text-muted", children: provider.version ? t('install.install.done', { version: provider.version }) : t('install.install.doneNoVersion') })) : (_jsxs(_Fragment, { children: [offered.length > 1 && platform !== null && (_jsx(Segmented, { value: platform, label: t('install.platform'), options: offered.map((id) => ({ id, label: t(`install.platforms.${id}`) })), onValueChange: setPlatform })), command ? _jsx(CommandBlock, { command: command }) : _jsx("p", { className: "text-xs text-text-muted", children: t('install.install.none') }), ((command && run) || install?.guideUrl) && (_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [command && run && (_jsxs(Button, { variant: "primary", onClick: () => onRun(command), children: [_jsx(Icon, { icon: SquareTerminal, size: 14 }), t('install.run')] })), install?.guideUrl && (_jsxs(Button, { href: install.guideUrl, children: [t('install.guide'), _jsx(Icon, { icon: ExternalLink, size: 14 })] }))] }))] }))
|
|
57
|
+
});
|
|
58
|
+
if (extra !== null) {
|
|
59
|
+
steps.push(extra);
|
|
60
|
+
}
|
|
61
|
+
const ways = install?.signIn ?? [];
|
|
62
|
+
steps.push({
|
|
63
|
+
title: t('install.signIn.title'),
|
|
64
|
+
done: provider.installed && signedIn,
|
|
65
|
+
body: ways.length === 0 ? (_jsx("p", { className: "text-xs text-text-muted", children: t('install.signIn.unknown') })) : (ways.map((way, index) => (_jsxs("div", { className: "flex min-w-0 flex-col gap-2", children: [index > 0 && _jsx("span", { className: "text-xs font-medium text-text-faint", children: t('install.signIn.or') }), _jsx(SignInWay, { way: way, canRun: run !== undefined && provider.installed, onRun: onRun })] }, `${way.kind}-${index}`))))
|
|
66
|
+
});
|
|
67
|
+
steps.push({
|
|
68
|
+
title: t('install.start.title'),
|
|
69
|
+
done: false,
|
|
70
|
+
body: _jsx("p", { className: "text-xs text-text-muted", children: t('install.start.description', { provider: provider.name }) })
|
|
71
|
+
});
|
|
72
|
+
const states = installStepStates(steps.map((step) => step.done));
|
|
73
|
+
return (_jsxs(_Fragment, { children: [_jsxs("header", { className: "flex min-w-0 items-start gap-3", children: [_jsx("span", { className: "grid size-10 shrink-0 place-items-center rounded-xl bg-surface-sunken", children: _jsx(CliMark, { kind: provider.kind, size: 20 }) }), _jsxs("div", { className: "flex min-w-0 grow flex-col", children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx("h3", { className: "truncate text-lg font-semibold text-text", children: provider.name }), provider.installed ? (provider.version && (_jsx(Pill, { tone: "idle", mono: true, children: provider.version }))) : (_jsx(Pill, { children: t('install.notInstalled') }))] }), install && _jsx("p", { className: "text-xs text-text-muted", children: install.description })] })] }), install ? (_jsx("ol", { "aria-label": t('install.steps', { provider: provider.name }), className: "flex min-w-0 flex-col gap-3", children: steps.map((step, index) => (_jsx(Step, { index: index, state: states[index], title: step.title, children: step.body }, index))) })) : (_jsx("p", { className: "text-xs text-text-muted", children: t('install.fallback', { provider: provider.name }) })), _jsxs("p", { className: "flex min-w-0 items-center gap-2 text-xs text-text-muted", children: [_jsx("span", { "aria-hidden": true, className: clsx('size-2 shrink-0 rounded-full', provider.installed ? 'bg-status-idle' : 'bg-text-faint') }), provider.installed ? t('install.footer.found') : t('install.footer.missing')] })] }));
|
|
74
|
+
}
|