@baguette-studios/kernl-ui-core 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,13 @@
1
+ Copyright (c) 2026 Jules Astier
2
+
3
+ Permission to use, copy, modify, and/or distribute this software for any
4
+ purpose with or without fee is hereby granted, provided that the above
5
+ copyright notice and this permission notice appear in all copies.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8
+ WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9
+ MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
10
+ ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11
+ WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
12
+ ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
13
+ OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @baguette-studios/kernl-ui-core
2
+
3
+ Framework-neutral assistant UI state, theme tokens, icons, and shared styles for Kernl framework adapters.
4
+
5
+ ```bash
6
+ npm install @baguette-studios/kernl-ui-core
7
+ ```
8
+
9
+ React applications should normally install `@baguette-studios/kernl-ui`. Use this package directly when building a framework adapter or applying the shared CSS variable contract.
10
+
11
+ Available styles include `@baguette-studios/kernl-ui-core/styles.css`, `@baguette-studios/kernl-ui-core/theme.css`, and `@baguette-studios/kernl-ui-core/tailwind.css`.
@@ -0,0 +1,34 @@
1
+ import type { AgentInFlightSubmitMode, AgentSessionInput, AgentSnapshot, AuditEvent, ApprovalRequest, ToolCall, ToolResult } from "@baguette-studios/kernl-core";
2
+ import type { AgentActionRequest, AgentActivityItem, AgentCommand, AgentQuickAction, AgentStatus, AgentUiSnapshot } from "./types";
3
+ export type OptionalAgentUiOverride<T> = {
4
+ [Property in keyof T]?: T[Property] | undefined;
5
+ };
6
+ export type AgentUiOverrides<TContent = string> = OptionalAgentUiOverride<Omit<AgentUiSnapshot<TContent>, "commands" | "quickActions" | "actions" | "activity">> & {
7
+ commands?: AgentUiSnapshot<TContent>["commands"] | undefined;
8
+ quickActions?: AgentUiSnapshot<TContent>["quickActions"] | undefined;
9
+ actions?: AgentUiSnapshot<TContent>["actions"] | undefined;
10
+ activity?: AgentUiSnapshot<TContent>["activity"] | undefined;
11
+ };
12
+ export type AgentUiApprovalController = {
13
+ approvals: readonly ApprovalRequest[];
14
+ approve: (requestId: string, reason?: string) => void;
15
+ deny: (requestId: string, reason?: string) => void;
16
+ };
17
+ export interface DeriveAgentUiSnapshotOptions<TContent = string> {
18
+ snapshot: AgentSnapshot;
19
+ eventLog?: readonly AuditEvent[] | undefined;
20
+ approvals?: AgentUiApprovalController | undefined;
21
+ invokeTool: (call: ToolCall) => Promise<ToolResult>;
22
+ sendMessage: (input: AgentSessionInput, options?: {
23
+ submitMode?: AgentInFlightSubmitMode | undefined;
24
+ } | undefined) => Promise<unknown>;
25
+ overrides?: AgentUiOverrides<TContent> | undefined;
26
+ }
27
+ export declare function deriveAgentUiSnapshot<TContent = string>({ snapshot, eventLog, approvals, invokeTool, sendMessage, overrides, }: DeriveAgentUiSnapshotOptions<TContent>): AgentUiSnapshot<TContent>;
28
+ export declare function deriveStatus<TContent = string>(snapshot: AgentSnapshot, events: readonly AuditEvent[], actions: readonly AgentActionRequest<TContent>[]): AgentStatus;
29
+ export declare function deriveCommands<TContent = string>(snapshot: AgentSnapshot, invokeTool: (call: ToolCall) => Promise<ToolResult>): AgentCommand<TContent>[];
30
+ export declare function deriveQuickActions<TContent = string>(snapshot: AgentSnapshot, onPrompt: NonNullable<AgentUiSnapshot<TContent>["onPrompt"]>): AgentQuickAction<TContent>[];
31
+ export declare function deriveApprovalActions<TContent = string>(events: readonly AuditEvent[], approvals: AgentUiApprovalController): AgentActionRequest<TContent>[];
32
+ export declare function deriveActivity<TContent = string>(events: readonly AuditEvent[], snapshot: AgentSnapshot): AgentActivityItem<TContent>[];
33
+ export declare function parseCommandArgs(input: string | undefined): unknown;
34
+ //# sourceMappingURL=derive.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"derive.d.ts","sourceRoot":"","sources":["../src/derive.ts"],"names":[],"mappings":"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"}
package/dist/derive.js ADDED
@@ -0,0 +1,234 @@
1
+ import { humanizeStatus } from "./utils";
2
+ export function deriveAgentUiSnapshot({ snapshot, eventLog = [], approvals = emptyApprovalController(), invokeTool, sendMessage, overrides = {}, }) {
3
+ const derivedActions = deriveApprovalActions(eventLog, approvals);
4
+ const derivedStatus = deriveStatus(snapshot, eventLog, derivedActions);
5
+ const commands = overrides.commands ?? deriveCommands(snapshot, invokeTool);
6
+ const onPrompt = overrides.onPrompt ??
7
+ ((prompt, options) => sendMessage(options?.assets?.length ? { role: "user", content: prompt, assets: options.assets } : prompt, options?.mode ? { submitMode: options.mode } : undefined).then(() => undefined));
8
+ const quickActions = overrides.quickActions ?? deriveQuickActions(snapshot, onPrompt);
9
+ const actions = overrides.actions ?? derivedActions;
10
+ const activity = overrides.activity ?? deriveActivity(eventLog, snapshot);
11
+ const status = overrides.status ?? derivedStatus;
12
+ const scopeTitle = activeScopeTitle(snapshot);
13
+ const statusDetail = `${snapshot.scopes.length} scopes · ${snapshot.tools.length} tools · ${snapshot.prompts.length} prompts`;
14
+ const onCommand = overrides.onCommand ??
15
+ ((command, input) => {
16
+ const tool = snapshot.tools.find((candidate) => candidate.name === command);
17
+ if (!tool) {
18
+ return undefined;
19
+ }
20
+ return invokeTool({
21
+ name: tool.name,
22
+ args: parseCommandArgs(input),
23
+ }).then(() => undefined);
24
+ });
25
+ return {
26
+ status,
27
+ statusLabel: overrides.statusLabel ?? asContent(humanizeStatus(status)),
28
+ statusDetail: overrides.statusDetail ??
29
+ overrides.currentTask ??
30
+ asContent(scopeTitle) ??
31
+ asContent(statusDetail),
32
+ goal: overrides.goal,
33
+ currentTask: overrides.currentTask ?? asContent(scopeTitle),
34
+ model: overrides.model,
35
+ commands,
36
+ quickActions,
37
+ actions,
38
+ activity,
39
+ onCommand,
40
+ onPrompt,
41
+ onApproveAction: overrides.onApproveAction ?? ((action) => approvals.approve(action.id)),
42
+ onRejectAction: overrides.onRejectAction ??
43
+ ((action) => approvals.deny(action.id, "Rejected in AgentActionReview")),
44
+ };
45
+ }
46
+ export function deriveStatus(snapshot, events, actions) {
47
+ if (actions.length > 0) {
48
+ return "waiting";
49
+ }
50
+ const lastEvent = events.at(-1);
51
+ if (lastEvent && (lastEvent.type.includes("failed") || lastEvent.type.includes("denied"))) {
52
+ return "error";
53
+ }
54
+ if (snapshot.scopes.length ||
55
+ snapshot.tools.length ||
56
+ snapshot.resources.length ||
57
+ snapshot.instructions.length) {
58
+ return "ready";
59
+ }
60
+ return "idle";
61
+ }
62
+ export function deriveCommands(snapshot, invokeTool) {
63
+ return snapshot.tools.map((tool) => ({
64
+ id: tool.name,
65
+ label: tool.name,
66
+ description: asContent(tool.description),
67
+ shortcut: tool.risk,
68
+ disabled: false,
69
+ run: (input) => invokeTool({
70
+ name: tool.name,
71
+ args: parseCommandArgs(input),
72
+ }).then(() => undefined),
73
+ }));
74
+ }
75
+ export function deriveQuickActions(snapshot, onPrompt) {
76
+ return snapshot.prompts.map((prompt) => ({
77
+ id: prompt.id,
78
+ label: prompt.label,
79
+ prompt: prompt.prompt,
80
+ description: asContent(prompt.description),
81
+ scopeId: prompt.scopeId,
82
+ disabled: false,
83
+ run: async () => {
84
+ await onPrompt(prompt.prompt);
85
+ },
86
+ }));
87
+ }
88
+ export function deriveApprovalActions(events, approvals) {
89
+ if (approvals.approvals.length > 0) {
90
+ return approvals.approvals.map((request) => ({
91
+ id: request.id,
92
+ title: `Run ${request.tool.name}`,
93
+ description: asContent(request.reason),
94
+ command: JSON.stringify({
95
+ tool: request.tool.name,
96
+ args: request.redactedArgs,
97
+ }, null, 2),
98
+ subject: request.tool.description,
99
+ risk: mapRisk(request.tool.risk),
100
+ status: "pending",
101
+ requestedAt: request.createdAt,
102
+ metadata: {
103
+ scope: asContent(request.tool.scopeId ?? "global"),
104
+ confirmation: asContent(request.tool.requiresConfirmation ? "required" : "not required"),
105
+ },
106
+ onApprove: () => approvals.approve(request.id),
107
+ onReject: () => approvals.deny(request.id, "Rejected in AgentActionReview"),
108
+ }));
109
+ }
110
+ const requests = new Map();
111
+ const resolved = new Set();
112
+ for (const event of events) {
113
+ const requestId = getAuditRequestId(event);
114
+ if (event.type === "tool.approval.requested" && requestId) {
115
+ requests.set(requestId, event);
116
+ }
117
+ if (event.type === "tool.approval.resolved" && requestId) {
118
+ resolved.add(requestId);
119
+ }
120
+ }
121
+ return [...requests.entries()]
122
+ .filter(([requestId]) => !resolved.has(requestId))
123
+ .map(([requestId, event]) => ({
124
+ id: requestId,
125
+ title: `Run ${event.toolName ?? "tool"}`,
126
+ description: asContent(event.message ?? "This tool requires confirmation before it can continue."),
127
+ command: JSON.stringify(getAuditData(event), null, 2),
128
+ subject: event.scopeId,
129
+ risk: "medium",
130
+ status: "pending",
131
+ requestedAt: event.timestamp,
132
+ metadata: {
133
+ scope: asContent(event.scopeId ?? "global"),
134
+ confirmation: asContent("required"),
135
+ },
136
+ }));
137
+ }
138
+ export function deriveActivity(events, snapshot) {
139
+ const activity = events.map((event) => ({
140
+ id: event.id,
141
+ title: event.message ?? humanizeStatus(event.type),
142
+ detail: asContent(event.toolName ?? event.type),
143
+ status: statusFromAudit(event.type),
144
+ actor: event.scopeId,
145
+ at: event.timestamp,
146
+ metadata: asContent(previewValue(event.data)),
147
+ }));
148
+ if (activity.length > 0) {
149
+ return activity.reverse();
150
+ }
151
+ return [
152
+ {
153
+ id: "snapshot-current",
154
+ title: "Context snapshot ready",
155
+ detail: asContent(`${snapshot.scopes.length} scopes, ${snapshot.tools.length} tools, ${snapshot.resources.length} resources`),
156
+ status: snapshot.scopes.length || snapshot.tools.length ? "ready" : "idle",
157
+ at: snapshot.generatedAt,
158
+ },
159
+ ];
160
+ }
161
+ export function parseCommandArgs(input) {
162
+ if (!input?.trim()) {
163
+ return {};
164
+ }
165
+ try {
166
+ return JSON.parse(input);
167
+ }
168
+ catch {
169
+ return { input };
170
+ }
171
+ }
172
+ function activeScopeTitle(snapshot) {
173
+ return snapshot.scopes[0]?.title;
174
+ }
175
+ function mapRisk(risk) {
176
+ switch (risk) {
177
+ case "destructive":
178
+ case "external":
179
+ return "high";
180
+ case "write":
181
+ return "medium";
182
+ case "draft":
183
+ case "read":
184
+ default:
185
+ return "low";
186
+ }
187
+ }
188
+ function statusFromAudit(type) {
189
+ if (type.includes("failed") || type.includes("denied")) {
190
+ return "error";
191
+ }
192
+ if (type.includes("approval")) {
193
+ return "waiting";
194
+ }
195
+ if (type.includes("executed") || type.includes("registered")) {
196
+ return "complete";
197
+ }
198
+ return "idle";
199
+ }
200
+ function getAuditData(event) {
201
+ if (!event.data || typeof event.data !== "object") {
202
+ return undefined;
203
+ }
204
+ return event.data;
205
+ }
206
+ function getAuditRequestId(event) {
207
+ const data = getAuditData(event);
208
+ const requestId = data?.requestId;
209
+ return typeof requestId === "string" ? requestId : undefined;
210
+ }
211
+ function previewValue(value) {
212
+ if (value === undefined) {
213
+ return undefined;
214
+ }
215
+ if (typeof value === "string") {
216
+ return value;
217
+ }
218
+ try {
219
+ return JSON.stringify(value);
220
+ }
221
+ catch {
222
+ return String(value);
223
+ }
224
+ }
225
+ function emptyApprovalController() {
226
+ return {
227
+ approvals: [],
228
+ approve: () => undefined,
229
+ deny: () => undefined,
230
+ };
231
+ }
232
+ function asContent(value) {
233
+ return value;
234
+ }