@ouraihub/aether-ui 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +3 -3
- package/src/chat/ApprovalCard.svelte +8 -2
- package/src/chat/ChatComposer.svelte +319 -0
- package/src/chat/ChatMessage.svelte +262 -0
- package/src/chat/ChatPanel.css +386 -0
- package/src/chat/ChatPanel.svelte +276 -1880
- package/src/chat/ChatPanelApprovals.svelte +28 -0
- package/src/chat/ChatPanelComposer.svelte +336 -0
- package/src/chat/ChatPanelDialogs.svelte +242 -0
- package/src/chat/ChatPanelHeader.svelte +108 -0
- package/src/chat/ChatPanelMessages.svelte +166 -0
- package/src/chat/ChatPanelMode.svelte +190 -0
- package/src/chat/ChatPanelState.svelte.ts +1 -0
- package/src/chat/ChatPanelToolbar.svelte +436 -0
- package/src/chat/ChatSurface.svelte +168 -0
- package/src/chat/ContextUsageStatus.svelte +97 -0
- package/src/chat/MessageItem.svelte +111 -214
- package/src/chat/ModelEffortPicker.svelte +326 -0
- package/src/chat/PickerEffort.svelte +71 -0
- package/src/chat/ReasoningControl.svelte +184 -0
- package/src/chat/ReasoningSlider.svelte +174 -0
- package/src/chat/SkillPicker.svelte +14 -6
- package/src/chat/UsageControl.svelte +223 -0
- package/src/chat/UsageDetails.svelte +44 -90
- package/src/chat/chat-attachments.svelte.ts +78 -0
- package/src/chat/chat-panel-history.svelte.ts +430 -0
- package/src/chat/chat-panel-models.svelte.ts +97 -0
- package/src/chat/chat-panel-props.ts +38 -0
- package/src/chat/context-status.ts +101 -0
- package/src/chat/icons/LICENSE-REMIX +186 -0
- package/src/chat/icons/LICENSE-SIMPLE-ICONS +30 -0
- package/src/chat/icons/PathIcon.svelte +8 -0
- package/src/chat/icons/effort-icons.ts +65 -0
- package/src/chat/icons/status-icons.ts +105 -0
- package/src/chat/index.ts +25 -1
- package/src/chat/model-effort.ts +177 -0
- package/src/chat/run-session-history.ts +56 -0
- package/src/chat/run-session-types.ts +69 -0
- package/src/chat/run-session.svelte.ts +73 -135
- package/src/chat/test-support/chat-fixture.ts +194 -0
- package/src/chat/test-support/conversation-fixtures.ts +32 -0
- package/src/chat/test-support/run-session-fixture.ts +112 -0
- package/src/dev/Demo.svelte +3 -1
- package/src/i18n/en-chat.d.ts +1 -0
- package/src/i18n/en-chat.js +201 -0
- package/src/i18n/en.ts +58 -180
- package/src/i18n/index.ts +7 -2
- package/src/i18n/zh-CN-chat.d.ts +1 -0
- package/src/i18n/zh-CN-chat.js +190 -0
- package/src/i18n/zh-CN.ts +8 -153
- package/src/logs/LogPanel.svelte +9 -3
- package/src/logs/LogSettings.svelte +3 -1
- package/src/mcp/McpClientEditor.svelte +204 -0
- package/src/mcp/McpClientSettings.svelte +57 -130
- package/src/mcp/McpServerSettings.svelte +47 -11
- package/src/mcp/input.ts +2 -1
- package/src/ports/contract.ts +11 -2
- package/src/ports/fake-optional.ts +81 -0
- package/src/ports/fake.ts +90 -86
- package/src/ports/search.ts +11 -2
- package/src/ports/test-support/fake-fixture.ts +63 -0
- package/src/providers/EndpointKeysDialog.svelte +27 -13
- package/src/providers/EndpointModels.svelte +311 -0
- package/src/providers/EndpointPanel.svelte +33 -258
- package/src/providers/ModelPickerDialog.svelte +59 -16
- package/src/providers/ModelPricing.svelte +125 -0
- package/src/providers/ModelSelect.svelte +22 -8
- package/src/providers/ModelSettingsDialog.svelte +61 -126
- package/src/providers/ProviderDialogs.svelte +120 -0
- package/src/providers/ProviderList.svelte +159 -0
- package/src/providers/ProvidersSettings.svelte +67 -207
- package/src/providers/RequestConfigDialog.svelte +40 -12
- package/src/providers/SecretInput.svelte +11 -3
- package/src/providers/draft.ts +39 -13
- package/src/providers/edit-session.ts +31 -7
- package/src/providers/reasoning.ts +18 -4
- package/src/providers/revision.svelte.ts +3 -1
- package/src/providers/test-support/providers-fixture.ts +120 -0
- package/src/search/SearchAdvancedTools.svelte +182 -0
- package/src/search/SearchProviderCard.svelte +195 -0
- package/src/search/SearchSettings.svelte +62 -265
- package/src/search/settings-flow.ts +8 -3
- package/src/skills/SkillAdd.svelte +51 -18
- package/src/skills/SkillAuthoring.svelte +69 -20
- package/src/skills/SkillEditor.svelte +13 -3
- package/src/skills/SkillPreviewDialog.svelte +19 -5
- package/src/skills/SkillsSettings.svelte +11 -4
- package/src/skills/test-support/skills-fixture.ts +139 -0
- package/src/tauri/index.ts +23 -7
- package/src/web/index.ts +90 -25
|
@@ -6,14 +6,11 @@
|
|
|
6
6
|
import { onDestroy } from 'svelte'
|
|
7
7
|
import { Alert, AlertDescription } from '#lib/components/ui/alert/index.js'
|
|
8
8
|
import { Button } from '#lib/components/ui/button/index.js'
|
|
9
|
-
import * as Dialog from '#lib/components/ui/dialog/index.js'
|
|
10
9
|
import * as Empty from '#lib/components/ui/empty/index.js'
|
|
11
10
|
import * as Field from '#lib/components/ui/field/index.js'
|
|
12
|
-
import { Input } from '#lib/components/ui/input/index.js'
|
|
13
|
-
import CopyInput from '../CopyInput.svelte'
|
|
14
11
|
import * as Select from '#lib/components/ui/select/index.js'
|
|
15
12
|
import { Switch } from '#lib/components/ui/switch/index.js'
|
|
16
|
-
import
|
|
13
|
+
import McpClientEditor from './McpClientEditor.svelte'
|
|
17
14
|
import { getKitContext } from '../context'
|
|
18
15
|
import { isKitClientError } from '../ports'
|
|
19
16
|
import type { Approval, McpTransport, ServerDto, ServerSave } from '../ports'
|
|
@@ -21,8 +18,6 @@
|
|
|
21
18
|
import { mapMcpInput } from './input'
|
|
22
19
|
|
|
23
20
|
const APPROVALS: Approval[] = ['auto', 'ask', 'deny']
|
|
24
|
-
const KINDS: McpTransport['kind'][] = ['http', 'stdio']
|
|
25
|
-
const ARGS_PLACEHOLDER = '-y\n@modelcontextprotocol/server-filesystem'
|
|
26
21
|
|
|
27
22
|
const { ports, i18n, notify, logger } = getKitContext()
|
|
28
23
|
const client = ports.mcpClient
|
|
@@ -130,7 +125,9 @@
|
|
|
130
125
|
|
|
131
126
|
/** One-line location shown in the list: the URL, or the command line. */
|
|
132
127
|
function location(transport: McpTransport): string {
|
|
133
|
-
return transport.kind === 'http'
|
|
128
|
+
return transport.kind === 'http'
|
|
129
|
+
? transport.url
|
|
130
|
+
: [transport.command, ...transport.args].join(' ')
|
|
134
131
|
}
|
|
135
132
|
|
|
136
133
|
const update = (next: ServerSave) => act(async () => void (servers = await need().save(next)))
|
|
@@ -277,7 +274,9 @@
|
|
|
277
274
|
>{server.name} <span class="text-muted-foreground">({server.slug})</span></span
|
|
278
275
|
>
|
|
279
276
|
<span class="text-muted-foreground truncate font-mono text-xs"
|
|
280
|
-
>{t(`mcp.client.transport.${server.transport.kind}`)} · {location(
|
|
277
|
+
>{t(`mcp.client.transport.${server.transport.kind}`)} · {location(
|
|
278
|
+
server.transport,
|
|
279
|
+
)}</span
|
|
281
280
|
>
|
|
282
281
|
{#if server.secretKeys.length}
|
|
283
282
|
<span class="text-muted-foreground text-xs">
|
|
@@ -291,7 +290,12 @@
|
|
|
291
290
|
<Button size="sm" variant="outline" disabled={busy} onclick={() => edit(server)}>
|
|
292
291
|
{t('mcp.client.edit')}
|
|
293
292
|
</Button>
|
|
294
|
-
<Button
|
|
293
|
+
<Button
|
|
294
|
+
size="sm"
|
|
295
|
+
variant="destructive"
|
|
296
|
+
disabled={busy}
|
|
297
|
+
onclick={() => void remove(server)}
|
|
298
|
+
>
|
|
295
299
|
{t('mcp.client.delete')}
|
|
296
300
|
</Button>
|
|
297
301
|
</div>
|
|
@@ -303,7 +307,9 @@
|
|
|
303
307
|
disabled={busy}
|
|
304
308
|
onCheckedChange={(on) => void update({ ...base(server), enabled: on })}
|
|
305
309
|
/>
|
|
306
|
-
<Field.Label for={`kit-mcp-enabled-${server.id}`}
|
|
310
|
+
<Field.Label for={`kit-mcp-enabled-${server.id}`}
|
|
311
|
+
>{t('mcp.client.enabled')}</Field.Label
|
|
312
|
+
>
|
|
307
313
|
</Field.Field>
|
|
308
314
|
<Field.Field orientation="horizontal" class="w-auto">
|
|
309
315
|
<Switch
|
|
@@ -312,7 +318,9 @@
|
|
|
312
318
|
disabled={busy}
|
|
313
319
|
onCheckedChange={(on) => void setTrusted(server, on)}
|
|
314
320
|
/>
|
|
315
|
-
<Field.Label for={`kit-mcp-trusted-${server.id}`}
|
|
321
|
+
<Field.Label for={`kit-mcp-trusted-${server.id}`}
|
|
322
|
+
>{t('mcp.client.trusted')}</Field.Label
|
|
323
|
+
>
|
|
316
324
|
</Field.Field>
|
|
317
325
|
{#if server.transport.kind === 'http'}
|
|
318
326
|
<Field.Field orientation="horizontal" class="w-auto">
|
|
@@ -322,13 +330,19 @@
|
|
|
322
330
|
disabled={busy}
|
|
323
331
|
onCheckedChange={(on) => void setPrivate(server, on)}
|
|
324
332
|
/>
|
|
325
|
-
<Field.Label for={`kit-mcp-private-${server.id}`}
|
|
333
|
+
<Field.Label for={`kit-mcp-private-${server.id}`}
|
|
334
|
+
>{t('mcp.client.allowPrivate')}</Field.Label
|
|
335
|
+
>
|
|
326
336
|
</Field.Field>
|
|
327
337
|
{/if}
|
|
328
338
|
</div>
|
|
329
339
|
{#if testErrors[server.id]}
|
|
330
340
|
<Alert variant="destructive">
|
|
331
|
-
<AlertDescription
|
|
341
|
+
<AlertDescription
|
|
342
|
+
>{t('mcp.client.testFailed', {
|
|
343
|
+
error: testErrors[server.id] ?? '',
|
|
344
|
+
})}</AlertDescription
|
|
345
|
+
>
|
|
332
346
|
</Alert>
|
|
333
347
|
{/if}
|
|
334
348
|
{#if server.tools.length}
|
|
@@ -345,7 +359,8 @@
|
|
|
345
359
|
<Select.Root
|
|
346
360
|
type="single"
|
|
347
361
|
value={tool.approval}
|
|
348
|
-
onValueChange={(value) =>
|
|
362
|
+
onValueChange={(value) =>
|
|
363
|
+
void setApproval(server, tool.name, value as Approval)}
|
|
349
364
|
>
|
|
350
365
|
<Select.Trigger
|
|
351
366
|
size="sm"
|
|
@@ -357,7 +372,10 @@
|
|
|
357
372
|
<Select.Content>
|
|
358
373
|
<Select.Group>
|
|
359
374
|
{#each APPROVALS as approval (approval)}
|
|
360
|
-
<Select.Item
|
|
375
|
+
<Select.Item
|
|
376
|
+
value={approval}
|
|
377
|
+
label={t(`mcp.client.approval.${approval}`)}
|
|
378
|
+
/>
|
|
361
379
|
{/each}
|
|
362
380
|
</Select.Group>
|
|
363
381
|
</Select.Content>
|
|
@@ -373,119 +391,28 @@
|
|
|
373
391
|
</ul>
|
|
374
392
|
</section>
|
|
375
393
|
|
|
376
|
-
<
|
|
377
|
-
open={editing}
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
<Select.Trigger id="kit-mcp-transport" class="w-full">
|
|
401
|
-
{t(`mcp.client.transport.${kind}`)}
|
|
402
|
-
</Select.Trigger>
|
|
403
|
-
<Select.Content>
|
|
404
|
-
<Select.Group>
|
|
405
|
-
{#each KINDS as option (option)}
|
|
406
|
-
<Select.Item value={option} label={t(`mcp.client.transport.${option}`)} />
|
|
407
|
-
{/each}
|
|
408
|
-
</Select.Group>
|
|
409
|
-
</Select.Content>
|
|
410
|
-
</Select.Root>
|
|
411
|
-
</Field.Field>
|
|
412
|
-
{#if kind === 'http'}
|
|
413
|
-
<Field.Field>
|
|
414
|
-
<Field.Label for="kit-mcp-url">{t('mcp.client.url')}</Field.Label>
|
|
415
|
-
<CopyInput id="kit-mcp-url" class="font-mono" placeholder="https://example.com/mcp" bind:value={url} />
|
|
416
|
-
<Field.Description>{t('mcp.client.urlHint')}</Field.Description>
|
|
417
|
-
</Field.Field>
|
|
418
|
-
{:else}
|
|
419
|
-
<Field.Field>
|
|
420
|
-
<Field.Label for="kit-mcp-command">{t('mcp.client.command')}</Field.Label>
|
|
421
|
-
<Input id="kit-mcp-command" class="font-mono" maxlength={1024} placeholder="npx" bind:value={command} />
|
|
422
|
-
</Field.Field>
|
|
423
|
-
<Field.Field>
|
|
424
|
-
<Field.Label for="kit-mcp-args">{t('mcp.client.args')}</Field.Label>
|
|
425
|
-
<Textarea id="kit-mcp-args" class="font-mono text-xs" placeholder={ARGS_PLACEHOLDER} bind:value={args} />
|
|
426
|
-
<Field.Description>{t('mcp.client.argsHint')}</Field.Description>
|
|
427
|
-
</Field.Field>
|
|
428
|
-
<Field.Field>
|
|
429
|
-
<Field.Label for="kit-mcp-cwd">{t('mcp.client.cwd')}</Field.Label>
|
|
430
|
-
<Input id="kit-mcp-cwd" class="font-mono" bind:value={cwd} />
|
|
431
|
-
<Field.Description>{t('mcp.client.cwdHint')}</Field.Description>
|
|
432
|
-
</Field.Field>
|
|
433
|
-
{/if}
|
|
434
|
-
{#if editId}
|
|
435
|
-
<Field.Field orientation="horizontal">
|
|
436
|
-
<Switch id="kit-mcp-replace" checked={replaceSecret} onCheckedChange={changeReplacement} />
|
|
437
|
-
<Field.Label for="kit-mcp-replace">
|
|
438
|
-
{t('mcp.client.replaceSecret', { keys: currentKeys.join(', ') || '—' })}
|
|
439
|
-
</Field.Label>
|
|
440
|
-
</Field.Field>
|
|
441
|
-
{/if}
|
|
442
|
-
{#if replaceSecret && kind === 'http'}
|
|
443
|
-
<Field.Field>
|
|
444
|
-
<Field.Label for="kit-mcp-headers">{t('mcp.client.headers')}</Field.Label>
|
|
445
|
-
<Textarea
|
|
446
|
-
id="kit-mcp-headers"
|
|
447
|
-
class="font-mono text-xs"
|
|
448
|
-
placeholder="Authorization: Bearer …"
|
|
449
|
-
bind:value={headers}
|
|
450
|
-
oninput={() => secretRevision++}
|
|
451
|
-
/>
|
|
452
|
-
</Field.Field>
|
|
453
|
-
<Field.Field>
|
|
454
|
-
<Field.Label for="kit-mcp-query">{t('mcp.client.query')}</Field.Label>
|
|
455
|
-
<Textarea
|
|
456
|
-
id="kit-mcp-query"
|
|
457
|
-
class="font-mono text-xs"
|
|
458
|
-
placeholder="ak=…"
|
|
459
|
-
bind:value={query}
|
|
460
|
-
oninput={() => secretRevision++}
|
|
461
|
-
/>
|
|
462
|
-
<Field.Description>{t('mcp.client.secretHint')}</Field.Description>
|
|
463
|
-
</Field.Field>
|
|
464
|
-
{:else if replaceSecret}
|
|
465
|
-
<Field.Field>
|
|
466
|
-
<Field.Label for="kit-mcp-env">{t('mcp.client.env')}</Field.Label>
|
|
467
|
-
<Textarea
|
|
468
|
-
id="kit-mcp-env"
|
|
469
|
-
class="font-mono text-xs"
|
|
470
|
-
placeholder="GITHUB_TOKEN=…"
|
|
471
|
-
bind:value={env}
|
|
472
|
-
oninput={() => secretRevision++}
|
|
473
|
-
/>
|
|
474
|
-
<Field.Description>{t('mcp.client.envHint')}</Field.Description>
|
|
475
|
-
</Field.Field>
|
|
476
|
-
{/if}
|
|
477
|
-
</Field.Group>
|
|
478
|
-
<Dialog.Footer>
|
|
479
|
-
<Button variant="outline" onclick={closeEditor}>{t('common.cancel')}</Button>
|
|
480
|
-
<Button
|
|
481
|
-
disabled={busy ||
|
|
482
|
-
editorSaving ||
|
|
483
|
-
!name.trim() ||
|
|
484
|
-
!slug.trim() ||
|
|
485
|
-
!(kind === 'http' ? url.trim() : command.trim())}
|
|
486
|
-
onclick={save}>{t('mcp.client.save')}</Button
|
|
487
|
-
>
|
|
488
|
-
</Dialog.Footer>
|
|
489
|
-
</Dialog.Content>
|
|
490
|
-
</Dialog.Root>
|
|
394
|
+
<McpClientEditor
|
|
395
|
+
bind:open={editing}
|
|
396
|
+
{editId}
|
|
397
|
+
bind:name
|
|
398
|
+
bind:slug
|
|
399
|
+
bind:kind
|
|
400
|
+
bind:url
|
|
401
|
+
bind:command
|
|
402
|
+
bind:args
|
|
403
|
+
bind:cwd
|
|
404
|
+
bind:replaceSecret
|
|
405
|
+
bind:headers
|
|
406
|
+
bind:query
|
|
407
|
+
bind:env
|
|
408
|
+
{currentKeys}
|
|
409
|
+
{editorSaving}
|
|
410
|
+
{busy}
|
|
411
|
+
onclose={closeEditor}
|
|
412
|
+
onsave={save}
|
|
413
|
+
onchangeKind={changeKind}
|
|
414
|
+
onchangeReplacement={changeReplacement}
|
|
415
|
+
oninputRevision={() => editRevision++}
|
|
416
|
+
onsecretInput={() => secretRevision++}
|
|
417
|
+
/>
|
|
491
418
|
{/if}
|
|
@@ -101,7 +101,11 @@
|
|
|
101
101
|
|
|
102
102
|
async function load() {
|
|
103
103
|
if (!server) return
|
|
104
|
-
const [nextStatus, nextScopes, nextTokens] = await Promise.all([
|
|
104
|
+
const [nextStatus, nextScopes, nextTokens] = await Promise.all([
|
|
105
|
+
server.status(),
|
|
106
|
+
server.scopes(),
|
|
107
|
+
server.tokens(),
|
|
108
|
+
])
|
|
105
109
|
setStatus(nextStatus)
|
|
106
110
|
scopes = nextScopes
|
|
107
111
|
tokens = nextTokens
|
|
@@ -111,7 +115,8 @@
|
|
|
111
115
|
void act(load)
|
|
112
116
|
})
|
|
113
117
|
|
|
114
|
-
const toggleRunning = () =>
|
|
118
|
+
const toggleRunning = () =>
|
|
119
|
+
act(async () => setStatus(status?.running ? await need().stop() : await need().start()))
|
|
115
120
|
|
|
116
121
|
const savePort = () => act(async () => setStatus(await need().setPort(Number(port))))
|
|
117
122
|
|
|
@@ -143,7 +148,8 @@
|
|
|
143
148
|
const revision = tokenRevision
|
|
144
149
|
const name = tokenName
|
|
145
150
|
const grants = [...tokenScopes]
|
|
146
|
-
const current = () =>
|
|
151
|
+
const current = () =>
|
|
152
|
+
tokenSession.isCurrent(token) && targetName === serverName && targetUrl === status?.url
|
|
147
153
|
issuing = true
|
|
148
154
|
try {
|
|
149
155
|
const next = await need().issueToken(name, grants)
|
|
@@ -204,7 +210,9 @@
|
|
|
204
210
|
<Field.Content>
|
|
205
211
|
<Field.Label>{t('mcp.server.title')}</Field.Label>
|
|
206
212
|
<Field.Description>
|
|
207
|
-
{status.running
|
|
213
|
+
{status.running
|
|
214
|
+
? t('mcp.server.running', { url: status.url })
|
|
215
|
+
: t('mcp.server.stopped')}
|
|
208
216
|
· {t('mcp.server.toolCount', { count: status.toolCount })}
|
|
209
217
|
</Field.Description>
|
|
210
218
|
</Field.Content>
|
|
@@ -218,7 +226,14 @@
|
|
|
218
226
|
</Field.Field>
|
|
219
227
|
<Field.Field orientation="horizontal">
|
|
220
228
|
<Field.Label for="kit-mcp-port">{t('mcp.server.port')}</Field.Label>
|
|
221
|
-
<Input
|
|
229
|
+
<Input
|
|
230
|
+
id="kit-mcp-port"
|
|
231
|
+
class="w-32"
|
|
232
|
+
type="number"
|
|
233
|
+
min="1024"
|
|
234
|
+
max="65535"
|
|
235
|
+
bind:value={port}
|
|
236
|
+
/>
|
|
222
237
|
<Button
|
|
223
238
|
disabled={busy || issuing || port === String(status.port)}
|
|
224
239
|
variant="outline"
|
|
@@ -240,7 +255,9 @@
|
|
|
240
255
|
bind:checked={() => scope.enabled, (on) => void toggleScope(scope, on)}
|
|
241
256
|
disabled={busy || issuing}
|
|
242
257
|
/>
|
|
243
|
-
<Field.Label for={`kit-mcp-scope-${scope.id}`}
|
|
258
|
+
<Field.Label for={`kit-mcp-scope-${scope.id}`}
|
|
259
|
+
>{t(scope.labelKey)} ({scope.id})</Field.Label
|
|
260
|
+
>
|
|
244
261
|
</Field.Field>
|
|
245
262
|
{/each}
|
|
246
263
|
</Field.Group>
|
|
@@ -251,7 +268,12 @@
|
|
|
251
268
|
<Field.Group>
|
|
252
269
|
<Field.Field>
|
|
253
270
|
<Field.Label for="kit-mcp-token-name">{t('mcp.server.tokenName')}</Field.Label>
|
|
254
|
-
<Input
|
|
271
|
+
<Input
|
|
272
|
+
id="kit-mcp-token-name"
|
|
273
|
+
bind:value={tokenName}
|
|
274
|
+
maxlength={200}
|
|
275
|
+
oninput={() => tokenRevision++}
|
|
276
|
+
/>
|
|
255
277
|
</Field.Field>
|
|
256
278
|
{#each scopes as scope (scope.id)}
|
|
257
279
|
<Field.Field orientation="horizontal">
|
|
@@ -260,7 +282,9 @@
|
|
|
260
282
|
checked={tokenScopes.includes(scope.id)}
|
|
261
283
|
onCheckedChange={(on) => toggleTokenScope(scope.id, on)}
|
|
262
284
|
/>
|
|
263
|
-
<Field.Label for={`kit-mcp-grant-${scope.id}`}
|
|
285
|
+
<Field.Label for={`kit-mcp-grant-${scope.id}`}
|
|
286
|
+
>{t(scope.labelKey)} ({scope.id})</Field.Label
|
|
287
|
+
>
|
|
264
288
|
</Field.Field>
|
|
265
289
|
{/each}
|
|
266
290
|
<Field.Field orientation="horizontal">
|
|
@@ -289,10 +313,17 @@
|
|
|
289
313
|
>
|
|
290
314
|
{t('mcp.server.copyClaude')}
|
|
291
315
|
</Button>
|
|
292
|
-
<Button
|
|
316
|
+
<Button
|
|
317
|
+
size="sm"
|
|
318
|
+
variant="outline"
|
|
319
|
+
disabled={!configInput}
|
|
320
|
+
onclick={() => void copy('json')}
|
|
321
|
+
>
|
|
293
322
|
{t('mcp.server.copyJson')}
|
|
294
323
|
</Button>
|
|
295
|
-
<Button size="sm" variant="ghost" onclick={clearIssued}
|
|
324
|
+
<Button size="sm" variant="ghost" onclick={clearIssued}
|
|
325
|
+
>{t('mcp.server.dismiss')}</Button
|
|
326
|
+
>
|
|
296
327
|
</div>
|
|
297
328
|
</AlertDescription>
|
|
298
329
|
</Alert>
|
|
@@ -313,7 +344,12 @@
|
|
|
313
344
|
</span>
|
|
314
345
|
</div>
|
|
315
346
|
{#if token.revokedAt === null}
|
|
316
|
-
<Button
|
|
347
|
+
<Button
|
|
348
|
+
size="sm"
|
|
349
|
+
variant="destructive"
|
|
350
|
+
disabled={busy || issuing}
|
|
351
|
+
onclick={() => void revoke(token)}
|
|
352
|
+
>
|
|
317
353
|
{t('mcp.server.revoke')}
|
|
318
354
|
</Button>
|
|
319
355
|
{:else}
|
package/src/mcp/input.ts
CHANGED
|
@@ -15,7 +15,8 @@ export interface McpInput {
|
|
|
15
15
|
env: string
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
export type McpInputResult =
|
|
18
|
+
export type McpInputResult =
|
|
19
|
+
{ ok: true; value: ServerSave } | { ok: false; error: 'secretLine' | 'transportChanged' }
|
|
19
20
|
|
|
20
21
|
/** Split only at the first separator; values may themselves contain separators. */
|
|
21
22
|
function pairs(text: string, separator: string): Record<string, string> | null {
|
package/src/ports/contract.ts
CHANGED
|
@@ -86,7 +86,12 @@ export interface ConversationClient {
|
|
|
86
86
|
get(id: string): Promise<Conversation>
|
|
87
87
|
remove(id: string): Promise<void>
|
|
88
88
|
rename(id: string, title: string): Promise<ConversationSummary>
|
|
89
|
-
editTurn(
|
|
89
|
+
editTurn(
|
|
90
|
+
conversationId: string,
|
|
91
|
+
turnId: string,
|
|
92
|
+
text: string,
|
|
93
|
+
expectedText: string,
|
|
94
|
+
): Promise<Conversation>
|
|
90
95
|
removeTurn(conversationId: string, turnId: string): Promise<Conversation>
|
|
91
96
|
fork(conversationId: string, turnId: string): Promise<Conversation>
|
|
92
97
|
selectTurn(conversationId: string, turnId: string): Promise<Conversation>
|
|
@@ -94,7 +99,11 @@ export interface ConversationClient {
|
|
|
94
99
|
|
|
95
100
|
export interface RunClient {
|
|
96
101
|
/** Resolves once accepted; events may arrive before acceptance. */
|
|
97
|
-
start(
|
|
102
|
+
start(
|
|
103
|
+
request: RunRequest,
|
|
104
|
+
onEvent: (event: RunEvent) => void,
|
|
105
|
+
options?: CallOptions,
|
|
106
|
+
): Promise<RunAccepted>
|
|
98
107
|
cancel(runId: string): Promise<void>
|
|
99
108
|
approve(runId: string, callId: string, allow: boolean): Promise<void>
|
|
100
109
|
getSnapshot(runId: string): Promise<RunSnapshot>
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { KitClientError } from './contract'
|
|
2
|
+
import type { McpClientPort, McpServerPort } from './contract'
|
|
3
|
+
import type { SearchPort } from './search'
|
|
4
|
+
import type { SkillSourcesPort } from './skill-sources'
|
|
5
|
+
|
|
6
|
+
export type FakeError = (
|
|
7
|
+
code: ConstructorParameters<typeof KitClientError>[0]['code'],
|
|
8
|
+
message: string,
|
|
9
|
+
details?: Record<string, string>,
|
|
10
|
+
) => KitClientError
|
|
11
|
+
|
|
12
|
+
const STOPPED = { running: false, port: 0, url: '', toolCount: 0 }
|
|
13
|
+
|
|
14
|
+
export function mcpClientDefaults(options: Partial<McpClientPort>): McpClientPort {
|
|
15
|
+
return {
|
|
16
|
+
list: () => Promise.resolve([]),
|
|
17
|
+
save: () => Promise.resolve([]),
|
|
18
|
+
remove: () => Promise.resolve([]),
|
|
19
|
+
refresh: () => Promise.resolve([]),
|
|
20
|
+
setToolApproval: () => Promise.resolve(),
|
|
21
|
+
...options,
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function mcpServerDefaults(options: Partial<McpServerPort>): McpServerPort {
|
|
26
|
+
return {
|
|
27
|
+
status: () => Promise.resolve(STOPPED),
|
|
28
|
+
tokens: () => Promise.resolve([]),
|
|
29
|
+
start: () => Promise.resolve(STOPPED),
|
|
30
|
+
stop: () => Promise.resolve(STOPPED),
|
|
31
|
+
setPort: (port) => Promise.resolve({ ...STOPPED, port }),
|
|
32
|
+
issueToken: (name, scopes) =>
|
|
33
|
+
Promise.resolve({
|
|
34
|
+
token: 'kit_fake',
|
|
35
|
+
id: 'fake-token',
|
|
36
|
+
name,
|
|
37
|
+
scopes: [...scopes],
|
|
38
|
+
createdAt: 0,
|
|
39
|
+
lastUsedAt: null,
|
|
40
|
+
revokedAt: null,
|
|
41
|
+
}),
|
|
42
|
+
revokeToken: () => Promise.resolve(),
|
|
43
|
+
scopes: () => Promise.resolve([]),
|
|
44
|
+
setScopes: () => Promise.resolve([]),
|
|
45
|
+
...options,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function searchDefaults(options: Partial<SearchPort>, error: FakeError): SearchPort {
|
|
50
|
+
const unavailable = () => Promise.reject(error('internal', 'Configure the fake search method'))
|
|
51
|
+
return {
|
|
52
|
+
settings: unavailable,
|
|
53
|
+
save: unavailable,
|
|
54
|
+
setDefault: unavailable,
|
|
55
|
+
savePreferences: unavailable,
|
|
56
|
+
saveKey: unavailable,
|
|
57
|
+
removeKey: unavailable,
|
|
58
|
+
reveal: unavailable,
|
|
59
|
+
check: unavailable,
|
|
60
|
+
search: unavailable,
|
|
61
|
+
fetch: unavailable,
|
|
62
|
+
...options,
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export function skillSourceDefaults(
|
|
67
|
+
options: Partial<SkillSourcesPort>,
|
|
68
|
+
error: FakeError,
|
|
69
|
+
): SkillSourcesPort {
|
|
70
|
+
const unavailable = () =>
|
|
71
|
+
Promise.reject(error('internal', 'Configure the fake skill source method'))
|
|
72
|
+
return {
|
|
73
|
+
search: unavailable,
|
|
74
|
+
prepare: unavailable,
|
|
75
|
+
discover: unavailable,
|
|
76
|
+
prepareSystem: unavailable,
|
|
77
|
+
pickDirectory: unavailable,
|
|
78
|
+
pickSearchDirectory: unavailable,
|
|
79
|
+
...options,
|
|
80
|
+
}
|
|
81
|
+
}
|