@makinbakin/sdk 0.0.1-rc.2 → 0.0.1-rc.21
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/README.md +1 -0
- package/_internal/app/components/agent-select.d.ts +16 -2
- package/_internal/app/components/asset-picker.d.ts +25 -0
- package/_internal/app/components/charts/bar-chart.d.ts +16 -0
- package/_internal/app/components/charts/chart-data-table.d.ts +31 -0
- package/_internal/app/components/charts/chart-explainer.d.ts +9 -0
- package/_internal/app/components/charts/chart-tooltip.d.ts +8 -0
- package/_internal/app/components/charts/line-chart.d.ts +13 -0
- package/_internal/app/components/charts/palette.d.ts +24 -0
- package/_internal/app/components/charts/sparkline.d.ts +12 -0
- package/_internal/app/components/charts/stacked-column-chart.d.ts +40 -0
- package/_internal/app/components/confirm-dialog.d.ts +54 -0
- package/_internal/app/components/conversation/activity-group.d.ts +15 -0
- package/_internal/app/components/conversation/agent-turn.d.ts +36 -0
- package/_internal/app/components/conversation/attention.d.ts +56 -0
- package/_internal/app/components/conversation/composer.d.ts +35 -0
- package/_internal/app/components/conversation/conversation-empty-state.d.ts +8 -0
- package/_internal/app/components/conversation/conversation-panel.d.ts +33 -0
- package/_internal/app/components/conversation/conversation.d.ts +14 -0
- package/_internal/app/components/conversation/fold.d.ts +129 -0
- package/_internal/app/components/conversation/notification-sound.d.ts +8 -0
- package/_internal/app/components/conversation/relative-time.d.ts +8 -0
- package/_internal/app/components/conversation/reply-toast.d.ts +15 -0
- package/_internal/app/components/conversation/thread-id.d.ts +8 -0
- package/_internal/app/components/conversation/tool-call-drawer.d.ts +7 -0
- package/_internal/app/components/conversation/turn-recorder.d.ts +37 -0
- package/_internal/app/components/conversation/use-conversation-attention.d.ts +64 -0
- package/_internal/app/components/conversation/use-conversation-thread.d.ts +55 -0
- package/_internal/app/components/conversation/user-message.d.ts +11 -0
- package/_internal/app/components/danger-zone.d.ts +28 -0
- package/_internal/app/components/empty-state.d.ts +18 -6
- package/_internal/app/components/plugin-header.d.ts +4 -3
- package/_internal/app/components/save-bar.d.ts +32 -0
- package/_internal/app/components/score-overlay.d.ts +33 -0
- package/_internal/app/components/search-degraded-chip.d.ts +4 -0
- package/_internal/app/components/search-partial-chip.d.ts +13 -0
- package/_internal/app/components/search-unavailable.d.ts +12 -0
- package/_internal/app/components/section-card.d.ts +22 -0
- package/_internal/app/components/segmented-control.d.ts +28 -0
- package/_internal/app/components/stat-tile.d.ts +26 -0
- package/_internal/app/components/status-badge.d.ts +19 -0
- package/_internal/app/components/turn-output-view.d.ts +57 -0
- package/_internal/app/components/ui/badge.d.ts +1 -1
- package/_internal/app/components/ui/button.d.ts +1 -1
- package/_internal/app/components/underline-tabs.d.ts +6 -2
- package/_internal/app/components/unsaved-changes-guard.d.ts +34 -0
- package/_internal/app/core/conversation-turns.d.ts +148 -0
- package/_internal/app/core/logger.d.ts +1 -0
- package/_internal/app/hooks/use-available-models.d.ts +5 -0
- package/_internal/app/hooks/use-content-store.d.ts +0 -9
- package/_internal/app/hooks/use-file-drop.d.ts +25 -0
- package/_internal/app/hooks/use-history-back.d.ts +1 -0
- package/_internal/app/hooks/use-horizontal-resize.d.ts +22 -0
- package/_internal/app/hooks/use-json-fetch.d.ts +26 -0
- package/_internal/app/hooks/use-nav-badge.d.ts +13 -0
- package/_internal/app/hooks/use-plugin-event.d.ts +19 -0
- package/_internal/app/hooks/use-query-state.d.ts +2 -0
- package/_internal/app/hooks/use-resizable-pane.d.ts +35 -0
- package/_internal/app/hooks/use-schedule.d.ts +47 -1
- package/_internal/app/hooks/use-search.d.ts +27 -8
- package/_internal/app/hooks/use-task-run-history.d.ts +26 -0
- package/_internal/app/hooks/use-toast.d.ts +3 -3
- package/_internal/app/hooks/use-vertical-resize.d.ts +6 -7
- package/_internal/app/lib/browser-notify.d.ts +12 -1
- package/_internal/app/types/index.d.ts +1 -105
- package/_internal/core/adapters/runtime/concepts.d.ts +671 -99
- package/_internal/core/adapters/runtime/errors.d.ts +98 -0
- package/_internal/core/adapters/runtime/helpers.d.ts +19 -0
- package/_internal/core/adapters/runtime/index.d.ts +7 -2
- package/_internal/core/adapters/runtime/testing.d.ts +79 -0
- package/_internal/core/adapters/runtime/turn-activity.d.ts +23 -0
- package/_internal/core/adapters/shared.d.ts +122 -12
- package/_internal/core/content-dir.d.ts +9 -0
- package/_internal/core/docs/route.d.ts +1 -1
- package/_internal/core/format/structured.d.ts +44 -0
- package/_internal/core/format.d.ts +13 -0
- package/_internal/core/media/downscale.d.ts +18 -0
- package/_internal/core/media/sharp-loader.d.ts +36 -0
- package/_internal/core/plugin-types.d.ts +216 -499
- package/_internal/core/routing/define.d.ts +26 -3
- package/_internal/core/routing/dispatcher.d.ts +15 -6
- package/_internal/core/routing/index.d.ts +1 -1
- package/_internal/core/routing/types.d.ts +13 -70
- package/_internal/core/storage/atomic-write.d.ts +11 -0
- package/_internal/core/tasks/store.d.ts +129 -0
- package/_internal/core/tasks/testing.d.ts +2 -0
- package/_internal/{plugins/workflows/lib → core/workflows}/notification-channel-registry.d.ts +1 -1
- package/_internal/plugins/team/types.d.ts +61 -4
- package/_internal/plugins/workflows/hooks/use-notification-channels.d.ts +1 -1
- package/components/index.d.ts +111 -5
- package/components/index.js +61815 -30060
- package/hooks/index.d.ts +90 -9
- package/hooks/index.js +15181 -685
- package/hooks/router.d.ts +20 -4
- package/index.d.ts +20 -3
- package/index.js +297 -259
- package/internal/index.d.ts +70 -0
- package/internal/index.js +409 -0
- package/metadata/index.d.ts +14 -1
- package/package.json +9 -2
- package/register.d.ts +63 -9
- package/routing/index.d.ts +6 -1
- package/routing/index.js +187 -147
- package/slots/index.d.ts +16 -24
- package/slots/index.js +215 -30
- package/testing/index.d.ts +122 -0
- package/testing/index.js +21874 -0
- package/types/index.d.ts +19 -919
- package/types/index.js +16 -0
- package/ui/index.js +2 -1
- package/utils/index.d.ts +46 -6
- package/utils/index.js +322 -249
- package/_internal/app/components/integrated-brainstorm/activity.d.ts +0 -23
- package/_internal/app/components/integrated-brainstorm/collapsed-header.d.ts +0 -14
- package/_internal/app/components/integrated-brainstorm/empty-state.d.ts +0 -5
- package/_internal/app/components/integrated-brainstorm/index.d.ts +0 -8
- package/_internal/app/components/integrated-brainstorm/input-row.d.ts +0 -16
- package/_internal/app/components/integrated-brainstorm/message-list.d.ts +0 -8
- package/_internal/app/components/integrated-brainstorm/session.d.ts +0 -16
- package/_internal/app/components/integrated-brainstorm/sse.d.ts +0 -8
- package/_internal/app/components/integrated-brainstorm/thinking-indicator.d.ts +0 -19
- package/_internal/app/components/integrated-brainstorm/types.d.ts +0 -63
- package/_internal/app/components/integrated-brainstorm/use-auto-grow.d.ts +0 -6
- package/_internal/app/components/integrated-brainstorm/use-brainstorm-state.d.ts +0 -21
- package/_internal/app/hooks/use-assets.d.ts +0 -25
package/slots/index.js
CHANGED
|
@@ -1,91 +1,276 @@
|
|
|
1
1
|
// @bun
|
|
2
2
|
// packages/sdk/src/slots/index.tsx
|
|
3
|
-
import { useSyncExternalStore } from "react";
|
|
3
|
+
import { Component, useEffect, useSyncExternalStore } from "react";
|
|
4
|
+
|
|
5
|
+
// packages/sdk/src/slots/registry.ts
|
|
6
|
+
function getRegistry() {
|
|
7
|
+
const g = globalThis;
|
|
8
|
+
if (!g.__bakinSlotRegistry) {
|
|
9
|
+
g.__bakinSlotRegistry = new Map;
|
|
10
|
+
}
|
|
11
|
+
return g.__bakinSlotRegistry;
|
|
12
|
+
}
|
|
13
|
+
function registerSlot(name, component, order = 100, owner) {
|
|
14
|
+
const reg = getRegistry();
|
|
15
|
+
const entries = reg.get(name) ?? [];
|
|
16
|
+
entries.push({ component, order, owner });
|
|
17
|
+
entries.sort((a, b) => a.order - b.order);
|
|
18
|
+
reg.set(name, entries);
|
|
19
|
+
}
|
|
20
|
+
function getSlotEntries(name) {
|
|
21
|
+
return getRegistry().get(name) ?? [];
|
|
22
|
+
}
|
|
23
|
+
function getSlotNamesOwnedBy(pluginId) {
|
|
24
|
+
const names = [];
|
|
25
|
+
for (const [name, entries] of getRegistry().entries()) {
|
|
26
|
+
if (entries.some((e) => e.owner === pluginId))
|
|
27
|
+
names.push(name);
|
|
28
|
+
}
|
|
29
|
+
return names;
|
|
30
|
+
}
|
|
31
|
+
function clearSlotsOwnedBy(pluginId) {
|
|
32
|
+
const reg = getRegistry();
|
|
33
|
+
for (const [name, entries] of reg.entries()) {
|
|
34
|
+
const filtered = entries.filter((e) => e.owner !== pluginId);
|
|
35
|
+
if (filtered.length === 0)
|
|
36
|
+
reg.delete(name);
|
|
37
|
+
else
|
|
38
|
+
reg.set(name, filtered);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
4
41
|
|
|
5
42
|
// packages/sdk/src/register.ts
|
|
6
43
|
"use client";
|
|
7
44
|
function buildNavItemsSnapshot(registry) {
|
|
8
45
|
const items = [];
|
|
46
|
+
for (const [pluginId, navItems] of registry.manifestNavByPlugin.entries()) {
|
|
47
|
+
if (registry.navByPlugin.has(pluginId))
|
|
48
|
+
continue;
|
|
49
|
+
items.push(...navItems);
|
|
50
|
+
}
|
|
9
51
|
for (const navItems of registry.navByPlugin.values()) {
|
|
10
52
|
items.push(...navItems);
|
|
11
53
|
}
|
|
12
54
|
return items.sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
|
|
13
55
|
}
|
|
14
|
-
function
|
|
56
|
+
function getRegistry2() {
|
|
15
57
|
const g = globalThis;
|
|
16
58
|
if (!g.__bakinClientRegistry) {
|
|
17
59
|
g.__bakinClientRegistry = {
|
|
18
60
|
navByPlugin: new Map,
|
|
61
|
+
manifestNavByPlugin: new Map,
|
|
19
62
|
routesByPlugin: new Map,
|
|
20
63
|
cleanupByPlugin: new Map,
|
|
21
64
|
navItemsSnapshot: [],
|
|
22
65
|
version: 0,
|
|
23
|
-
listeners: new Set
|
|
66
|
+
listeners: new Set,
|
|
67
|
+
badgesByPlugin: new Map,
|
|
68
|
+
badgesSnapshot: new Map,
|
|
69
|
+
badgeListeners: new Set,
|
|
70
|
+
hitRenderersByPlugin: new Map,
|
|
71
|
+
hitRenderersSnapshot: new Map,
|
|
72
|
+
hitRendererListeners: new Set
|
|
24
73
|
};
|
|
25
74
|
}
|
|
26
75
|
const registry = g.__bakinClientRegistry;
|
|
76
|
+
if (!registry.manifestNavByPlugin)
|
|
77
|
+
registry.manifestNavByPlugin = new Map;
|
|
27
78
|
if (!Array.isArray(registry.navItemsSnapshot)) {
|
|
28
79
|
registry.navItemsSnapshot = buildNavItemsSnapshot(registry);
|
|
29
80
|
}
|
|
81
|
+
if (!registry.badgesByPlugin)
|
|
82
|
+
registry.badgesByPlugin = new Map;
|
|
83
|
+
if (!registry.badgesSnapshot)
|
|
84
|
+
registry.badgesSnapshot = buildBadgesSnapshot(registry);
|
|
85
|
+
if (!registry.badgeListeners)
|
|
86
|
+
registry.badgeListeners = new Set;
|
|
87
|
+
if (!registry.hitRenderersByPlugin)
|
|
88
|
+
registry.hitRenderersByPlugin = new Map;
|
|
89
|
+
if (!registry.hitRenderersSnapshot)
|
|
90
|
+
registry.hitRenderersSnapshot = buildHitRenderersSnapshot(registry);
|
|
91
|
+
if (!registry.hitRendererListeners)
|
|
92
|
+
registry.hitRendererListeners = new Set;
|
|
30
93
|
return registry;
|
|
31
94
|
}
|
|
95
|
+
function buildHitRenderersSnapshot(registry) {
|
|
96
|
+
const snapshot = new Map;
|
|
97
|
+
for (const byType of registry.hitRenderersByPlugin.values()) {
|
|
98
|
+
for (const [type, renderer] of byType) {
|
|
99
|
+
if (!snapshot.has(type))
|
|
100
|
+
snapshot.set(type, renderer);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return snapshot;
|
|
104
|
+
}
|
|
105
|
+
function buildBadgesSnapshot(registry) {
|
|
106
|
+
const snapshot = new Map;
|
|
107
|
+
for (const byNavItemId of registry.badgesByPlugin.values()) {
|
|
108
|
+
for (const [navItemId, badge] of byNavItemId) {
|
|
109
|
+
if (!snapshot.has(navItemId))
|
|
110
|
+
snapshot.set(navItemId, badge);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return snapshot;
|
|
114
|
+
}
|
|
32
115
|
function getRegistryVersion() {
|
|
33
|
-
return
|
|
116
|
+
return getRegistry2().version;
|
|
34
117
|
}
|
|
35
118
|
function subscribeRegistry(listener) {
|
|
36
|
-
const registry =
|
|
119
|
+
const registry = getRegistry2();
|
|
37
120
|
registry.listeners.add(listener);
|
|
38
121
|
return () => {
|
|
39
122
|
registry.listeners.delete(listener);
|
|
40
123
|
};
|
|
41
124
|
}
|
|
42
125
|
|
|
43
|
-
// packages/sdk/src/
|
|
44
|
-
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
|
|
126
|
+
// packages/sdk/src/lazy.ts
|
|
45
127
|
"use client";
|
|
46
|
-
function
|
|
128
|
+
function getStore() {
|
|
47
129
|
const g = globalThis;
|
|
48
|
-
if (!g.
|
|
49
|
-
g.
|
|
130
|
+
if (!g.__bakinLazyPluginStore) {
|
|
131
|
+
g.__bakinLazyPluginStore = {
|
|
132
|
+
ownersBySlot: new Map,
|
|
133
|
+
routeOwners: [],
|
|
134
|
+
states: new Map,
|
|
135
|
+
errors: new Map,
|
|
136
|
+
loader: null,
|
|
137
|
+
version: 0,
|
|
138
|
+
listeners: new Set
|
|
139
|
+
};
|
|
50
140
|
}
|
|
51
|
-
return g.
|
|
141
|
+
return g.__bakinLazyPluginStore;
|
|
52
142
|
}
|
|
53
|
-
function
|
|
54
|
-
const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
143
|
+
function bump() {
|
|
144
|
+
const store = getStore();
|
|
145
|
+
store.version++;
|
|
146
|
+
for (const l of store.listeners) {
|
|
147
|
+
try {
|
|
148
|
+
l();
|
|
149
|
+
} catch (err) {
|
|
150
|
+
console.error("[bakin] lazy-plugin listener threw:", err);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
59
153
|
}
|
|
60
|
-
function
|
|
61
|
-
return
|
|
154
|
+
function getPluginLoadState(pluginId) {
|
|
155
|
+
return getStore().states.get(pluginId) ?? "idle";
|
|
62
156
|
}
|
|
63
|
-
function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
157
|
+
function getPluginLoadError(pluginId) {
|
|
158
|
+
return getStore().errors.get(pluginId);
|
|
159
|
+
}
|
|
160
|
+
function getSlotOwners(name) {
|
|
161
|
+
return getStore().ownersBySlot.get(name) ?? [];
|
|
162
|
+
}
|
|
163
|
+
function demand(pluginIds) {
|
|
164
|
+
const store = getStore();
|
|
165
|
+
if (!store.loader)
|
|
166
|
+
return;
|
|
167
|
+
for (const pluginId of pluginIds) {
|
|
168
|
+
if ((store.states.get(pluginId) ?? "idle") !== "idle")
|
|
169
|
+
continue;
|
|
170
|
+
store.loader(pluginId);
|
|
71
171
|
}
|
|
72
172
|
}
|
|
173
|
+
function requestSlotPlugins(name) {
|
|
174
|
+
demand(getSlotOwners(name));
|
|
175
|
+
}
|
|
176
|
+
function retryPluginLoad(pluginId) {
|
|
177
|
+
const store = getStore();
|
|
178
|
+
if (store.states.get(pluginId) !== "error")
|
|
179
|
+
return;
|
|
180
|
+
store.states.set(pluginId, "idle");
|
|
181
|
+
store.errors.delete(pluginId);
|
|
182
|
+
bump();
|
|
183
|
+
demand([pluginId]);
|
|
184
|
+
}
|
|
185
|
+
function getLazyPluginsVersion() {
|
|
186
|
+
return getStore().version;
|
|
187
|
+
}
|
|
188
|
+
function subscribeLazyPlugins(listener) {
|
|
189
|
+
const store = getStore();
|
|
190
|
+
store.listeners.add(listener);
|
|
191
|
+
return () => {
|
|
192
|
+
store.listeners.delete(listener);
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// packages/sdk/src/slots/index.tsx
|
|
196
|
+
import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
|
|
197
|
+
"use client";
|
|
198
|
+
|
|
199
|
+
class SlotEntryBoundary extends Component {
|
|
200
|
+
state = { error: null };
|
|
201
|
+
static getDerivedStateFromError(error) {
|
|
202
|
+
return { error };
|
|
203
|
+
}
|
|
204
|
+
componentDidCatch(error) {
|
|
205
|
+
console.error(`[bakin] slot "${this.props.slotName}" entry${this.props.owner ? ` from plugin "${this.props.owner}"` : ""} crashed:`, error);
|
|
206
|
+
}
|
|
207
|
+
render() {
|
|
208
|
+
if (this.state.error) {
|
|
209
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
210
|
+
className: "rounded-md border border-destructive/40 bg-destructive/10 px-3 py-2 text-xs text-destructive",
|
|
211
|
+
role: "alert",
|
|
212
|
+
children: [
|
|
213
|
+
this.props.owner ? `Plugin "${this.props.owner}"` : "A plugin",
|
|
214
|
+
" failed to render this section."
|
|
215
|
+
]
|
|
216
|
+
}, undefined, true, undefined, this);
|
|
217
|
+
}
|
|
218
|
+
return this.props.children;
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function SlotLoadError({ slotName, pluginIds }) {
|
|
222
|
+
return /* @__PURE__ */ jsxDEV("div", {
|
|
223
|
+
className: "flex flex-col items-start gap-2 rounded-md border border-destructive/40 bg-destructive/10 px-4 py-3 text-sm text-destructive",
|
|
224
|
+
role: "alert",
|
|
225
|
+
children: [
|
|
226
|
+
/* @__PURE__ */ jsxDEV("span", {
|
|
227
|
+
children: [
|
|
228
|
+
pluginIds.length === 1 ? `Plugin "${pluginIds[0]}" failed to load` : `Plugins ${pluginIds.map((id) => `"${id}"`).join(", ")} failed to load`,
|
|
229
|
+
getPluginLoadError(pluginIds[0]) ? ` \u2014 ${getPluginLoadError(pluginIds[0])}` : ""
|
|
230
|
+
]
|
|
231
|
+
}, undefined, true, undefined, this),
|
|
232
|
+
/* @__PURE__ */ jsxDEV("button", {
|
|
233
|
+
type: "button",
|
|
234
|
+
className: "rounded border border-destructive/40 px-2 py-1 text-xs hover:bg-destructive/20",
|
|
235
|
+
onClick: () => pluginIds.forEach(retryPluginLoad),
|
|
236
|
+
"aria-label": `Retry loading ${slotName}`,
|
|
237
|
+
children: "Retry"
|
|
238
|
+
}, undefined, false, undefined, this)
|
|
239
|
+
]
|
|
240
|
+
}, undefined, true, undefined, this);
|
|
241
|
+
}
|
|
73
242
|
function Slot({ name, ...props }) {
|
|
74
243
|
useSyncExternalStore(subscribeRegistry, getRegistryVersion, getRegistryVersion);
|
|
244
|
+
useSyncExternalStore(subscribeLazyPlugins, getLazyPluginsVersion, getLazyPluginsVersion);
|
|
245
|
+
useEffect(() => {
|
|
246
|
+
requestSlotPlugins(name);
|
|
247
|
+
}, [name]);
|
|
75
248
|
const entries = getSlotEntries(name);
|
|
76
|
-
if (entries.length === 0)
|
|
249
|
+
if (entries.length === 0) {
|
|
250
|
+
const failed = getSlotOwners(name).filter((id) => getPluginLoadState(id) === "error");
|
|
251
|
+
if (failed.length > 0)
|
|
252
|
+
return /* @__PURE__ */ jsxDEV(SlotLoadError, {
|
|
253
|
+
slotName: name,
|
|
254
|
+
pluginIds: [...failed]
|
|
255
|
+
}, undefined, false, undefined, this);
|
|
77
256
|
return null;
|
|
257
|
+
}
|
|
78
258
|
return /* @__PURE__ */ jsxDEV(Fragment, {
|
|
79
259
|
children: entries.map((entry, i) => {
|
|
80
260
|
const C = entry.component;
|
|
81
|
-
return /* @__PURE__ */ jsxDEV(
|
|
82
|
-
|
|
261
|
+
return /* @__PURE__ */ jsxDEV(SlotEntryBoundary, {
|
|
262
|
+
owner: entry.owner,
|
|
263
|
+
slotName: name,
|
|
264
|
+
children: /* @__PURE__ */ jsxDEV(C, {
|
|
265
|
+
...props
|
|
266
|
+
}, undefined, false, undefined, this)
|
|
83
267
|
}, `${name}-${i}`, false, undefined, this);
|
|
84
268
|
})
|
|
85
269
|
}, undefined, false, undefined, this);
|
|
86
270
|
}
|
|
87
271
|
export {
|
|
88
272
|
registerSlot,
|
|
273
|
+
getSlotNamesOwnedBy,
|
|
89
274
|
getSlotEntries,
|
|
90
275
|
clearSlotsOwnedBy,
|
|
91
276
|
Slot
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
import type { BakinPlugin, ExecToolDefinition, ExecToolResult, HealthCheckRegistrationInput, HealthRepairActionDefinition, NavItem, PluginContext, PluginNodeTypeInput, PluginNotificationChannelInput, PluginToolContext, SearchResponse, SearchResult, SkillDefinition, UISlotRegistration, WorkflowDefinitionInput } from '../types/index';
|
|
2
|
+
import type { APIRoute } from '../routing/index';
|
|
3
|
+
/** One captured `ctx.log` line. */
|
|
4
|
+
export interface CapturedLog {
|
|
5
|
+
level: 'debug' | 'info' | 'warn' | 'error';
|
|
6
|
+
message: string;
|
|
7
|
+
data?: unknown;
|
|
8
|
+
}
|
|
9
|
+
/** One captured `ctx.activity.log` / `ctx.activity.audit` call. */
|
|
10
|
+
export interface CapturedActivity {
|
|
11
|
+
kind: 'log' | 'audit';
|
|
12
|
+
agent: string;
|
|
13
|
+
message: string;
|
|
14
|
+
data?: Record<string, unknown>;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* The harness returned by {@link createTestContext} / {@link activatePlugin}.
|
|
18
|
+
* Everything the plugin registered is captured on plain arrays so tests can
|
|
19
|
+
* assert on it directly.
|
|
20
|
+
*/
|
|
21
|
+
export interface PluginTestContext {
|
|
22
|
+
/** The isolated context — pass to `callRoute`, or to the plugin directly. */
|
|
23
|
+
ctx: PluginContext;
|
|
24
|
+
/** All routes: declarative `plugin.routes` + the auto-wired search route. */
|
|
25
|
+
routes: APIRoute[];
|
|
26
|
+
/** Exec tools registered via `ctx.registerExecTool`. */
|
|
27
|
+
execTools: ExecToolDefinition[];
|
|
28
|
+
/** Nav items registered via `ctx.registerNav`. */
|
|
29
|
+
navItems: NavItem[];
|
|
30
|
+
/** Slot registrations via `ctx.registerSlot`. */
|
|
31
|
+
slots: UISlotRegistration[];
|
|
32
|
+
/** Workflows registered via `ctx.registerWorkflow`. */
|
|
33
|
+
workflows: WorkflowDefinitionInput[];
|
|
34
|
+
/** Node types registered via `ctx.registerNodeType`. */
|
|
35
|
+
nodeTypes: PluginNodeTypeInput<unknown>[];
|
|
36
|
+
/** Notification channels registered via `ctx.registerNotificationChannel`. */
|
|
37
|
+
notificationChannels: PluginNotificationChannelInput[];
|
|
38
|
+
/** Health checks registered via `ctx.registerHealthCheck`. */
|
|
39
|
+
healthChecks: HealthCheckRegistrationInput[];
|
|
40
|
+
/** Repair actions registered via `ctx.registerHealthRepairAction`. */
|
|
41
|
+
healthRepairActions: HealthRepairActionDefinition[];
|
|
42
|
+
/** Runtime skills registered via `ctx.registerSkill`. */
|
|
43
|
+
skills: SkillDefinition[];
|
|
44
|
+
/** File-watch patterns passed to `ctx.watchFiles`. */
|
|
45
|
+
watchedPatterns: string[];
|
|
46
|
+
/** Everything logged through `ctx.log`. */
|
|
47
|
+
logs: CapturedLog[];
|
|
48
|
+
/** Everything sent to `ctx.activity`. */
|
|
49
|
+
activity: CapturedActivity[];
|
|
50
|
+
/** Absolute path of the temp directory backing `ctx.storage`. */
|
|
51
|
+
dir: string;
|
|
52
|
+
/**
|
|
53
|
+
* Seed `ctx.search.query()` responses. All subsequent queries return these
|
|
54
|
+
* results until re-seeded.
|
|
55
|
+
*/
|
|
56
|
+
seedSearchResults(results: SearchResult[], aggregations?: SearchResponse['aggregations']): void;
|
|
57
|
+
/** Build the `PluginToolContext` an exec tool receives as its third arg. */
|
|
58
|
+
toolContext(): PluginToolContext;
|
|
59
|
+
/** Delete the temp directory. Call from `afterAll`. Safe to call twice. */
|
|
60
|
+
dispose(): void;
|
|
61
|
+
}
|
|
62
|
+
export interface CreateTestContextOptions {
|
|
63
|
+
/** Initial `ctx.getSettings()` value. `ctx.updateSettings` patches it. */
|
|
64
|
+
settings?: Record<string, unknown>;
|
|
65
|
+
/**
|
|
66
|
+
* Use this directory instead of a fresh temp dir. The harness will NOT
|
|
67
|
+
* delete a caller-provided directory on `dispose()`.
|
|
68
|
+
*/
|
|
69
|
+
dir?: string;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Create an isolated `PluginContext` for `pluginId`.
|
|
73
|
+
*
|
|
74
|
+
* Storage is a real filesystem adapter rooted at a fresh temp directory;
|
|
75
|
+
* events are a real in-process bus; hooks are a local registry (the plugin
|
|
76
|
+
* can invoke its own hooks); runtime/tasks are the SDK mock implementations;
|
|
77
|
+
* search is seedable via `seedSearchResults`. Registration calls are
|
|
78
|
+
* captured, never applied to any global registry.
|
|
79
|
+
*/
|
|
80
|
+
export declare function createTestContext(pluginId: string, options?: CreateTestContextOptions): PluginTestContext;
|
|
81
|
+
/**
|
|
82
|
+
* Activate a plugin against a fresh test context. Declarative `plugin.routes`
|
|
83
|
+
* are collected first (as the host does), then `activate(ctx)` runs and its
|
|
84
|
+
* registrations land on the same arrays.
|
|
85
|
+
*/
|
|
86
|
+
export declare function activatePlugin(plugin: BakinPlugin, options?: CreateTestContextOptions): Promise<PluginTestContext>;
|
|
87
|
+
/** Find a route by method and declared path (`'GET', '/items/:id'`). */
|
|
88
|
+
export declare function findRoute(routes: APIRoute[], method: string, path: string): APIRoute | undefined;
|
|
89
|
+
/** Find an exec tool by name. */
|
|
90
|
+
export declare function findTool(tools: ExecToolDefinition[], name: string): ExecToolDefinition | undefined;
|
|
91
|
+
/** Build a `Request` the way the host's router would. */
|
|
92
|
+
export declare function makeRequest(path: string, opts?: {
|
|
93
|
+
method?: string;
|
|
94
|
+
body?: unknown;
|
|
95
|
+
searchParams?: Record<string, string>;
|
|
96
|
+
}): Request;
|
|
97
|
+
/**
|
|
98
|
+
* Call a route handler and return `{ status, body, response }`.
|
|
99
|
+
*
|
|
100
|
+
* Routes that declare typed contracts (`params`/`query`/`body`/`responses`)
|
|
101
|
+
* dispatch through the same router the host uses, so schema validation and
|
|
102
|
+
* the `(req, ctx, parsed)` handler signature behave exactly as in
|
|
103
|
+
* production. Path params resolve from `opts.path` (`'/abc-1/move'` binds
|
|
104
|
+
* `:taskId` for a route at `'/:taskId/move'`) or from `opts.searchParams`
|
|
105
|
+
* entries matching placeholder names.
|
|
106
|
+
*/
|
|
107
|
+
export declare function callRoute(route: APIRoute, ctx: PluginContext, opts?: {
|
|
108
|
+
path?: string;
|
|
109
|
+
body?: unknown;
|
|
110
|
+
searchParams?: Record<string, string>;
|
|
111
|
+
rawResponse?: boolean;
|
|
112
|
+
}): Promise<{
|
|
113
|
+
status: number;
|
|
114
|
+
body: Record<string, unknown>;
|
|
115
|
+
response: Response;
|
|
116
|
+
}>;
|
|
117
|
+
/**
|
|
118
|
+
* Call an exec tool handler. Pass `toolCtx` (from `harness.toolContext()`)
|
|
119
|
+
* when the tool uses its third argument — scaffold-style tools that persist
|
|
120
|
+
* via `toolCtx.storage` need it.
|
|
121
|
+
*/
|
|
122
|
+
export declare function callTool(tool: ExecToolDefinition, params: Record<string, unknown>, agent?: string, toolCtx?: PluginToolContext): Promise<ExecToolResult>;
|