@iloveagents/foundry-web-ui 0.3.1 → 0.5.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.
Files changed (227) hide show
  1. package/README.md +13 -4
  2. package/dist/components/ag-ui-runtime-provider.d.ts +64 -0
  3. package/dist/components/ag-ui-runtime-provider.js +71 -0
  4. package/dist/components/app-brand.d.ts +6 -0
  5. package/dist/components/app-brand.js +13 -0
  6. package/dist/components/assistant-chat.d.ts +26 -0
  7. package/dist/components/assistant-chat.js +94 -0
  8. package/dist/components/chat-attachments.d.ts +25 -0
  9. package/dist/components/chat-attachments.js +20 -0
  10. package/dist/components/chat-bubble.d.ts +1 -0
  11. package/dist/components/chat-bubble.js +105 -0
  12. package/dist/components/chat-header.d.ts +2 -0
  13. package/dist/components/chat-header.js +16 -0
  14. package/dist/components/client-tool-executor.d.ts +12 -0
  15. package/dist/components/client-tool-executor.js +108 -0
  16. package/dist/components/collection-empty-state.d.ts +9 -0
  17. package/dist/components/collection-empty-state.js +6 -0
  18. package/dist/components/collection-filter-bar.d.ts +19 -0
  19. package/dist/components/collection-filter-bar.js +28 -0
  20. package/dist/components/collection-search-input.d.ts +6 -0
  21. package/dist/components/collection-search-input.js +8 -0
  22. package/dist/components/collection-skeleton.d.ts +6 -0
  23. package/dist/components/collection-skeleton.js +10 -0
  24. package/dist/components/collection-sort-menu.d.ts +10 -0
  25. package/dist/components/collection-sort-menu.js +9 -0
  26. package/dist/components/collection-surface.d.ts +8 -0
  27. package/dist/components/collection-surface.js +5 -0
  28. package/dist/components/collection-toolbar.d.ts +9 -0
  29. package/dist/components/collection-toolbar.js +5 -0
  30. package/dist/components/collection-view-toggle.d.ts +7 -0
  31. package/dist/components/collection-view-toggle.js +17 -0
  32. package/dist/components/composer-submit-bridge.d.ts +1 -0
  33. package/dist/components/composer-submit-bridge.js +15 -0
  34. package/dist/components/confirm-dialog.d.ts +11 -0
  35. package/dist/components/confirm-dialog.js +6 -0
  36. package/dist/components/confirmation-card.d.ts +14 -0
  37. package/dist/components/confirmation-card.js +12 -0
  38. package/dist/components/context-badges.d.ts +16 -0
  39. package/dist/components/context-badges.js +56 -0
  40. package/dist/components/context-bar.d.ts +41 -0
  41. package/dist/components/context-bar.js +123 -0
  42. package/dist/components/form-dialog.d.ts +12 -0
  43. package/dist/components/form-dialog.js +13 -0
  44. package/dist/components/global-selection-popover.d.ts +7 -0
  45. package/dist/components/global-selection-popover.js +167 -0
  46. package/dist/components/infinite-scroll-sentinel.d.ts +6 -0
  47. package/dist/components/infinite-scroll-sentinel.js +25 -0
  48. package/dist/components/json-viewer.d.ts +10 -0
  49. package/dist/components/json-viewer.js +80 -0
  50. package/dist/components/loading-indicator.d.ts +13 -0
  51. package/dist/components/loading-indicator.js +35 -0
  52. package/dist/components/markdown-text.d.ts +13 -0
  53. package/dist/components/markdown-text.js +221 -0
  54. package/dist/components/message-error.d.ts +10 -0
  55. package/dist/components/message-error.js +10 -0
  56. package/dist/components/message-timestamp.d.ts +10 -0
  57. package/dist/components/message-timestamp.js +18 -0
  58. package/dist/components/name-dialog.d.ts +16 -0
  59. package/dist/components/name-dialog.js +23 -0
  60. package/dist/components/selection-popover.d.ts +12 -0
  61. package/dist/components/selection-popover.js +111 -0
  62. package/dist/components/show-document-tool-ui.d.ts +1 -0
  63. package/dist/components/show-document-tool-ui.js +53 -0
  64. package/dist/components/sidebar.d.ts +4 -0
  65. package/dist/components/sidebar.js +904 -0
  66. package/dist/components/surface-card.d.ts +9 -0
  67. package/dist/components/surface-card.js +33 -0
  68. package/dist/components/theme-runtime-provider.d.ts +15 -0
  69. package/dist/components/theme-runtime-provider.js +48 -0
  70. package/dist/components/theme-toggle.d.ts +2 -0
  71. package/dist/components/theme-toggle.js +19 -0
  72. package/dist/components/tool-call-card.d.ts +27 -0
  73. package/dist/components/tool-call-card.js +13 -0
  74. package/dist/components/tool-fallback.d.ts +26 -0
  75. package/dist/components/tool-fallback.js +129 -0
  76. package/dist/components/tool-panel-layout.d.ts +10 -0
  77. package/dist/components/tool-panel-layout.js +12 -0
  78. package/dist/components/tool-panel.d.ts +1 -0
  79. package/dist/components/tool-panel.js +89 -0
  80. package/dist/components/tooltip-icon-button.d.ts +7 -0
  81. package/dist/components/tooltip-icon-button.js +9 -0
  82. package/dist/components/user-menu.d.ts +2 -0
  83. package/dist/components/user-menu.js +14 -0
  84. package/dist/index.d.ts +68 -0
  85. package/dist/index.js +83 -0
  86. package/dist/lib/ag-ui-adapter.d.ts +29 -0
  87. package/dist/lib/ag-ui-adapter.js +382 -0
  88. package/dist/lib/app-store.d.ts +115 -0
  89. package/dist/lib/app-store.js +199 -0
  90. package/dist/lib/attachment-adapter.d.ts +20 -0
  91. package/dist/lib/attachment-adapter.js +99 -0
  92. package/dist/lib/auth-provider.d.ts +16 -0
  93. package/dist/lib/auth-provider.js +88 -0
  94. package/dist/lib/chat-bubble-store.d.ts +30 -0
  95. package/dist/lib/chat-bubble-store.js +23 -0
  96. package/dist/lib/chat-lifecycle-store.d.ts +10 -0
  97. package/{src/lib/chat-lifecycle-store.ts → dist/lib/chat-lifecycle-store.js} +3 -13
  98. package/dist/lib/client-tools.d.ts +11 -0
  99. package/dist/lib/client-tools.js +274 -0
  100. package/dist/lib/composer-submit-store.d.ts +12 -0
  101. package/dist/lib/composer-submit-store.js +17 -0
  102. package/dist/lib/dev-store.d.ts +38 -0
  103. package/dist/lib/dev-store.js +32 -0
  104. package/dist/lib/nav-config.d.ts +159 -0
  105. package/dist/lib/nav-config.js +162 -0
  106. package/dist/lib/nav-dnd.d.ts +8 -0
  107. package/dist/lib/nav-dnd.js +9 -0
  108. package/dist/lib/nav-store.d.ts +45 -0
  109. package/dist/lib/nav-store.js +49 -0
  110. package/dist/lib/selection-context.d.ts +21 -0
  111. package/dist/lib/selection-context.js +34 -0
  112. package/dist/lib/sidebar-store.d.ts +23 -0
  113. package/dist/lib/sidebar-store.js +98 -0
  114. package/dist/lib/theme-runtime.d.ts +130 -0
  115. package/dist/lib/theme-runtime.js +479 -0
  116. package/dist/lib/theme-store.d.ts +15 -0
  117. package/dist/lib/theme-store.js +53 -0
  118. package/dist/lib/tool-panel-store.d.ts +48 -0
  119. package/dist/lib/tool-panel-store.js +69 -0
  120. package/dist/lib/use-new-conversation.d.ts +8 -0
  121. package/dist/lib/use-new-conversation.js +62 -0
  122. package/dist/lib/use-page-tools.d.ts +27 -0
  123. package/{src/lib/use-page-tools.ts → dist/lib/use-page-tools.js} +11 -13
  124. package/dist/styles.css +142 -0
  125. package/dist/ui/collapsible.d.ts +5 -0
  126. package/{src/ui/collapsible.tsx → dist/ui/collapsible.js} +0 -2
  127. package/dist/ui/dialog.d.ts +15 -0
  128. package/dist/ui/dialog.js +25 -0
  129. package/dist/ui/dropdown-menu.d.ts +7 -0
  130. package/dist/ui/dropdown-menu.js +19 -0
  131. package/dist/ui/popover.d.ts +7 -0
  132. package/dist/ui/popover.js +10 -0
  133. package/dist/ui/select.d.ts +4 -0
  134. package/dist/ui/select.js +9 -0
  135. package/dist/ui/tooltip.d.ts +7 -0
  136. package/dist/ui/tooltip.js +10 -0
  137. package/package.json +31 -12
  138. package/AGENTS.md +0 -59
  139. package/CHANGELOG.md +0 -211
  140. package/CLAUDE.md +0 -1
  141. package/src/__tests__/no-spaces-imports.test.ts +0 -59
  142. package/src/__tests__/open-core-guards.test.ts +0 -307
  143. package/src/__tests__/theme-runtime.test.ts +0 -81
  144. package/src/__tests__/tool-fallback.test.tsx +0 -109
  145. package/src/components/__tests__/context-bar.test.ts +0 -112
  146. package/src/components/ag-ui-runtime-provider.tsx +0 -170
  147. package/src/components/app-brand.tsx +0 -38
  148. package/src/components/assistant-chat.tsx +0 -461
  149. package/src/components/chat-attachments.tsx +0 -68
  150. package/src/components/chat-bubble.tsx +0 -373
  151. package/src/components/chat-header.tsx +0 -44
  152. package/src/components/client-tool-executor.tsx +0 -230
  153. package/src/components/collection-empty-state.tsx +0 -37
  154. package/src/components/collection-filter-bar.tsx +0 -168
  155. package/src/components/collection-search-input.tsx +0 -41
  156. package/src/components/collection-skeleton.tsx +0 -55
  157. package/src/components/collection-sort-menu.tsx +0 -62
  158. package/src/components/collection-surface.tsx +0 -46
  159. package/src/components/collection-toolbar.tsx +0 -33
  160. package/src/components/collection-view-toggle.tsx +0 -61
  161. package/src/components/composer-submit-bridge.tsx +0 -19
  162. package/src/components/confirm-dialog.tsx +0 -49
  163. package/src/components/confirmation-card.tsx +0 -32
  164. package/src/components/context-badges.tsx +0 -136
  165. package/src/components/context-bar.tsx +0 -238
  166. package/src/components/form-dialog.tsx +0 -56
  167. package/src/components/global-selection-popover.tsx +0 -266
  168. package/src/components/infinite-scroll-sentinel.tsx +0 -48
  169. package/src/components/json-viewer.tsx +0 -232
  170. package/src/components/loading-indicator.tsx +0 -40
  171. package/src/components/markdown-text-citations.test.tsx +0 -108
  172. package/src/components/markdown-text.tsx +0 -508
  173. package/src/components/name-dialog.tsx +0 -87
  174. package/src/components/selection-popover.tsx +0 -156
  175. package/src/components/show-document-tool-ui.tsx +0 -90
  176. package/src/components/sidebar.test.tsx +0 -611
  177. package/src/components/sidebar.tsx +0 -1689
  178. package/src/components/surface-card.tsx +0 -45
  179. package/src/components/theme-runtime-provider.tsx +0 -93
  180. package/src/components/theme-toggle.tsx +0 -27
  181. package/src/components/tool-call-card.tsx +0 -126
  182. package/src/components/tool-fallback.tsx +0 -169
  183. package/src/components/tool-panel-layout.tsx +0 -36
  184. package/src/components/tool-panel.tsx +0 -233
  185. package/src/components/tooltip-icon-button.tsx +0 -28
  186. package/src/components/user-menu.tsx +0 -60
  187. package/src/index.ts +0 -185
  188. package/src/lib/__tests__/ag-ui-adapter.test.ts +0 -279
  189. package/src/lib/__tests__/app-store.test.ts +0 -405
  190. package/src/lib/__tests__/attachment-adapter.test.ts +0 -48
  191. package/src/lib/__tests__/chat-bubble-store.test.ts +0 -67
  192. package/src/lib/__tests__/client-tools.test.ts +0 -124
  193. package/src/lib/__tests__/dev-store.test.ts +0 -78
  194. package/src/lib/__tests__/nav-config.test.ts +0 -135
  195. package/src/lib/__tests__/nav-dnd.test.ts +0 -24
  196. package/src/lib/__tests__/nav-store.test.ts +0 -59
  197. package/src/lib/__tests__/selection-context.test.ts +0 -114
  198. package/src/lib/__tests__/sidebar-store.test.ts +0 -144
  199. package/src/lib/__tests__/theme-store.test.ts +0 -83
  200. package/src/lib/__tests__/tool-panel-store.test.ts +0 -61
  201. package/src/lib/__tests__/use-page-context.test.ts +0 -58
  202. package/src/lib/ag-ui-adapter.ts +0 -426
  203. package/src/lib/app-store.ts +0 -361
  204. package/src/lib/attachment-adapter.ts +0 -92
  205. package/src/lib/auth-provider.tsx +0 -144
  206. package/src/lib/chat-bubble-store.ts +0 -46
  207. package/src/lib/client-tools.ts +0 -293
  208. package/src/lib/composer-submit-store.ts +0 -32
  209. package/src/lib/dev-store.ts +0 -69
  210. package/src/lib/nav-config.ts +0 -329
  211. package/src/lib/nav-dnd.ts +0 -14
  212. package/src/lib/nav-store.ts +0 -89
  213. package/src/lib/selection-context.ts +0 -65
  214. package/src/lib/sidebar-store.ts +0 -113
  215. package/src/lib/theme-runtime.ts +0 -660
  216. package/src/lib/theme-store.ts +0 -67
  217. package/src/lib/tool-panel-store.ts +0 -121
  218. package/src/lib/use-new-conversation.test.tsx +0 -168
  219. package/src/lib/use-new-conversation.ts +0 -64
  220. package/src/ui/dialog.tsx +0 -109
  221. package/src/ui/dropdown-menu.tsx +0 -75
  222. package/src/ui/popover.tsx +0 -34
  223. package/src/ui/select.tsx +0 -15
  224. package/src/ui/tooltip.tsx +0 -30
  225. package/src/vite-env.d.ts +0 -1
  226. package/tsconfig.json +0 -16
  227. package/vitest.config.ts +0 -8
@@ -0,0 +1,274 @@
1
+ /**
2
+ * Global Client Tools — registered into the dynamic tool registry at app init.
3
+ *
4
+ * Naming convention:
5
+ * ui_* — tools that affect the UI (navigate, theme, panel, content)
6
+ *
7
+ * Page-specific tools use their own prefix (e.g., page_search_documents).
8
+ * The adapter reads from the registry (not this file) on every request.
9
+ */
10
+ import { useThemeStore } from "./theme-store.js";
11
+ import { useToolPanelStore } from "./tool-panel-store.js";
12
+ import { useAppStore } from "./app-store.js";
13
+ import { clientToolRegistry } from "@iloveagents/foundry-agent";
14
+ // ---------------------------------------------------------------------------
15
+ // Navigate function injection (needs React Router context)
16
+ // ---------------------------------------------------------------------------
17
+ let _navigateFn = null;
18
+ export function setNavigateFunction(fn) {
19
+ _navigateFn = fn;
20
+ }
21
+ // ---------------------------------------------------------------------------
22
+ // Global tool definitions with executors
23
+ // ---------------------------------------------------------------------------
24
+ const GLOBAL_TOOLS = [
25
+ {
26
+ name: "ui_navigate",
27
+ description: "Navigate the user to a different page in the application. " +
28
+ "Only use when the user explicitly asks to go to a page.",
29
+ parameters: {
30
+ type: "object",
31
+ properties: {
32
+ path: {
33
+ type: "string",
34
+ description: "The path to navigate to (e.g. '/workspace')",
35
+ },
36
+ },
37
+ required: ["path"],
38
+ },
39
+ execute: async (argsJson) => {
40
+ const { path } = JSON.parse(argsJson || "{}");
41
+ if (_navigateFn)
42
+ _navigateFn(path);
43
+ return JSON.stringify({ status: "success", path });
44
+ },
45
+ },
46
+ {
47
+ name: "ui_set_theme",
48
+ description: "Change the application theme. Modes: 'light', 'dark', or 'system'.",
49
+ parameters: {
50
+ type: "object",
51
+ properties: {
52
+ mode: {
53
+ type: "string",
54
+ enum: ["light", "dark", "system"],
55
+ description: "The theme mode to apply",
56
+ },
57
+ },
58
+ required: ["mode"],
59
+ },
60
+ execute: async (argsJson) => {
61
+ const { mode } = JSON.parse(argsJson || "{}");
62
+ useThemeStore.getState().setMode(mode);
63
+ return JSON.stringify({ status: "success", mode });
64
+ },
65
+ },
66
+ {
67
+ name: "ui_open_panel",
68
+ description: "Show content in the side panel. Prefer this over ui_navigate to keep " +
69
+ "chat visible. Use path for a page component (e.g. '/workspace'), " +
70
+ "or content for generated markdown/text.",
71
+ parameters: {
72
+ type: "object",
73
+ properties: {
74
+ title: { type: "string", description: "Panel title" },
75
+ path: {
76
+ type: "string",
77
+ description: "Page path to render in the panel (e.g. '/workspace')",
78
+ },
79
+ content: {
80
+ type: "string",
81
+ description: "Markdown or text content (used when path is not provided)",
82
+ },
83
+ type: {
84
+ type: "string",
85
+ enum: ["markdown", "text"],
86
+ description: "Content format (default: markdown)",
87
+ },
88
+ },
89
+ required: ["title"],
90
+ },
91
+ execute: async (argsJson) => {
92
+ const args = JSON.parse(argsJson || "{}");
93
+ if (args.path) {
94
+ useToolPanelStore.getState().openPanel({
95
+ title: args.title,
96
+ content: args.path,
97
+ type: "page",
98
+ });
99
+ }
100
+ else {
101
+ useToolPanelStore.getState().openPanel({
102
+ title: args.title,
103
+ content: args.content || "",
104
+ type: args.type || "markdown",
105
+ });
106
+ }
107
+ return JSON.stringify({
108
+ status: "success",
109
+ title: args.title,
110
+ mode: args.path ? "page" : "content",
111
+ });
112
+ },
113
+ },
114
+ {
115
+ name: "ui_select_item",
116
+ description: "Select an item in the current page by its ID. Highlights it in the UI.",
117
+ parameters: {
118
+ type: "object",
119
+ properties: {
120
+ itemId: {
121
+ type: "string",
122
+ description: "The ID of the item to select (or null to deselect)",
123
+ },
124
+ },
125
+ required: ["itemId"],
126
+ },
127
+ execute: async (argsJson) => {
128
+ const { itemId } = JSON.parse(argsJson || "{}");
129
+ useAppStore.getState().setSelectedItemId(itemId ?? null);
130
+ return JSON.stringify({ status: "success", itemId });
131
+ },
132
+ },
133
+ {
134
+ name: "ui_update_content",
135
+ description: "Update fields in the shared draft/form. Pass all fields as key-value " +
136
+ "pairs in a single call. Works for one or many fields.",
137
+ parameters: {
138
+ type: "object",
139
+ properties: {
140
+ fields: {
141
+ type: "object",
142
+ description: "Key-value pairs of field names and their values",
143
+ additionalProperties: true,
144
+ },
145
+ },
146
+ required: ["fields"],
147
+ },
148
+ execute: async (argsJson) => {
149
+ const { fields } = JSON.parse(argsJson || "{}");
150
+ const store = useAppStore.getState();
151
+ for (const [key, value] of Object.entries(fields)) {
152
+ store.updateContentField(key, value);
153
+ }
154
+ return JSON.stringify({ status: "success", fields });
155
+ },
156
+ },
157
+ {
158
+ name: "ui_highlight",
159
+ description: "Highlight an entity in the UI to draw the user's attention.",
160
+ parameters: {
161
+ type: "object",
162
+ properties: {
163
+ entityId: {
164
+ type: "string",
165
+ description: "The ID of the entity to highlight",
166
+ },
167
+ },
168
+ required: ["entityId"],
169
+ },
170
+ execute: async (argsJson) => {
171
+ const { entityId } = JSON.parse(argsJson || "{}");
172
+ useAppStore.getState().addHighlight(entityId);
173
+ return JSON.stringify({ status: "success", entityId });
174
+ },
175
+ },
176
+ {
177
+ name: "ui_confirm",
178
+ description: "Ask the user to confirm or reject an action before proceeding. " +
179
+ "Use for destructive or important actions.",
180
+ parameters: {
181
+ type: "object",
182
+ properties: {
183
+ action: {
184
+ type: "string",
185
+ description: "Short description of the action requiring confirmation",
186
+ },
187
+ details: {
188
+ type: "string",
189
+ description: "Optional details about what will happen",
190
+ },
191
+ },
192
+ required: ["action"],
193
+ },
194
+ execute: async (argsJson) => {
195
+ const { action, details } = JSON.parse(argsJson || "{}");
196
+ return JSON.stringify({
197
+ status: "pending",
198
+ action,
199
+ details: details || "",
200
+ message: "Awaiting user confirmation via chat.",
201
+ });
202
+ },
203
+ },
204
+ {
205
+ name: "ui_get_context",
206
+ description: "Get the full application context: navigation breadcrumb from root " +
207
+ "to current page (with accumulated metadata), selected items, draft " +
208
+ "values, highlights, and user-pinned context items.",
209
+ parameters: { type: "object", properties: {}, required: [] },
210
+ execute: async () => {
211
+ const state = useAppStore.getState().getAgentState();
212
+ const { useNavStore } = await import("./nav-store.js");
213
+ const navConfig = useNavStore.getState().config;
214
+ // Build breadcrumb: root group → parent item → current leaf
215
+ const breadcrumb = [];
216
+ for (const group of navConfig) {
217
+ for (const item of group.items) {
218
+ if (item.to === state.navigation.page) {
219
+ breadcrumb.push({ level: "group", label: group.label, meta: group.meta });
220
+ breadcrumb.push({
221
+ level: "page",
222
+ label: item.label,
223
+ description: item.description,
224
+ meta: item.meta,
225
+ });
226
+ break;
227
+ }
228
+ if (item.children) {
229
+ for (const child of item.children) {
230
+ if (child.to === state.navigation.page) {
231
+ breadcrumb.push({ level: "group", label: group.label, meta: group.meta });
232
+ breadcrumb.push({
233
+ level: "parent",
234
+ label: item.label,
235
+ description: item.description,
236
+ meta: item.meta,
237
+ });
238
+ breadcrumb.push({
239
+ level: "page",
240
+ label: child.label,
241
+ description: child.description,
242
+ meta: child.meta,
243
+ });
244
+ break;
245
+ }
246
+ }
247
+ }
248
+ }
249
+ if (breadcrumb.length > 0)
250
+ break;
251
+ }
252
+ return JSON.stringify({
253
+ status: "success",
254
+ breadcrumb,
255
+ currentPage: state.navigation,
256
+ selectedItemId: state.selectedItemId,
257
+ content: state.content,
258
+ highlights: state.highlights,
259
+ contextItems: state.contextItems,
260
+ });
261
+ },
262
+ },
263
+ ];
264
+ // ---------------------------------------------------------------------------
265
+ // Registration — called once at module load
266
+ // ---------------------------------------------------------------------------
267
+ export function registerGlobalTools() {
268
+ const registry = clientToolRegistry.getState();
269
+ for (const tool of GLOBAL_TOOLS) {
270
+ registry.registerGlobal(tool);
271
+ }
272
+ }
273
+ // Auto-register on import
274
+ registerGlobalTools();
@@ -0,0 +1,12 @@
1
+ interface PendingComposerSubmit {
2
+ id: number;
3
+ text: string;
4
+ }
5
+ interface ComposerSubmitState {
6
+ pending: PendingComposerSubmit | null;
7
+ submit: (text: string) => void;
8
+ consume: (id: number) => void;
9
+ }
10
+ export declare const useComposerSubmitStore: import("zustand").UseBoundStore<import("zustand").StoreApi<ComposerSubmitState>>;
11
+ export declare function submitComposerText(text: string): void;
12
+ export {};
@@ -0,0 +1,17 @@
1
+ import { create } from "zustand";
2
+ let nextSubmitId = 1;
3
+ export const useComposerSubmitStore = create((set) => ({
4
+ pending: null,
5
+ submit: (text) => {
6
+ const trimmed = text.trim();
7
+ if (!trimmed)
8
+ return;
9
+ set({ pending: { id: nextSubmitId++, text: trimmed } });
10
+ },
11
+ consume: (id) => set((state) => ({
12
+ pending: state.pending?.id === id ? null : state.pending,
13
+ })),
14
+ }));
15
+ export function submitComposerText(text) {
16
+ useComposerSubmitStore.getState().submit(text);
17
+ }
@@ -0,0 +1,38 @@
1
+ /**
2
+ * Dev Store — captures debug telemetry for the Dev Panel.
3
+ *
4
+ * Only populated in dev mode. Stores the last AG-UI request payload
5
+ * and tool call events so developers can inspect the full agent turn.
6
+ */
7
+ export interface DevToolCall {
8
+ id: string;
9
+ name: string;
10
+ args: string;
11
+ result?: unknown;
12
+ isClientSide: boolean;
13
+ timestamp: number;
14
+ }
15
+ interface DevState {
16
+ /** Last AG-UI request payload (runInput) */
17
+ lastRequest: Record<string, unknown> | null;
18
+ /** Timestamp of last request */
19
+ lastRequestAt: number | null;
20
+ /** Tool calls from the current/last turn */
21
+ toolCalls: DevToolCall[];
22
+ /** SSE events log (last N) */
23
+ events: Array<{
24
+ type: string;
25
+ timestamp: number;
26
+ data?: string;
27
+ }>;
28
+ /** Capture a request payload (resets tool calls for new turn) */
29
+ captureRequest: (payload: Record<string, unknown>) => void;
30
+ /** Record a tool call */
31
+ addToolCall: (call: DevToolCall) => void;
32
+ /** Update a tool call with args and/or result */
33
+ updateToolCall: (id: string, update: Partial<Pick<DevToolCall, "args" | "result">>) => void;
34
+ /** Log an SSE event */
35
+ logEvent: (type: string, data?: string) => void;
36
+ }
37
+ export declare const useDevStore: import("zustand").UseBoundStore<import("zustand").StoreApi<DevState>>;
38
+ export {};
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Dev Store — captures debug telemetry for the Dev Panel.
3
+ *
4
+ * Only populated in dev mode. Stores the last AG-UI request payload
5
+ * and tool call events so developers can inspect the full agent turn.
6
+ */
7
+ import { create } from "zustand";
8
+ const MAX_EVENTS = 50;
9
+ export const useDevStore = create((set, get) => ({
10
+ lastRequest: null,
11
+ lastRequestAt: null,
12
+ toolCalls: [],
13
+ events: [],
14
+ captureRequest: (payload) => {
15
+ const isFollowUp = get().toolCalls.length > 0;
16
+ set({
17
+ lastRequest: payload,
18
+ lastRequestAt: Date.now(),
19
+ // Keep tool calls for follow-up requests (multi-turn), reset on fresh turn
20
+ ...(isFollowUp ? {} : { toolCalls: [], events: [] }),
21
+ });
22
+ },
23
+ addToolCall: (call) => set({ toolCalls: [...get().toolCalls, call] }),
24
+ updateToolCall: (id, update) => set({
25
+ toolCalls: get().toolCalls.map((tc) => (tc.id === id ? { ...tc, ...update } : tc)),
26
+ }),
27
+ logEvent: (type, data) => {
28
+ const events = get().events;
29
+ const next = [...events, { type, timestamp: Date.now(), data }];
30
+ set({ events: next.length > MAX_EVENTS ? next.slice(-MAX_EVENTS) : next });
31
+ },
32
+ }));
@@ -0,0 +1,159 @@
1
+ /**
2
+ * Navigation Configuration — types, default config, and lookup utility.
3
+ *
4
+ * This is the single source of truth for the sidebar and agent context projection.
5
+ * The sidebar and app-layout read from the nav store (nav-store.ts), which is
6
+ * initialized with DEFAULT_NAV_CONFIG. Dynamic items (e.g., from a database)
7
+ * can be merged at runtime via useNavStore.getState().addGroup().
8
+ */
9
+ import type { LucideIcon } from "lucide-react";
10
+ export interface NavItemAction {
11
+ icon: LucideIcon;
12
+ label: string;
13
+ handler: () => void | Promise<void>;
14
+ /** Render a separator line before this action. */
15
+ separator?: boolean;
16
+ /** Style as destructive (red text). */
17
+ destructive?: boolean;
18
+ }
19
+ /** Drag-and-drop behavior for a nav item. Provided by feature modules (e.g., SPACES). */
20
+ export interface NavItemDnd {
21
+ /** MIME type for dataTransfer */
22
+ type: string;
23
+ /** Data to set on drag start (e.g., entity ID) */
24
+ getData: () => string | null;
25
+ /** Whether this item can be dragged */
26
+ canDrag: () => boolean;
27
+ /** Whether this item accepts drops */
28
+ canDrop: () => boolean;
29
+ /** Whether this item accepts external file drops (e.g. from Finder) */
30
+ canDropFiles?: () => boolean;
31
+ /** Handle a drop event — receives dragged data string and returns a promise */
32
+ onDrop: (draggedData: string) => Promise<void>;
33
+ /** Handle external file drop — receives File objects from the browser */
34
+ onFileDrop?: (files: File[]) => Promise<void>;
35
+ }
36
+ export interface NavItem {
37
+ to: string;
38
+ label: string;
39
+ icon: LucideIcon;
40
+ /** When true, the item is visible but not clickable (ghost state for label scope). */
41
+ disabled?: boolean;
42
+ /** Render with reduced opacity (e.g., hidden files). */
43
+ dimmed?: boolean;
44
+ /** Small text badge after the label (e.g., "managed", "locked"). */
45
+ badge?: string;
46
+ /** Small status dot after the label for quiet state hints such as pending review impact. */
47
+ statusDot?: {
48
+ tone?: "neutral" | "info" | "low-impact" | "medium-impact" | "high-impact" | "pending";
49
+ label?: string;
50
+ };
51
+ /**
52
+ * Optional warning / status icon shown after the label. Use for
53
+ * "something needs attention" annotations (e.g. failed indexing,
54
+ * permission drift) where a coloured dot isn't legible enough.
55
+ * Pass any LucideIcon; the tone drives the colour.
56
+ */
57
+ statusIcon?: {
58
+ icon: LucideIcon;
59
+ tone?: "neutral" | "info" | "warning" | "danger";
60
+ label?: string;
61
+ };
62
+ /** Page description sent to the agent for context */
63
+ description?: string;
64
+ /** Arbitrary metadata sent to the agent (e.g., workspace IDs, entity types) */
65
+ meta?: Record<string, unknown>;
66
+ /** Page-specific instructions automatically sent to the agent when this page is active */
67
+ contextInstructions?: string;
68
+ /** Sub-navigation items (rendered indented under parent) */
69
+ children?: NavItem[];
70
+ /** Inline action buttons rendered next to the nav item (e.g., + document, + folder) */
71
+ actions?: NavItemAction[];
72
+ /** Optional drag-and-drop behavior (provided by feature modules) */
73
+ dnd?: NavItemDnd;
74
+ }
75
+ /** Action shown in the "+" dropdown on a nav group header. */
76
+ export interface NavGroupCreateAction {
77
+ id: string;
78
+ label: string;
79
+ handler: () => void;
80
+ }
81
+ /** Item rendered on the collapsed sidebar rail. Returned by `NavGroup.collapsedRail`. */
82
+ export interface CollapsedRailItem {
83
+ to: string;
84
+ label: string;
85
+ icon: LucideIcon;
86
+ isActive: boolean;
87
+ }
88
+ /**
89
+ * Context passed to `NavGroup.collapsedRail` so the renderer can decide which
90
+ * shortcuts to surface. Modules read their own keys out of `navContextMeta`
91
+ * (e.g., Spaces uses `spacesRootId`).
92
+ */
93
+ export interface CollapsedRailContext {
94
+ currentPage: string;
95
+ navContextMeta: Record<string, unknown>;
96
+ }
97
+ export interface NavGroup {
98
+ label: string;
99
+ items: NavItem[];
100
+ /**
101
+ * Render order weight. Higher = higher in the sidebar. Default 0.
102
+ * Ties keep insertion order (stable sort), so existing call sites
103
+ * that don't set a priority preserve the legacy "addGroup appends"
104
+ * behaviour. Use this to pin a group to a specific slot regardless
105
+ * of which feature hook finishes first.
106
+ */
107
+ priority?: number;
108
+ /**
109
+ * When true, the group header gets a click-to-toggle chevron and
110
+ * the children hide when collapsed. State persists per group label
111
+ * in localStorage so the user's preference survives reloads. Mutually
112
+ * exclusive with ``hideLabel`` — a hidden label can't host a chevron.
113
+ *
114
+ * If any child carries a :attr:`NavItem.statusDot`, it bubbles up to
115
+ * the collapsed header so the user can still see "the active chat is
116
+ * inside this collapsed group" without auto-expanding.
117
+ */
118
+ collapsible?: boolean;
119
+ /** Initial collapse state when no user preference is stored. */
120
+ defaultCollapsed?: boolean;
121
+ /** Optional link for the group header label */
122
+ to?: string;
123
+ /** Hide the group header while preserving group semantics. */
124
+ hideLabel?: boolean;
125
+ /** Group description sent to the agent */
126
+ description?: string;
127
+ /** Group-level metadata (e.g., org settings, workspace config, custom instructions) */
128
+ meta?: Record<string, unknown>;
129
+ /** Group-level instructions automatically sent to the agent for all pages in this group */
130
+ contextInstructions?: string;
131
+ /** Create actions shown as a "+" dropdown in the group header */
132
+ createActions?: NavGroupCreateAction[];
133
+ /**
134
+ * Optional override for the collapsed sidebar rail. When present, the
135
+ * shell calls this instead of mapping `items` to icons one-to-one.
136
+ *
137
+ * Useful for groups whose collapsed view is "header link plus the active
138
+ * item's root", not a flat icon list. Returning `[]` hides the group.
139
+ */
140
+ collapsedRail?: (ctx: CollapsedRailContext) => CollapsedRailItem[];
141
+ }
142
+ /** Static default config — the template ships with these pages. */
143
+ export declare const DEFAULT_NAV_CONFIG: NavGroup[];
144
+ /**
145
+ * Find the active nav item by path match.
146
+ * Tries exact match first, then longest-prefix match for dynamic routes.
147
+ * Searches top-level items and their children.
148
+ *
149
+ * For dynamic routes loaded from a database, add them to the nav store
150
+ * at runtime — they'll be found here automatically.
151
+ */
152
+ export interface NavMatch {
153
+ group: string;
154
+ groupMeta?: Record<string, unknown>;
155
+ groupDescription?: string;
156
+ groupInstructions?: string;
157
+ item: NavItem;
158
+ }
159
+ export declare function findNavItem(config: NavGroup[], path: string): NavMatch | null;