@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.
Files changed (125) hide show
  1. package/README.md +1 -0
  2. package/_internal/app/components/agent-select.d.ts +16 -2
  3. package/_internal/app/components/asset-picker.d.ts +25 -0
  4. package/_internal/app/components/charts/bar-chart.d.ts +16 -0
  5. package/_internal/app/components/charts/chart-data-table.d.ts +31 -0
  6. package/_internal/app/components/charts/chart-explainer.d.ts +9 -0
  7. package/_internal/app/components/charts/chart-tooltip.d.ts +8 -0
  8. package/_internal/app/components/charts/line-chart.d.ts +13 -0
  9. package/_internal/app/components/charts/palette.d.ts +24 -0
  10. package/_internal/app/components/charts/sparkline.d.ts +12 -0
  11. package/_internal/app/components/charts/stacked-column-chart.d.ts +40 -0
  12. package/_internal/app/components/confirm-dialog.d.ts +54 -0
  13. package/_internal/app/components/conversation/activity-group.d.ts +15 -0
  14. package/_internal/app/components/conversation/agent-turn.d.ts +36 -0
  15. package/_internal/app/components/conversation/attention.d.ts +56 -0
  16. package/_internal/app/components/conversation/composer.d.ts +35 -0
  17. package/_internal/app/components/conversation/conversation-empty-state.d.ts +8 -0
  18. package/_internal/app/components/conversation/conversation-panel.d.ts +33 -0
  19. package/_internal/app/components/conversation/conversation.d.ts +14 -0
  20. package/_internal/app/components/conversation/fold.d.ts +129 -0
  21. package/_internal/app/components/conversation/notification-sound.d.ts +8 -0
  22. package/_internal/app/components/conversation/relative-time.d.ts +8 -0
  23. package/_internal/app/components/conversation/reply-toast.d.ts +15 -0
  24. package/_internal/app/components/conversation/thread-id.d.ts +8 -0
  25. package/_internal/app/components/conversation/tool-call-drawer.d.ts +7 -0
  26. package/_internal/app/components/conversation/turn-recorder.d.ts +37 -0
  27. package/_internal/app/components/conversation/use-conversation-attention.d.ts +64 -0
  28. package/_internal/app/components/conversation/use-conversation-thread.d.ts +55 -0
  29. package/_internal/app/components/conversation/user-message.d.ts +11 -0
  30. package/_internal/app/components/danger-zone.d.ts +28 -0
  31. package/_internal/app/components/empty-state.d.ts +18 -6
  32. package/_internal/app/components/plugin-header.d.ts +4 -3
  33. package/_internal/app/components/save-bar.d.ts +32 -0
  34. package/_internal/app/components/score-overlay.d.ts +33 -0
  35. package/_internal/app/components/search-degraded-chip.d.ts +4 -0
  36. package/_internal/app/components/search-partial-chip.d.ts +13 -0
  37. package/_internal/app/components/search-unavailable.d.ts +12 -0
  38. package/_internal/app/components/section-card.d.ts +22 -0
  39. package/_internal/app/components/segmented-control.d.ts +28 -0
  40. package/_internal/app/components/stat-tile.d.ts +26 -0
  41. package/_internal/app/components/status-badge.d.ts +19 -0
  42. package/_internal/app/components/turn-output-view.d.ts +57 -0
  43. package/_internal/app/components/ui/badge.d.ts +1 -1
  44. package/_internal/app/components/ui/button.d.ts +1 -1
  45. package/_internal/app/components/underline-tabs.d.ts +6 -2
  46. package/_internal/app/components/unsaved-changes-guard.d.ts +34 -0
  47. package/_internal/app/core/conversation-turns.d.ts +148 -0
  48. package/_internal/app/core/logger.d.ts +1 -0
  49. package/_internal/app/hooks/use-available-models.d.ts +5 -0
  50. package/_internal/app/hooks/use-content-store.d.ts +0 -9
  51. package/_internal/app/hooks/use-file-drop.d.ts +25 -0
  52. package/_internal/app/hooks/use-history-back.d.ts +1 -0
  53. package/_internal/app/hooks/use-horizontal-resize.d.ts +22 -0
  54. package/_internal/app/hooks/use-json-fetch.d.ts +26 -0
  55. package/_internal/app/hooks/use-nav-badge.d.ts +13 -0
  56. package/_internal/app/hooks/use-plugin-event.d.ts +19 -0
  57. package/_internal/app/hooks/use-query-state.d.ts +2 -0
  58. package/_internal/app/hooks/use-resizable-pane.d.ts +35 -0
  59. package/_internal/app/hooks/use-schedule.d.ts +47 -1
  60. package/_internal/app/hooks/use-search.d.ts +27 -8
  61. package/_internal/app/hooks/use-task-run-history.d.ts +26 -0
  62. package/_internal/app/hooks/use-toast.d.ts +3 -3
  63. package/_internal/app/hooks/use-vertical-resize.d.ts +6 -7
  64. package/_internal/app/lib/browser-notify.d.ts +12 -1
  65. package/_internal/app/types/index.d.ts +1 -105
  66. package/_internal/core/adapters/runtime/concepts.d.ts +671 -99
  67. package/_internal/core/adapters/runtime/errors.d.ts +98 -0
  68. package/_internal/core/adapters/runtime/helpers.d.ts +19 -0
  69. package/_internal/core/adapters/runtime/index.d.ts +7 -2
  70. package/_internal/core/adapters/runtime/testing.d.ts +79 -0
  71. package/_internal/core/adapters/runtime/turn-activity.d.ts +23 -0
  72. package/_internal/core/adapters/shared.d.ts +122 -12
  73. package/_internal/core/content-dir.d.ts +9 -0
  74. package/_internal/core/docs/route.d.ts +1 -1
  75. package/_internal/core/format/structured.d.ts +44 -0
  76. package/_internal/core/format.d.ts +13 -0
  77. package/_internal/core/media/downscale.d.ts +18 -0
  78. package/_internal/core/media/sharp-loader.d.ts +36 -0
  79. package/_internal/core/plugin-types.d.ts +216 -499
  80. package/_internal/core/routing/define.d.ts +26 -3
  81. package/_internal/core/routing/dispatcher.d.ts +15 -6
  82. package/_internal/core/routing/index.d.ts +1 -1
  83. package/_internal/core/routing/types.d.ts +13 -70
  84. package/_internal/core/storage/atomic-write.d.ts +11 -0
  85. package/_internal/core/tasks/store.d.ts +129 -0
  86. package/_internal/core/tasks/testing.d.ts +2 -0
  87. package/_internal/{plugins/workflows/lib → core/workflows}/notification-channel-registry.d.ts +1 -1
  88. package/_internal/plugins/team/types.d.ts +61 -4
  89. package/_internal/plugins/workflows/hooks/use-notification-channels.d.ts +1 -1
  90. package/components/index.d.ts +111 -5
  91. package/components/index.js +61815 -30060
  92. package/hooks/index.d.ts +90 -9
  93. package/hooks/index.js +15181 -685
  94. package/hooks/router.d.ts +20 -4
  95. package/index.d.ts +20 -3
  96. package/index.js +297 -259
  97. package/internal/index.d.ts +70 -0
  98. package/internal/index.js +409 -0
  99. package/metadata/index.d.ts +14 -1
  100. package/package.json +9 -2
  101. package/register.d.ts +63 -9
  102. package/routing/index.d.ts +6 -1
  103. package/routing/index.js +187 -147
  104. package/slots/index.d.ts +16 -24
  105. package/slots/index.js +215 -30
  106. package/testing/index.d.ts +122 -0
  107. package/testing/index.js +21874 -0
  108. package/types/index.d.ts +19 -919
  109. package/types/index.js +16 -0
  110. package/ui/index.js +2 -1
  111. package/utils/index.d.ts +46 -6
  112. package/utils/index.js +322 -249
  113. package/_internal/app/components/integrated-brainstorm/activity.d.ts +0 -23
  114. package/_internal/app/components/integrated-brainstorm/collapsed-header.d.ts +0 -14
  115. package/_internal/app/components/integrated-brainstorm/empty-state.d.ts +0 -5
  116. package/_internal/app/components/integrated-brainstorm/index.d.ts +0 -8
  117. package/_internal/app/components/integrated-brainstorm/input-row.d.ts +0 -16
  118. package/_internal/app/components/integrated-brainstorm/message-list.d.ts +0 -8
  119. package/_internal/app/components/integrated-brainstorm/session.d.ts +0 -16
  120. package/_internal/app/components/integrated-brainstorm/sse.d.ts +0 -8
  121. package/_internal/app/components/integrated-brainstorm/thinking-indicator.d.ts +0 -19
  122. package/_internal/app/components/integrated-brainstorm/types.d.ts +0 -63
  123. package/_internal/app/components/integrated-brainstorm/use-auto-grow.d.ts +0 -6
  124. package/_internal/app/components/integrated-brainstorm/use-brainstorm-state.d.ts +0 -21
  125. 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 getRegistry() {
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 getRegistry().version;
116
+ return getRegistry2().version;
34
117
  }
35
118
  function subscribeRegistry(listener) {
36
- const registry = getRegistry();
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/slots/index.tsx
44
- import { jsxDEV, Fragment } from "react/jsx-dev-runtime";
126
+ // packages/sdk/src/lazy.ts
45
127
  "use client";
46
- function getRegistry2() {
128
+ function getStore() {
47
129
  const g = globalThis;
48
- if (!g.__bakinSlotRegistry) {
49
- g.__bakinSlotRegistry = new Map;
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.__bakinSlotRegistry;
141
+ return g.__bakinLazyPluginStore;
52
142
  }
53
- function registerSlot(name, component, order = 100, owner) {
54
- const reg = getRegistry2();
55
- const entries = reg.get(name) ?? [];
56
- entries.push({ component, order, owner });
57
- entries.sort((a, b) => a.order - b.order);
58
- reg.set(name, entries);
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 getSlotEntries(name) {
61
- return getRegistry2().get(name) ?? [];
154
+ function getPluginLoadState(pluginId) {
155
+ return getStore().states.get(pluginId) ?? "idle";
62
156
  }
63
- function clearSlotsOwnedBy(pluginId) {
64
- const reg = getRegistry2();
65
- for (const [name, entries] of reg.entries()) {
66
- const filtered = entries.filter((e) => e.owner !== pluginId);
67
- if (filtered.length === 0)
68
- reg.delete(name);
69
- else
70
- reg.set(name, filtered);
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(C, {
82
- ...props
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>;