@signal9/era-ui 34.3.0 → 34.4.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/CHANGELOG.md +12 -0
- package/dist/ai/code-mode/code-mode.svelte +201 -0
- package/dist/ai/code-mode/code-mode.svelte.d.ts +15 -0
- package/dist/ai/code-mode/index.d.ts +2 -0
- package/dist/ai/code-mode/index.js +1 -0
- package/dist/ai/code-mode/types.d.ts +26 -0
- package/dist/ai/code-mode/types.js +1 -0
- package/dist/ai/confirmation/batch.d.ts +21 -0
- package/dist/ai/confirmation/batch.js +1 -0
- package/dist/ai/confirmation/confirmation-batch.svelte +190 -0
- package/dist/ai/confirmation/confirmation-batch.svelte.d.ts +17 -0
- package/dist/ai/confirmation/index.d.ts +2 -0
- package/dist/ai/confirmation/index.js +1 -0
- package/dist/ai/index.d.ts +1 -0
- package/dist/ai/index.js +1 -0
- package/dist/era-ui.css +1 -1
- package/dist/styles/surfaces/bevel.css +5 -5
- package/dist/ui/file-diff/file-diff.svelte +243 -0
- package/dist/ui/file-diff/file-diff.svelte.d.ts +16 -0
- package/dist/ui/file-diff/fixture.svelte +76 -0
- package/dist/ui/file-diff/fixture.svelte.d.ts +3 -0
- package/dist/ui/file-diff/index.d.ts +2 -0
- package/dist/ui/file-diff/index.js +1 -0
- package/dist/ui/file-diff/types.d.ts +31 -0
- package/dist/ui/file-diff/types.js +1 -0
- package/dist/ui/tabs/tabs.svelte +7 -2
- package/dist/ui/tabs/tabs.svelte.d.ts +1 -1
- package/dist/ui/terminal/fixture.svelte +57 -0
- package/dist/ui/terminal/fixture.svelte.d.ts +3 -0
- package/dist/ui/terminal/index.d.ts +2 -0
- package/dist/ui/terminal/index.js +1 -0
- package/dist/ui/terminal/terminal.svelte +91 -0
- package/dist/ui/terminal/terminal.svelte.d.ts +18 -0
- package/dist/ui/terminal/types.d.ts +26 -0
- package/dist/ui/terminal/types.js +1 -0
- package/package.json +16 -1
- package/skills/era-ui/references/releases/34.md +12 -0
- package/skills/era-ui/references/releases/index.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,15 @@
|
|
|
1
|
+
## [34.4.1](https://github.com/sig-nine/era-ui/compare/v34.4.0...v34.4.1) (2026-08-26)
|
|
2
|
+
|
|
3
|
+
### Bug Fixes
|
|
4
|
+
|
|
5
|
+
* **bevel:** unify compact keycap travel ([7ca2e28](https://github.com/sig-nine/era-ui/commit/7ca2e2874a6bbe6e6f6a0aff811462bdab40aad6))
|
|
6
|
+
|
|
7
|
+
## [34.4.0](https://github.com/sig-nine/era-ui/compare/v34.3.0...v34.4.0) (2026-08-25)
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* add Navi execution primitives ([540c97b](https://github.com/sig-nine/era-ui/commit/540c97bc0a4f45b106dd7bb4228810d2f17c9db6))
|
|
12
|
+
|
|
1
13
|
## [34.3.0](https://github.com/sig-nine/era-ui/compare/v34.2.9...v34.3.0) (2026-08-25)
|
|
2
14
|
|
|
3
15
|
### Features
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
4
|
+
import { Badge } from '../../ui/badge/index.js';
|
|
5
|
+
import { Bar } from '../../ui/bar/index.js';
|
|
6
|
+
import { Button } from '../../ui/button/index.js';
|
|
7
|
+
import { CodeBlock } from '../../ui/code-block/index.js';
|
|
8
|
+
import * as Tabs from '../../ui/tabs/index.js';
|
|
9
|
+
import { cn } from '../../utils/index.js';
|
|
10
|
+
import * as RunStatus from '../run-status/index.js';
|
|
11
|
+
import * as StructuredValue from '../structured-value/index.js';
|
|
12
|
+
import type {
|
|
13
|
+
CodeModeCallState,
|
|
14
|
+
CodeModeExternalCall,
|
|
15
|
+
CodeModeExecution,
|
|
16
|
+
CodeModeLog,
|
|
17
|
+
CodeModeView
|
|
18
|
+
} from './types.js';
|
|
19
|
+
|
|
20
|
+
interface Props extends HTMLAttributes<HTMLDivElement>, CodeModeExecution {
|
|
21
|
+
ref?: HTMLDivElement | null;
|
|
22
|
+
activeView?: CodeModeView;
|
|
23
|
+
label?: string;
|
|
24
|
+
oncancel?: () => void;
|
|
25
|
+
call?: Snippet<[CodeModeExternalCall]>;
|
|
26
|
+
resultView?: Snippet<[unknown]>;
|
|
27
|
+
empty?: Snippet<[CodeModeView]>;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
let {
|
|
31
|
+
ref = $bindable(null),
|
|
32
|
+
status,
|
|
33
|
+
source,
|
|
34
|
+
language = 'javascript',
|
|
35
|
+
logs = [],
|
|
36
|
+
externalCalls = [],
|
|
37
|
+
result,
|
|
38
|
+
error,
|
|
39
|
+
activeView = $bindable('source'),
|
|
40
|
+
label = 'Code Mode execution',
|
|
41
|
+
oncancel,
|
|
42
|
+
call,
|
|
43
|
+
resultView,
|
|
44
|
+
empty,
|
|
45
|
+
class: className,
|
|
46
|
+
...restProps
|
|
47
|
+
}: Props = $props();
|
|
48
|
+
|
|
49
|
+
const latest = $derived(logs.at(-1));
|
|
50
|
+
const completedCalls = $derived(
|
|
51
|
+
externalCalls.filter((externalCall) => externalCall.state === 'complete').length
|
|
52
|
+
);
|
|
53
|
+
const failedCalls = $derived(
|
|
54
|
+
externalCalls.filter((externalCall) => externalCall.state === 'failed').length
|
|
55
|
+
);
|
|
56
|
+
|
|
57
|
+
const callTone: Record<CodeModeCallState, 'default' | 'accent' | 'success' | 'destructive'> = {
|
|
58
|
+
queued: 'default',
|
|
59
|
+
running: 'accent',
|
|
60
|
+
complete: 'success',
|
|
61
|
+
failed: 'destructive',
|
|
62
|
+
cancelled: 'default'
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function logClass(log: CodeModeLog): string {
|
|
66
|
+
return (
|
|
67
|
+
{
|
|
68
|
+
default: 'text-fg',
|
|
69
|
+
muted: 'text-muted',
|
|
70
|
+
success: 'text-success',
|
|
71
|
+
warning: 'text-warning',
|
|
72
|
+
destructive: 'text-destructive'
|
|
73
|
+
} as const
|
|
74
|
+
)[log.tone ?? 'default'];
|
|
75
|
+
}
|
|
76
|
+
</script>
|
|
77
|
+
|
|
78
|
+
<div
|
|
79
|
+
bind:this={ref}
|
|
80
|
+
aria-label={label}
|
|
81
|
+
class={cn(
|
|
82
|
+
'flex min-h-0 min-w-0 flex-col overflow-hidden rounded-bar bg-well shadow-well',
|
|
83
|
+
className
|
|
84
|
+
)}
|
|
85
|
+
{...restProps}
|
|
86
|
+
>
|
|
87
|
+
<RunStatus.Root
|
|
88
|
+
{status}
|
|
89
|
+
tools={externalCalls.length
|
|
90
|
+
? {
|
|
91
|
+
complete: completedCalls,
|
|
92
|
+
total: externalCalls.length,
|
|
93
|
+
running: externalCalls.filter((externalCall) => externalCall.state === 'running').length,
|
|
94
|
+
failed: failedCalls
|
|
95
|
+
}
|
|
96
|
+
: undefined}
|
|
97
|
+
latest={latest ? { tone: latest.tone ?? 'default', text: latest.text } : undefined}
|
|
98
|
+
{oncancel}
|
|
99
|
+
class="rounded-b-none shadow-none"
|
|
100
|
+
/>
|
|
101
|
+
|
|
102
|
+
<Tabs.Root bind:value={activeView} class="flex min-h-0 flex-1 flex-col">
|
|
103
|
+
<Tabs.List>
|
|
104
|
+
<Bar size="control" content="chip" divider class="overflow-x-auto rounded-none">
|
|
105
|
+
{#each ['source', 'console', 'calls', 'result'] as view (view)}
|
|
106
|
+
<Tabs.Trigger value={view}>
|
|
107
|
+
{#snippet child({ props })}
|
|
108
|
+
<Button
|
|
109
|
+
{...props}
|
|
110
|
+
size="chip"
|
|
111
|
+
class="data-[state=active]:bg-highlight data-[state=active]:text-bright"
|
|
112
|
+
>
|
|
113
|
+
{view}{view === 'console' && logs.length ? ` ${logs.length}` : ''}{view ===
|
|
114
|
+
'calls' && externalCalls.length
|
|
115
|
+
? ` ${externalCalls.length}`
|
|
116
|
+
: ''}
|
|
117
|
+
</Button>
|
|
118
|
+
{/snippet}
|
|
119
|
+
</Tabs.Trigger>
|
|
120
|
+
{/each}
|
|
121
|
+
</Bar>
|
|
122
|
+
</Tabs.List>
|
|
123
|
+
|
|
124
|
+
<Tabs.Content value="source" class="min-h-0 overflow-auto p-panel">
|
|
125
|
+
{#if source}
|
|
126
|
+
<CodeBlock code={source} data-language={language} />
|
|
127
|
+
{:else if empty}
|
|
128
|
+
{@render empty('source')}
|
|
129
|
+
{:else}
|
|
130
|
+
<p class="text-body text-muted">No source</p>
|
|
131
|
+
{/if}
|
|
132
|
+
</Tabs.Content>
|
|
133
|
+
|
|
134
|
+
<Tabs.Content value="console" class="min-h-0 overflow-auto p-panel">
|
|
135
|
+
{#if logs.length}
|
|
136
|
+
<div role="log" aria-live="polite" class="flex min-w-0 flex-col font-mono text-body">
|
|
137
|
+
{#each logs as log (log.id)}
|
|
138
|
+
<div class={cn('min-h-control whitespace-pre-wrap', logClass(log))}>{log.text}</div>
|
|
139
|
+
{/each}
|
|
140
|
+
</div>
|
|
141
|
+
{:else if empty}
|
|
142
|
+
{@render empty('console')}
|
|
143
|
+
{:else}
|
|
144
|
+
<p class="text-body text-muted">No console output</p>
|
|
145
|
+
{/if}
|
|
146
|
+
</Tabs.Content>
|
|
147
|
+
|
|
148
|
+
<Tabs.Content value="calls" class="min-h-0 overflow-auto p-panel">
|
|
149
|
+
{#if externalCalls.length}
|
|
150
|
+
<div class="flex min-w-0 flex-col gap-panel">
|
|
151
|
+
{#each externalCalls as externalCall (externalCall.id)}
|
|
152
|
+
{#if call}
|
|
153
|
+
{@render call(externalCall)}
|
|
154
|
+
{:else}
|
|
155
|
+
<article
|
|
156
|
+
class="flex min-w-0 flex-col gap-gutter border-b border-divider-faded pb-panel"
|
|
157
|
+
>
|
|
158
|
+
<header class="flex h-control items-center gap-gutter">
|
|
159
|
+
<code class="min-w-0 flex-1 truncate text-bright">{externalCall.tool}</code>
|
|
160
|
+
{#if externalCall.durationMs !== undefined}
|
|
161
|
+
<span class="text-muted tabular-nums">{externalCall.durationMs}ms</span>
|
|
162
|
+
{/if}
|
|
163
|
+
<Badge tone={callTone[externalCall.state]}>{externalCall.state}</Badge>
|
|
164
|
+
</header>
|
|
165
|
+
{#if externalCall.input !== undefined}
|
|
166
|
+
<StructuredValue.Root value={externalCall.input} />
|
|
167
|
+
{/if}
|
|
168
|
+
{#if externalCall.output !== undefined}
|
|
169
|
+
<StructuredValue.Root value={externalCall.output} />
|
|
170
|
+
{/if}
|
|
171
|
+
{#if externalCall.error}
|
|
172
|
+
<p class="text-body text-destructive">{externalCall.error}</p>
|
|
173
|
+
{/if}
|
|
174
|
+
</article>
|
|
175
|
+
{/if}
|
|
176
|
+
{/each}
|
|
177
|
+
</div>
|
|
178
|
+
{:else if empty}
|
|
179
|
+
{@render empty('calls')}
|
|
180
|
+
{:else}
|
|
181
|
+
<p class="text-body text-muted">No external calls</p>
|
|
182
|
+
{/if}
|
|
183
|
+
</Tabs.Content>
|
|
184
|
+
|
|
185
|
+
<Tabs.Content value="result" class="min-h-0 overflow-auto p-panel">
|
|
186
|
+
{#if error}
|
|
187
|
+
<p class="font-mono text-body whitespace-pre-wrap text-destructive">{error}</p>
|
|
188
|
+
{:else if result !== undefined}
|
|
189
|
+
{#if resultView}
|
|
190
|
+
{@render resultView(result)}
|
|
191
|
+
{:else}
|
|
192
|
+
<StructuredValue.Root value={result} />
|
|
193
|
+
{/if}
|
|
194
|
+
{:else if empty}
|
|
195
|
+
{@render empty('result')}
|
|
196
|
+
{:else}
|
|
197
|
+
<p class="text-body text-muted">No result yet</p>
|
|
198
|
+
{/if}
|
|
199
|
+
</Tabs.Content>
|
|
200
|
+
</Tabs.Root>
|
|
201
|
+
</div>
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import type { CodeModeExternalCall, CodeModeExecution, CodeModeView } from './types.js';
|
|
4
|
+
interface Props extends HTMLAttributes<HTMLDivElement>, CodeModeExecution {
|
|
5
|
+
ref?: HTMLDivElement | null;
|
|
6
|
+
activeView?: CodeModeView;
|
|
7
|
+
label?: string;
|
|
8
|
+
oncancel?: () => void;
|
|
9
|
+
call?: Snippet<[CodeModeExternalCall]>;
|
|
10
|
+
resultView?: Snippet<[unknown]>;
|
|
11
|
+
empty?: Snippet<[CodeModeView]>;
|
|
12
|
+
}
|
|
13
|
+
declare const CodeMode: import("svelte").Component<Props, {}, "ref" | "activeView">;
|
|
14
|
+
type CodeMode = ReturnType<typeof CodeMode>;
|
|
15
|
+
export default CodeMode;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { default as Root } from './code-mode.svelte';
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { LogTone, RunState } from '../run-status/index.js';
|
|
2
|
+
export type CodeModeView = 'source' | 'console' | 'calls' | 'result';
|
|
3
|
+
export interface CodeModeLog {
|
|
4
|
+
id: string | number;
|
|
5
|
+
text: string;
|
|
6
|
+
tone?: LogTone;
|
|
7
|
+
}
|
|
8
|
+
export type CodeModeCallState = 'queued' | 'running' | 'complete' | 'failed' | 'cancelled';
|
|
9
|
+
export interface CodeModeExternalCall {
|
|
10
|
+
id: string;
|
|
11
|
+
tool: string;
|
|
12
|
+
state: CodeModeCallState;
|
|
13
|
+
input?: unknown;
|
|
14
|
+
output?: unknown;
|
|
15
|
+
error?: string;
|
|
16
|
+
durationMs?: number;
|
|
17
|
+
}
|
|
18
|
+
export interface CodeModeExecution {
|
|
19
|
+
status: RunState;
|
|
20
|
+
source: string;
|
|
21
|
+
language?: string;
|
|
22
|
+
logs?: readonly CodeModeLog[];
|
|
23
|
+
externalCalls?: readonly CodeModeExternalCall[];
|
|
24
|
+
result?: unknown;
|
|
25
|
+
error?: string;
|
|
26
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ApprovalController } from './approval.svelte.js';
|
|
2
|
+
export interface ApprovalScope {
|
|
3
|
+
id: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export interface BatchedApprovalRequest {
|
|
8
|
+
id: string;
|
|
9
|
+
title: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
capability?: string;
|
|
12
|
+
/** Omit to permit every scope offered by the enclosing panel. */
|
|
13
|
+
scopeIds?: readonly string[];
|
|
14
|
+
controller: ApprovalController;
|
|
15
|
+
}
|
|
16
|
+
export interface BatchedApprovalDecision {
|
|
17
|
+
decision: 'approved' | 'denied';
|
|
18
|
+
scopeId: string;
|
|
19
|
+
requestIds: string[];
|
|
20
|
+
overrides: Record<string, Record<string, unknown>>;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
3
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
4
|
+
import * as Checkbox from '../../ui/checkbox/index.js';
|
|
5
|
+
import { Button } from '../../ui/button/index.js';
|
|
6
|
+
import { Label } from '../../ui/label/index.js';
|
|
7
|
+
import { cn } from '../../utils/index.js';
|
|
8
|
+
import Args from './confirmation-args.svelte';
|
|
9
|
+
import type { ApprovalScope, BatchedApprovalDecision, BatchedApprovalRequest } from './batch.js';
|
|
10
|
+
|
|
11
|
+
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
12
|
+
ref?: HTMLDivElement | null;
|
|
13
|
+
requests: readonly BatchedApprovalRequest[];
|
|
14
|
+
scopes: readonly ApprovalScope[];
|
|
15
|
+
selectedIds?: string[];
|
|
16
|
+
scopeId?: string | null;
|
|
17
|
+
label?: string;
|
|
18
|
+
busy?: boolean;
|
|
19
|
+
onapprove?: (decision: BatchedApprovalDecision) => void | Promise<void>;
|
|
20
|
+
ondeny?: (decision: BatchedApprovalDecision) => void | Promise<void>;
|
|
21
|
+
ondecision?: (decision: BatchedApprovalDecision) => void | Promise<void>;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
let {
|
|
25
|
+
ref = $bindable(null),
|
|
26
|
+
requests,
|
|
27
|
+
scopes,
|
|
28
|
+
selectedIds = $bindable([]),
|
|
29
|
+
scopeId = $bindable(null),
|
|
30
|
+
label = 'Requested actions',
|
|
31
|
+
busy = false,
|
|
32
|
+
onapprove,
|
|
33
|
+
ondeny,
|
|
34
|
+
ondecision,
|
|
35
|
+
class: className,
|
|
36
|
+
...restProps
|
|
37
|
+
}: Props = $props();
|
|
38
|
+
|
|
39
|
+
const selected = $derived(new SvelteSet(selectedIds));
|
|
40
|
+
const selectedRequests = $derived(requests.filter((request) => selected.has(request.id)));
|
|
41
|
+
const allowedScopes = $derived(
|
|
42
|
+
scopes.filter((scope) =>
|
|
43
|
+
selectedRequests.every((request) => !request.scopeIds || request.scopeIds.includes(scope.id))
|
|
44
|
+
)
|
|
45
|
+
);
|
|
46
|
+
const effectiveScopeId = $derived(
|
|
47
|
+
allowedScopes.some((scope) => scope.id === scopeId) ? scopeId : (allowedScopes[0]?.id ?? null)
|
|
48
|
+
);
|
|
49
|
+
const allSelected = $derived(requests.length > 0 && selectedRequests.length === requests.length);
|
|
50
|
+
const someSelected = $derived(selectedRequests.length > 0 && !allSelected);
|
|
51
|
+
const canDecide = $derived(selectedRequests.length > 0 && effectiveScopeId !== null);
|
|
52
|
+
const canApprove = $derived(
|
|
53
|
+
selectedRequests.length > 0 &&
|
|
54
|
+
effectiveScopeId !== null &&
|
|
55
|
+
selectedRequests.every((request) => request.controller.valid)
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
function toggleRequest(requestId: string, checked: boolean): void {
|
|
59
|
+
const next = new SvelteSet(selectedIds);
|
|
60
|
+
if (checked) next.add(requestId);
|
|
61
|
+
else next.delete(requestId);
|
|
62
|
+
selectedIds = [...next];
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
function toggleAll(checked: boolean): void {
|
|
66
|
+
selectedIds = checked ? requests.map((request) => request.id) : [];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function chooseScope(nextScopeId: string): void {
|
|
70
|
+
scopeId = nextScopeId;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function decision(kind: BatchedApprovalDecision['decision']): BatchedApprovalDecision | null {
|
|
74
|
+
if (!canDecide || (kind === 'approved' && !canApprove) || !effectiveScopeId) return null;
|
|
75
|
+
return {
|
|
76
|
+
decision: kind,
|
|
77
|
+
scopeId: effectiveScopeId,
|
|
78
|
+
requestIds: selectedRequests.map((request) => request.id),
|
|
79
|
+
overrides: Object.fromEntries(
|
|
80
|
+
selectedRequests.map((request) => [request.id, request.controller.diff()])
|
|
81
|
+
)
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async function submit(kind: BatchedApprovalDecision['decision']): Promise<void> {
|
|
86
|
+
const payload = decision(kind);
|
|
87
|
+
if (!payload) return;
|
|
88
|
+
await ondecision?.(payload);
|
|
89
|
+
if (kind === 'approved') await onapprove?.(payload);
|
|
90
|
+
else await ondeny?.(payload);
|
|
91
|
+
}
|
|
92
|
+
</script>
|
|
93
|
+
|
|
94
|
+
<div
|
|
95
|
+
bind:this={ref}
|
|
96
|
+
class={cn('flex min-w-0 flex-col gap-panel rounded-bar bg-well p-panel shadow-well', className)}
|
|
97
|
+
{...restProps}
|
|
98
|
+
>
|
|
99
|
+
<fieldset disabled={busy} class="flex min-w-0 flex-col gap-panel">
|
|
100
|
+
<legend class="sr-only">{label}</legend>
|
|
101
|
+
<div class="flex h-control items-center gap-gutter border-b border-divider-faded">
|
|
102
|
+
<Label
|
|
103
|
+
class="flex min-w-0 flex-1 cursor-pointer items-center gap-gutter font-medium text-bright"
|
|
104
|
+
>
|
|
105
|
+
<Checkbox.Root
|
|
106
|
+
checked={allSelected}
|
|
107
|
+
indeterminate={someSelected}
|
|
108
|
+
onCheckedChange={toggleAll}
|
|
109
|
+
aria-label="Select all actions"
|
|
110
|
+
/>
|
|
111
|
+
<span class="min-w-0 flex-1 truncate">{label}</span>
|
|
112
|
+
</Label>
|
|
113
|
+
<span class="text-body text-muted tabular-nums"
|
|
114
|
+
>{selectedRequests.length}/{requests.length}</span
|
|
115
|
+
>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div class="flex min-w-0 flex-col gap-panel">
|
|
119
|
+
{#each requests as request (request.id)}
|
|
120
|
+
<article
|
|
121
|
+
class={cn(
|
|
122
|
+
'flex min-w-0 flex-col gap-gutter border-b border-divider-faded pb-panel',
|
|
123
|
+
selected.has(request.id) && 'bg-highlight px-panel'
|
|
124
|
+
)}
|
|
125
|
+
>
|
|
126
|
+
<Label class="flex min-h-control cursor-pointer items-center gap-gutter">
|
|
127
|
+
<Checkbox.Root
|
|
128
|
+
checked={selected.has(request.id)}
|
|
129
|
+
onCheckedChange={(checked) => toggleRequest(request.id, checked)}
|
|
130
|
+
aria-label={`Select ${request.title}`}
|
|
131
|
+
/>
|
|
132
|
+
<span class="flex min-w-0 flex-1 flex-col gap-inset-pill">
|
|
133
|
+
<span class="truncate font-medium text-bright">{request.title}</span>
|
|
134
|
+
{#if request.description}
|
|
135
|
+
<span class="text-body text-muted">{request.description}</span>
|
|
136
|
+
{/if}
|
|
137
|
+
</span>
|
|
138
|
+
{#if request.capability}
|
|
139
|
+
<code class="shrink-0 text-body text-muted">{request.capability}</code>
|
|
140
|
+
{/if}
|
|
141
|
+
</Label>
|
|
142
|
+
{#if selected.has(request.id)}
|
|
143
|
+
<Args
|
|
144
|
+
controller={request.controller}
|
|
145
|
+
class="ps-[calc(var(--era-h-icon)+var(--era-gap))]"
|
|
146
|
+
/>
|
|
147
|
+
{/if}
|
|
148
|
+
</article>
|
|
149
|
+
{/each}
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
<div class="flex min-w-0 flex-col gap-gutter">
|
|
153
|
+
<span class="text-body text-muted">Approval scope</span>
|
|
154
|
+
<div role="radiogroup" aria-label="Approval scope" class="flex flex-wrap gap-gutter">
|
|
155
|
+
{#each scopes as scope (scope.id)}
|
|
156
|
+
{@const allowed = allowedScopes.some((candidate) => candidate.id === scope.id)}
|
|
157
|
+
<Button
|
|
158
|
+
type="button"
|
|
159
|
+
size="chip"
|
|
160
|
+
role="radio"
|
|
161
|
+
aria-checked={scope.id === effectiveScopeId}
|
|
162
|
+
active={scope.id === effectiveScopeId}
|
|
163
|
+
disabled={!allowed}
|
|
164
|
+
title={scope.description}
|
|
165
|
+
onclick={() => chooseScope(scope.id)}
|
|
166
|
+
>
|
|
167
|
+
{scope.label}
|
|
168
|
+
</Button>
|
|
169
|
+
{/each}
|
|
170
|
+
</div>
|
|
171
|
+
</div>
|
|
172
|
+
|
|
173
|
+
<div class="flex flex-wrap items-center justify-end gap-gutter">
|
|
174
|
+
<Button
|
|
175
|
+
type="button"
|
|
176
|
+
tone="destructive"
|
|
177
|
+
disabled={!canDecide}
|
|
178
|
+
{busy}
|
|
179
|
+
onclick={() => void submit('denied')}>Deny selected</Button
|
|
180
|
+
>
|
|
181
|
+
<Button
|
|
182
|
+
type="button"
|
|
183
|
+
tone="success"
|
|
184
|
+
disabled={!canApprove}
|
|
185
|
+
{busy}
|
|
186
|
+
onclick={() => void submit('approved')}>Approve selected</Button
|
|
187
|
+
>
|
|
188
|
+
</div>
|
|
189
|
+
</fieldset>
|
|
190
|
+
</div>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'svelte/elements';
|
|
2
|
+
import type { ApprovalScope, BatchedApprovalDecision, BatchedApprovalRequest } from './batch.js';
|
|
3
|
+
interface Props extends HTMLAttributes<HTMLDivElement> {
|
|
4
|
+
ref?: HTMLDivElement | null;
|
|
5
|
+
requests: readonly BatchedApprovalRequest[];
|
|
6
|
+
scopes: readonly ApprovalScope[];
|
|
7
|
+
selectedIds?: string[];
|
|
8
|
+
scopeId?: string | null;
|
|
9
|
+
label?: string;
|
|
10
|
+
busy?: boolean;
|
|
11
|
+
onapprove?: (decision: BatchedApprovalDecision) => void | Promise<void>;
|
|
12
|
+
ondeny?: (decision: BatchedApprovalDecision) => void | Promise<void>;
|
|
13
|
+
ondecision?: (decision: BatchedApprovalDecision) => void | Promise<void>;
|
|
14
|
+
}
|
|
15
|
+
declare const ConfirmationBatch: import("svelte").Component<Props, {}, "ref" | "selectedIds" | "scopeId">;
|
|
16
|
+
type ConfirmationBatch = ReturnType<typeof ConfirmationBatch>;
|
|
17
|
+
export default ConfirmationBatch;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
export { default as Root, type ApprovalState } from './confirmation.svelte';
|
|
2
2
|
export { default as Actions } from './confirmation-actions.svelte';
|
|
3
3
|
export { default as Args } from './confirmation-args.svelte';
|
|
4
|
+
export { default as Batch } from './confirmation-batch.svelte';
|
|
5
|
+
export type { ApprovalScope, BatchedApprovalDecision, BatchedApprovalRequest } from './batch.js';
|
|
4
6
|
export { ApprovalController, setApprovalContext, getApprovalContext, type FieldKind } from './approval.svelte.js';
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as Root } from './confirmation.svelte';
|
|
2
2
|
export { default as Actions } from './confirmation-actions.svelte';
|
|
3
3
|
export { default as Args } from './confirmation-args.svelte';
|
|
4
|
+
export { default as Batch } from './confirmation-batch.svelte';
|
|
4
5
|
export { ApprovalController, setApprovalContext, getApprovalContext } from './approval.svelte.js';
|
package/dist/ai/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export * as RuntimeFeed from './runtime-feed/index.js';
|
|
|
19
19
|
export * as ErrorPanel from './error-panel/index.js';
|
|
20
20
|
export * as RunStatus from './run-status/index.js';
|
|
21
21
|
export * as Swarm from './swarm/index.js';
|
|
22
|
+
export * as CodeMode from './code-mode/index.js';
|
|
22
23
|
export { Response, repairStreamingMarkdown } from './response/index.js';
|
|
23
24
|
export { default as ContextGauge } from './context/context.svelte';
|
|
24
25
|
export { default as ModelSelector } from './model-selector/model-selector.svelte';
|
package/dist/ai/index.js
CHANGED
|
@@ -24,6 +24,7 @@ export * as RuntimeFeed from './runtime-feed/index.js';
|
|
|
24
24
|
export * as ErrorPanel from './error-panel/index.js';
|
|
25
25
|
export * as RunStatus from './run-status/index.js';
|
|
26
26
|
export * as Swarm from './swarm/index.js';
|
|
27
|
+
export * as CodeMode from './code-mode/index.js';
|
|
27
28
|
export { Response, repairStreamingMarkdown } from './response/index.js';
|
|
28
29
|
export { default as ContextGauge } from './context/context.svelte';
|
|
29
30
|
export { default as ModelSelector } from './model-selector/model-selector.svelte';
|