@agent-native/core 0.120.0 → 0.120.2

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 (207) hide show
  1. package/corpus/README.md +2 -2
  2. package/corpus/core/CHANGELOG.md +16 -0
  3. package/corpus/core/docs/content/extensions.mdx +23 -4
  4. package/corpus/core/package.json +1 -1
  5. package/corpus/core/src/agent/production-agent.ts +4 -0
  6. package/corpus/core/src/agent/run-manager.ts +36 -10
  7. package/corpus/core/src/agent/types.ts +2 -0
  8. package/corpus/core/src/client/MultiTabAssistantChat.tsx +45 -0
  9. package/corpus/core/src/client/extensions/ExtensionsListPage.tsx +16 -3
  10. package/corpus/core/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  11. package/corpus/core/src/client/settings/SettingsPanel.tsx +10 -0
  12. package/corpus/core/src/client/use-chat-models.ts +45 -0
  13. package/corpus/core/src/deploy/build.ts +3 -0
  14. package/corpus/core/src/server/analytics.ts +164 -20
  15. package/corpus/core/src/server/auth.ts +17 -13
  16. package/corpus/core/src/server/better-auth-instance.ts +13 -1
  17. package/corpus/core/src/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  18. package/corpus/core/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  19. package/corpus/core/src/templates/chat/netlify.toml +1 -0
  20. package/corpus/core/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  21. package/corpus/core/src/vite/client.ts +6 -0
  22. package/corpus/templates/analytics/.agents/skills/adhoc-analysis/SKILL.md +27 -43
  23. package/corpus/templates/analytics/.agents/skills/dashboard-management/SKILL.md +19 -8
  24. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +2 -2
  25. package/corpus/templates/analytics/AGENTS.md +20 -8
  26. package/corpus/templates/analytics/actions/get-explorer-dashboard.ts +3 -0
  27. package/corpus/templates/analytics/actions/list-dashboard-usage-stats.ts +140 -46
  28. package/corpus/templates/analytics/actions/migrate-analytics-artifacts.ts +48 -0
  29. package/corpus/templates/analytics/actions/save-analysis.ts +2 -3
  30. package/corpus/templates/analytics/actions/view-screen.ts +1 -1
  31. package/corpus/templates/analytics/app/components/dashboard/DashboardMetadata.tsx +77 -0
  32. package/corpus/templates/analytics/app/components/dashboard/DashboardPanelSkeleton.tsx +7 -1
  33. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  34. package/corpus/templates/analytics/app/components/layout/Sidebar.tsx +103 -502
  35. package/corpus/templates/analytics/app/global.css +30 -0
  36. package/corpus/templates/analytics/app/hooks/use-navigation-state.ts +2 -2
  37. package/corpus/templates/analytics/app/i18n-data.ts +80 -0
  38. package/corpus/templates/analytics/app/pages/Agents.tsx +49 -2
  39. package/corpus/templates/analytics/app/pages/adhoc/explorer-dashboard/index.tsx +54 -11
  40. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/SqlChartCard.tsx +3 -53
  41. package/corpus/templates/analytics/app/pages/adhoc/sql-dashboard/index.tsx +23 -25
  42. package/corpus/templates/analytics/app/pages/analyses/AnalysisDetail.tsx +2 -2
  43. package/corpus/templates/analytics/app/routes/analyses._index.tsx +3 -2
  44. package/corpus/templates/analytics/app/routes/extensions._index.tsx +2 -2
  45. package/corpus/templates/analytics/changelog/2026-07-23-analytics-now-groups-saved-analyses-and-embedded-extensions-.md +6 -0
  46. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-menus-show-who-created-and-last-updated-each-dashb.md +6 -0
  47. package/corpus/templates/analytics/changelog/2026-07-23-dashboard-usage-now-loads-reliably-for-organizations-with-ma.md +6 -0
  48. package/corpus/templates/analytics/changelog/2026-07-23-long-dashboard-building-requests-now-continue-without-stoppi.md +6 -0
  49. package/corpus/templates/analytics/netlify.toml +4 -0
  50. package/corpus/templates/analytics/server/db/schema.ts +4 -0
  51. package/corpus/templates/analytics/server/lib/agent-chat-plan-mode.ts +0 -1
  52. package/corpus/templates/analytics/server/lib/agent-readable-resource-context.ts +1 -0
  53. package/corpus/templates/analytics/server/lib/migrate-analytics-artifacts.ts +1062 -0
  54. package/corpus/templates/analytics/server/plugins/agent-chat.ts +6 -52
  55. package/corpus/templates/analytics/server/plugins/core-routes.ts +1 -1
  56. package/corpus/templates/analytics/server/plugins/db.ts +10 -0
  57. package/corpus/templates/assets/actions/generate-image-batch.ts +36 -1
  58. package/corpus/templates/assets/actions/generate-image.ts +28 -1
  59. package/corpus/templates/assets/app/components/layout/Sidebar.tsx +47 -9
  60. package/corpus/templates/assets/app/routes/extensions._index.tsx +2 -2
  61. package/corpus/templates/assets/changelog/2026-07-23-assets-image-generation-now-recovers-after-a-completed-tool-.md +6 -0
  62. package/corpus/templates/assets/changelog/2026-07-23-new-chat-aligns-with-sidebar-controls.md +6 -0
  63. package/corpus/templates/assets/netlify.toml +1 -0
  64. package/corpus/templates/brain/app/components/layout/Sidebar.tsx +38 -8
  65. package/corpus/templates/brain/app/routes/extensions._index.tsx +2 -2
  66. package/corpus/templates/brain/netlify.toml +1 -0
  67. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +43 -5
  68. package/corpus/templates/calendar/app/routes/_app.extensions._index.tsx +2 -16
  69. package/corpus/templates/calendar/netlify.toml +1 -0
  70. package/corpus/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  71. package/corpus/templates/chat/app/routes/extensions._index.tsx +2 -2
  72. package/corpus/templates/chat/netlify.toml +1 -0
  73. package/corpus/templates/clips/app/components/library/library-layout.tsx +52 -6
  74. package/corpus/templates/clips/app/routes/_app.extensions._index.tsx +2 -16
  75. package/corpus/templates/clips/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  76. package/corpus/templates/clips/changelog/2026-07-23-meeting-recording-meters-and-dismissed-prompts.md +6 -0
  77. package/corpus/templates/clips/desktop/src/hooks/useMicMeter.ts +1 -1
  78. package/corpus/templates/clips/desktop/src/lib/meeting-notification-dismissal.ts +2 -0
  79. package/corpus/templates/clips/desktop/src/lib/voice-dictation.ts +1 -3
  80. package/corpus/templates/clips/desktop/src/overlays/live-audio-bars.tsx +86 -0
  81. package/corpus/templates/clips/desktop/src/overlays/meeting-notification.tsx +24 -0
  82. package/corpus/templates/clips/desktop/src/overlays/recording-pill.tsx +5 -69
  83. package/corpus/templates/clips/desktop/src/styles.css +35 -3
  84. package/corpus/templates/clips/desktop/src-tauri/src/adhoc_meetings_watcher.rs +13 -44
  85. package/corpus/templates/clips/desktop/src-tauri/src/notifications.rs +119 -17
  86. package/corpus/templates/clips/netlify.toml +1 -0
  87. package/corpus/templates/content/app/components/sidebar/DocumentSidebar.tsx +3 -7
  88. package/corpus/templates/content/app/routes/_app.extensions._index.tsx +2 -2
  89. package/corpus/templates/content/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  90. package/corpus/templates/content/netlify.toml +1 -0
  91. package/corpus/templates/design/app/components/layout/Sidebar.tsx +55 -17
  92. package/corpus/templates/design/app/routes/extensions._index.tsx +2 -2
  93. package/corpus/templates/design/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  94. package/corpus/templates/design/netlify.toml +1 -0
  95. package/corpus/templates/dispatch/app/dispatch-extensions.tsx +1 -1
  96. package/corpus/templates/dispatch/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  97. package/corpus/templates/dispatch/netlify.toml +1 -0
  98. package/corpus/templates/forms/.agents/skills/form-publishing/SKILL.md +9 -3
  99. package/corpus/templates/forms/AGENTS.md +11 -1
  100. package/corpus/templates/forms/README.md +24 -1
  101. package/corpus/templates/forms/actions/update-form.ts +12 -5
  102. package/corpus/templates/forms/app/components/builder/FieldPropertiesPanel.tsx +199 -1
  103. package/corpus/templates/forms/app/components/layout/Sidebar.tsx +41 -45
  104. package/corpus/templates/forms/app/i18n/en-US.ts +13 -1
  105. package/corpus/templates/forms/app/pages/FormBuilderPage.tsx +35 -4
  106. package/corpus/templates/forms/app/pages/FormFillPage.tsx +7 -16
  107. package/corpus/templates/forms/app/routes/_app.extensions._index.tsx +2 -2
  108. package/corpus/templates/forms/changelog/2026-07-23-agent-settings-are-clearly-labeled-manage-agent-in-the-sideb.md +6 -0
  109. package/corpus/templates/forms/changelog/2026-07-23-forms-can-branch-into-follow-up-questions-and-route-response.md +6 -0
  110. package/corpus/templates/forms/netlify.toml +1 -0
  111. package/corpus/templates/forms/server/handlers/submissions.ts +22 -31
  112. package/corpus/templates/forms/server/lib/integrations.ts +11 -2
  113. package/corpus/templates/forms/server/lib/public-form-ssr.ts +26 -5
  114. package/corpus/templates/forms/server/lib/validate-fields.ts +48 -11
  115. package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -0
  116. package/corpus/templates/forms/shared/conditional.ts +67 -0
  117. package/corpus/templates/macros/app/components/layout/AppLayout.tsx +36 -5
  118. package/corpus/templates/macros/app/routes/extensions._index.tsx +2 -2
  119. package/corpus/templates/macros/netlify.toml +1 -0
  120. package/corpus/templates/mail/app/components/layout/AppLayout.tsx +0 -9
  121. package/corpus/templates/mail/app/routes/extensions._index.tsx +2 -2
  122. package/corpus/templates/mail/netlify.toml +1 -0
  123. package/corpus/templates/plan/app/components/layout/Sidebar.tsx +38 -5
  124. package/corpus/templates/plan/app/routes/extensions._index.tsx +2 -2
  125. package/corpus/templates/plan/netlify.toml +1 -0
  126. package/corpus/templates/slides/app/components/layout/Sidebar.tsx +47 -4
  127. package/corpus/templates/slides/app/routes/extensions._index.tsx +2 -2
  128. package/corpus/templates/slides/netlify.toml +1 -0
  129. package/corpus/templates/tasks/app/components/layout/Sidebar.tsx +37 -6
  130. package/corpus/templates/tasks/app/routes/extensions._index.tsx +2 -2
  131. package/corpus/templates/tasks/app/routes/settings.tsx +31 -0
  132. package/corpus/templates/tasks/netlify.toml +1 -0
  133. package/dist/agent/production-agent.d.ts.map +1 -1
  134. package/dist/agent/production-agent.js +4 -0
  135. package/dist/agent/production-agent.js.map +1 -1
  136. package/dist/agent/run-manager.d.ts +9 -0
  137. package/dist/agent/run-manager.d.ts.map +1 -1
  138. package/dist/agent/run-manager.js +25 -10
  139. package/dist/agent/run-manager.js.map +1 -1
  140. package/dist/agent/types.d.ts +2 -2
  141. package/dist/agent/types.d.ts.map +1 -1
  142. package/dist/agent/types.js.map +1 -1
  143. package/dist/client/MultiTabAssistantChat.d.ts.map +1 -1
  144. package/dist/client/MultiTabAssistantChat.js +35 -0
  145. package/dist/client/MultiTabAssistantChat.js.map +1 -1
  146. package/dist/client/extensions/ExtensionsListPage.d.ts +5 -1
  147. package/dist/client/extensions/ExtensionsListPage.d.ts.map +1 -1
  148. package/dist/client/extensions/ExtensionsListPage.js +5 -3
  149. package/dist/client/extensions/ExtensionsListPage.js.map +1 -1
  150. package/dist/client/settings/ExtensionsSettingsContent.d.ts +2 -0
  151. package/dist/client/settings/ExtensionsSettingsContent.d.ts.map +1 -0
  152. package/dist/client/settings/ExtensionsSettingsContent.js +10 -0
  153. package/dist/client/settings/ExtensionsSettingsContent.js.map +1 -0
  154. package/dist/client/settings/SettingsPanel.d.ts.map +1 -1
  155. package/dist/client/settings/SettingsPanel.js +10 -1
  156. package/dist/client/settings/SettingsPanel.js.map +1 -1
  157. package/dist/client/use-chat-models.d.ts +1 -0
  158. package/dist/client/use-chat-models.d.ts.map +1 -1
  159. package/dist/client/use-chat-models.js +33 -0
  160. package/dist/client/use-chat-models.js.map +1 -1
  161. package/dist/collab/awareness.d.ts +2 -2
  162. package/dist/collab/awareness.d.ts.map +1 -1
  163. package/dist/deploy/build.js +1 -0
  164. package/dist/deploy/build.js.map +1 -1
  165. package/dist/file-upload/actions/upload-image.d.ts +1 -1
  166. package/dist/observability/routes.d.ts +3 -3
  167. package/dist/provider-api/actions/custom-provider-registration.d.ts +4 -4
  168. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  169. package/dist/server/analytics.d.ts +17 -4
  170. package/dist/server/analytics.d.ts.map +1 -1
  171. package/dist/server/analytics.js +122 -17
  172. package/dist/server/analytics.js.map +1 -1
  173. package/dist/server/auth.d.ts.map +1 -1
  174. package/dist/server/auth.js +5 -4
  175. package/dist/server/auth.js.map +1 -1
  176. package/dist/server/better-auth-instance.d.ts +8 -0
  177. package/dist/server/better-auth-instance.d.ts.map +1 -1
  178. package/dist/server/better-auth-instance.js +10 -1
  179. package/dist/server/better-auth-instance.js.map +1 -1
  180. package/dist/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  181. package/dist/templates/chat/app/routes/extensions._index.tsx +2 -2
  182. package/dist/templates/chat/netlify.toml +1 -0
  183. package/dist/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  184. package/dist/vite/client.d.ts.map +1 -1
  185. package/dist/vite/client.js +2 -0
  186. package/dist/vite/client.js.map +1 -1
  187. package/docs/content/extensions.mdx +23 -4
  188. package/package.json +1 -1
  189. package/src/agent/production-agent.ts +4 -0
  190. package/src/agent/run-manager.ts +36 -10
  191. package/src/agent/types.ts +2 -0
  192. package/src/client/MultiTabAssistantChat.tsx +45 -0
  193. package/src/client/extensions/ExtensionsListPage.tsx +16 -3
  194. package/src/client/settings/ExtensionsSettingsContent.tsx +24 -0
  195. package/src/client/settings/SettingsPanel.tsx +10 -0
  196. package/src/client/use-chat-models.ts +45 -0
  197. package/src/deploy/build.ts +3 -0
  198. package/src/server/analytics.ts +164 -20
  199. package/src/server/auth.ts +17 -13
  200. package/src/server/better-auth-instance.ts +13 -1
  201. package/src/templates/chat/app/components/layout/Sidebar.tsx +35 -6
  202. package/src/templates/chat/app/routes/extensions._index.tsx +2 -2
  203. package/src/templates/chat/netlify.toml +1 -0
  204. package/src/templates/workspace-core/.agents/skills/extensions/SKILL.md +16 -0
  205. package/src/vite/client.ts +6 -0
  206. package/corpus/templates/analytics/app/components/layout/NewAnalysisDialog.tsx +0 -165
  207. package/corpus/templates/analytics/app/pages/analyses/AnalysesList.tsx +0 -175
@@ -510,19 +510,40 @@ function renderFormPage(
510
510
  var condVal = el.dataset.condVal;
511
511
  var depVal = getFieldValue(depId);
512
512
  var show = true;
513
- if (op === "equals") show = depVal === condVal;
513
+ if (Array.isArray(depVal)) {
514
+ if (op === "equals") show = depVal.length === 1 && depVal[0] === condVal;
515
+ else if (op === "not_equals") show = depVal.indexOf(condVal) < 0;
516
+ else if (op === "contains") show = depVal.indexOf(condVal) >= 0;
517
+ } else if (op === "equals") show = depVal === condVal;
514
518
  else if (op === "not_equals") show = depVal !== condVal;
515
519
  else if (op === "contains") show = depVal.indexOf(condVal) >= 0;
516
520
  el.style.display = show ? "" : "none";
517
521
  el.dataset.hidden = show ? "" : "1";
522
+ el.querySelectorAll("input, textarea, select, button").forEach(function(control) {
523
+ control.disabled = !show;
524
+ });
518
525
  });
519
526
  }
520
527
 
521
528
  function getFieldValue(id) {
522
- var el = document.querySelector('[name="' + id + '"]');
523
- if (!el) return "";
524
- if (el.type === "checkbox" && !el.closest(".ms-group")) return el.checked ? "true" : "";
525
- return el.value || "";
529
+ var controls = document.getElementsByName(id);
530
+ if (!controls.length) return "";
531
+ var first = controls[0];
532
+ if (first.type === "checkbox") {
533
+ if (controls.length > 1) {
534
+ return Array.prototype.map.call(controls, function(control) {
535
+ return control.checked ? control.value : "";
536
+ }).filter(Boolean);
537
+ }
538
+ return first.checked ? "true" : "false";
539
+ }
540
+ if (first.type === "radio") {
541
+ for (var i = 0; i < controls.length; i++) {
542
+ if (controls[i].checked) return controls[i].value || "";
543
+ }
544
+ return "";
545
+ }
546
+ return first.value || "";
526
547
  }
527
548
 
528
549
  document.getElementById("mainForm").addEventListener("input", updateVisibility);
@@ -4,6 +4,7 @@
4
4
  // runtime — an unrestricted id like `x" onfocus="alert(1)` would otherwise
5
5
  // stored-XSS every anonymous submitter of a published form.
6
6
  export const FIELD_ID_PATTERN = /^[A-Za-z0-9_-]+$/;
7
+ const CONDITIONAL_OPERATORS = new Set(["equals", "not_equals", "contains"]);
7
8
 
8
9
  export function assertValidFields(fields: unknown): void {
9
10
  if (!Array.isArray(fields)) {
@@ -28,17 +29,30 @@ export function assertValidFields(fields: unknown): void {
28
29
  seenIds.add(id);
29
30
 
30
31
  const cond = f.conditional;
31
- if (cond && typeof cond === "object") {
32
- const condFieldId = (cond as Record<string, unknown>).fieldId;
33
- if (condFieldId !== undefined) {
34
- if (
35
- typeof condFieldId !== "string" ||
36
- !FIELD_ID_PATTERN.test(condFieldId)
37
- ) {
38
- throw new Error(
39
- `field #${idx + 1} conditional.fieldId ${JSON.stringify(condFieldId)} is invalid — must match ${FIELD_ID_PATTERN.source}`,
40
- );
41
- }
32
+ if (cond !== undefined) {
33
+ if (cond == null || typeof cond !== "object") {
34
+ throw new Error(`field #${idx + 1} conditional must be an object`);
35
+ }
36
+ const condition = cond as Record<string, unknown>;
37
+ const condFieldId = condition.fieldId;
38
+ if (
39
+ typeof condFieldId !== "string" ||
40
+ !FIELD_ID_PATTERN.test(condFieldId)
41
+ ) {
42
+ throw new Error(
43
+ `field #${idx + 1} conditional.fieldId ${JSON.stringify(condFieldId)} is invalid — must match ${FIELD_ID_PATTERN.source}`,
44
+ );
45
+ }
46
+ if (
47
+ typeof condition.operator !== "string" ||
48
+ !CONDITIONAL_OPERATORS.has(condition.operator)
49
+ ) {
50
+ throw new Error(
51
+ `field #${idx + 1} conditional.operator must be equals, not_equals, or contains`,
52
+ );
53
+ }
54
+ if (typeof condition.value !== "string") {
55
+ throw new Error(`field #${idx + 1} conditional.value must be a string`);
42
56
  }
43
57
  }
44
58
 
@@ -69,4 +83,27 @@ export function assertValidFields(fields: unknown): void {
69
83
  }
70
84
  }
71
85
  }
86
+
87
+ const fieldIndexes = new Map(
88
+ fields.map((field, index) => [
89
+ (field as Record<string, unknown>).id,
90
+ index,
91
+ ]),
92
+ );
93
+ for (const [idx, field] of fields.entries()) {
94
+ const condition = (field as Record<string, unknown>).conditional;
95
+ if (!condition || typeof condition !== "object") continue;
96
+ const condFieldId = (condition as Record<string, unknown>).fieldId;
97
+ const sourceIndex = fieldIndexes.get(condFieldId);
98
+ if (sourceIndex === undefined) {
99
+ throw new Error(
100
+ `field #${idx + 1} conditional.fieldId ${JSON.stringify(condFieldId)} does not reference a field in this form`,
101
+ );
102
+ }
103
+ if (sourceIndex >= idx) {
104
+ throw new Error(
105
+ `field #${idx + 1} conditional.fieldId must reference an earlier field`,
106
+ );
107
+ }
108
+ }
72
109
  }
@@ -18,6 +18,7 @@ Core rules:
18
18
  - When the user asks for an anonymous feedback form or survey, create the complete form atomically with \`status: "published"\`, then return the exact public response URL from the successful action result. Do not return only the private editor link, and do not claim it is live without verifying the saved status and fields.
19
19
  - Use \`preview-form\` when the user asks about a form's setup, fields, configuration, publish state, or response count. It renders a native chat summary.
20
20
  - When the user wants email notifications for new responses, set \`settings.emailOnNewResponses: true\` with \`create-form\` or \`update-form\`; notifications go to the form owner's account email.
21
+ - When the user wants Slack, Discord, Google Sheets, or webhook notifications, explain that Forms already supports them from the form builder's Integrations tab and navigate there with \`tab: "integrations"\`. Slack uses an Incoming Webhook URL; Google Sheets uses a deployed Apps Script \`/exec\` URL that parses \`e.postData.contents\`. Do not redirect users to the managed Messaging integration for these form destinations.
21
22
  - Use \`response-insights\` for response analytics. Do not invent SQL or fake chart data. Pass \`displayMode: "chart"\` for chart-only requests, \`displayMode: "table"\` only when the user asks for a table/rows, and \`displayMode: "insights"\` only for combined dashboards or reports.
22
23
  - Use \`list-responses\` and \`export-responses\` for response data review and export. When the user asks to see, open, or view all responses for a form, call \`navigate\` with \`view: "responses"\` instead of listing rows in chat.
23
24
  - Use \`navigate\` to open focused workspace views such as the forms list, builder, published preview, responses, response insights, extensions, or team/settings views. For builder sub-tabs, pass \`view=form\`, the form ID, and \`tab=edit|responses|settings|integrations\`.
@@ -0,0 +1,67 @@
1
+ import type { FormField } from "./types.js";
2
+
3
+ export function conditionalValue(value: unknown): string {
4
+ if (Array.isArray(value)) return value.map(conditionalValue).join(",");
5
+ if (value === true) return "true";
6
+ if (value === false) return "false";
7
+ if (value == null) return "";
8
+ return String(value);
9
+ }
10
+
11
+ export function isConditionalFieldVisible(
12
+ field: Pick<FormField, "conditional">,
13
+ values: Record<string, unknown>,
14
+ ): boolean {
15
+ const condition = field.conditional;
16
+ if (!condition) return true;
17
+
18
+ if (
19
+ typeof condition.fieldId !== "string" ||
20
+ typeof condition.value !== "string"
21
+ ) {
22
+ return false;
23
+ }
24
+
25
+ const rawValue = values[condition.fieldId];
26
+ if (Array.isArray(rawValue)) {
27
+ const selectedValues = rawValue.map(conditionalValue);
28
+ switch (condition.operator) {
29
+ case "equals":
30
+ return (
31
+ selectedValues.length === 1 && selectedValues[0] === condition.value
32
+ );
33
+ case "not_equals":
34
+ return !selectedValues.includes(condition.value);
35
+ case "contains":
36
+ return selectedValues.includes(condition.value);
37
+ default:
38
+ return false;
39
+ }
40
+ }
41
+
42
+ const currentValue = conditionalValue(rawValue);
43
+ switch (condition.operator) {
44
+ case "equals":
45
+ return currentValue === condition.value;
46
+ case "not_equals":
47
+ return currentValue !== condition.value;
48
+ case "contains":
49
+ return currentValue.includes(condition.value);
50
+ default:
51
+ return false;
52
+ }
53
+ }
54
+
55
+ export function sanitizeConditionalValues(
56
+ fields: FormField[],
57
+ values: Record<string, unknown>,
58
+ ): Record<string, unknown> {
59
+ const visibleValues: Record<string, unknown> = {};
60
+ for (const field of fields) {
61
+ if (!isConditionalFieldVisible(field, visibleValues)) continue;
62
+ if (Object.prototype.hasOwnProperty.call(values, field.id)) {
63
+ visibleValues[field.id] = values[field.id];
64
+ }
65
+ }
66
+ return visibleValues;
67
+ }
@@ -1,7 +1,6 @@
1
1
  import { AgentSidebar } from "@agent-native/core/client/agent-chat";
2
2
  import { agentNativePath, appPath } from "@agent-native/core/client/api-path";
3
3
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
4
- import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
5
4
  import { useT } from "@agent-native/core/client/i18n";
6
5
  import { OrgSwitcher } from "@agent-native/core/client/org";
7
6
  import { FeedbackButton } from "@agent-native/core/client/ui";
@@ -39,6 +38,9 @@ import { Header } from "./Header";
39
38
  const navItems = [
40
39
  { icon: IconFlame, labelKey: "navigation.entry", href: "/" },
41
40
  { icon: IconChartBar, labelKey: "navigation.analytics", href: "/analytics" },
41
+ ];
42
+
43
+ const bottomNavItems = [
42
44
  { icon: IconHierarchy2, labelKey: "settings.agentTitle", href: "/agent" },
43
45
  { icon: IconSettings, labelKey: "navigation.settings", href: "/settings" },
44
46
  ];
@@ -287,12 +289,41 @@ function SidebarContent({
287
289
  })}
288
290
  </nav>
289
291
 
292
+ <nav className="grid shrink-0 gap-1 px-2 py-1">
293
+ {bottomNavItems.map((item) => {
294
+ const Icon = item.icon;
295
+ const label = t(item.labelKey);
296
+ const isActive = pathname.startsWith(item.href);
297
+ const link = (
298
+ <Link
299
+ key={item.href}
300
+ to={item.href}
301
+ aria-label={collapsed ? label : undefined}
302
+ className={cn(
303
+ "flex h-9 items-center rounded-lg text-sm transition-colors",
304
+ collapsed ? "justify-center px-0" : "gap-3 px-3",
305
+ isActive
306
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
307
+ : "text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground",
308
+ )}
309
+ >
310
+ <Icon className="h-4 w-4 shrink-0" />
311
+ {!collapsed && label}
312
+ </Link>
313
+ );
314
+ return collapsed ? (
315
+ <Tooltip key={item.href}>
316
+ <TooltipTrigger asChild>{link}</TooltipTrigger>
317
+ <TooltipContent side="right">{label}</TooltipContent>
318
+ </Tooltip>
319
+ ) : (
320
+ link
321
+ );
322
+ })}
323
+ </nav>
324
+
290
325
  {!collapsed && (
291
326
  <>
292
- <div className="px-2 py-2">
293
- <ExtensionsSidebarSection />
294
- </div>
295
-
296
327
  <div className="space-y-2 px-3 py-2">
297
328
  <DevDatabaseLink />
298
329
  <FeedbackButton />
@@ -1,4 +1,4 @@
1
- import { ExtensionsListPage } from "@agent-native/core/client/extensions";
1
+ import { Navigate } from "react-router";
2
2
 
3
3
  import messages from "@/i18n/en-US";
4
4
 
@@ -7,5 +7,5 @@ export function meta() {
7
7
  }
8
8
 
9
9
  export default function ExtensionsRoute() {
10
- return <ExtensionsListPage />;
10
+ return <Navigate to="/settings#extensions" replace />;
11
11
  }
@@ -6,5 +6,6 @@ functions = "templates/macros/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
8
  GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
+ GTM_CONTAINER_ID = "GTM-N3WSTXZ"
9
10
  NITRO_PRESET = "netlify"
10
11
  NPM_CONFIG_PRODUCTION = "false"
@@ -5,7 +5,6 @@ import {
5
5
  import { agentNativePath } from "@agent-native/core/client/api-path";
6
6
  import { appApiPath } from "@agent-native/core/client/api-path";
7
7
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
8
- import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
9
8
  import { useT } from "@agent-native/core/client/i18n";
10
9
  import { InvitationBanner, OrgSwitcher } from "@agent-native/core/client/org";
11
10
  import { FeedbackButton } from "@agent-native/core/client/ui";
@@ -1740,10 +1739,6 @@ function AppLayoutInner({ children }: AppLayoutProps) {
1740
1739
  </div>
1741
1740
 
1742
1741
  <div className="shrink-0">
1743
- <div className="px-2 py-1">
1744
- <ExtensionsSidebarSection />
1745
- </div>
1746
-
1747
1742
  <div className="px-3 py-2">
1748
1743
  <OrgSwitcher />
1749
1744
  </div>
@@ -2112,10 +2107,6 @@ function StandardLayout({ children }: AppLayoutProps) {
2112
2107
  </div>
2113
2108
 
2114
2109
  <div className="shrink-0">
2115
- <div className="px-2 py-1">
2116
- <ExtensionsSidebarSection />
2117
- </div>
2118
-
2119
2110
  <div className="px-3 py-2">
2120
2111
  <OrgSwitcher />
2121
2112
  </div>
@@ -1,5 +1,5 @@
1
- import { ExtensionsListPage } from "@agent-native/core/client/extensions";
1
+ import { Navigate } from "react-router";
2
2
 
3
3
  export default function ExtensionsRoute() {
4
- return <ExtensionsListPage />;
4
+ return <Navigate to="/settings#extensions" replace />;
5
5
  }
@@ -6,6 +6,7 @@ functions = "templates/mail/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
8
  GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
+ GTM_CONTAINER_ID = "GTM-N3WSTXZ"
9
10
  NITRO_PRESET = "netlify"
10
11
  NPM_CONFIG_PRODUCTION = "false"
11
12
 
@@ -9,7 +9,6 @@ import { useCodeMode } from "@agent-native/core/client/agent-chat";
9
9
  import { agentNativePath, appPath } from "@agent-native/core/client/api-path";
10
10
  import { PromptComposer } from "@agent-native/core/client/composer";
11
11
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
12
- import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
13
12
  import { useSession } from "@agent-native/core/client/hooks";
14
13
  import { useT } from "@agent-native/core/client/i18n";
15
14
  import { OrgSwitcher } from "@agent-native/core/client/org";
@@ -73,6 +72,9 @@ function buildBrandingCustomizationMessage(request: string) {
73
72
  const navItems = [
74
73
  { icon: IconMessageCircle, labelKey: "navigation.ask", href: "/" },
75
74
  { icon: IconClipboardCheck, labelKey: "navigation.plan", href: "/plans" },
75
+ ];
76
+
77
+ const bottomNavItems = [
76
78
  { icon: IconHierarchy2, labelKey: "settings.agentTitle", href: "/agent" },
77
79
  { icon: IconSettings, labelKey: "navigation.settings", href: "/settings" },
78
80
  ];
@@ -638,12 +640,43 @@ export function Sidebar({
638
640
  })}
639
641
  </nav>
640
642
 
643
+ <nav className="grid shrink-0 gap-1 px-2 py-1">
644
+ {bottomNavItems.map((item) => {
645
+ const Icon = item.icon;
646
+ const isActive = location.pathname.startsWith(item.href);
647
+ const link = (
648
+ <Link
649
+ to={item.href}
650
+ className={cn(
651
+ "flex items-center gap-3 rounded-lg px-3 py-2 text-sm transition-colors",
652
+ isActive
653
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
654
+ : "text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground",
655
+ collapsed && "justify-center gap-0 px-0",
656
+ )}
657
+ aria-label={collapsed ? t(item.labelKey) : undefined}
658
+ >
659
+ <Icon className="h-4 w-4 shrink-0" />
660
+ {collapsed ? (
661
+ <span className="sr-only">{t(item.labelKey)}</span>
662
+ ) : (
663
+ t(item.labelKey)
664
+ )}
665
+ </Link>
666
+ );
667
+ return collapsed ? (
668
+ <Tooltip key={item.href}>
669
+ <TooltipTrigger asChild>{link}</TooltipTrigger>
670
+ <TooltipContent side="right">{t(item.labelKey)}</TooltipContent>
671
+ </Tooltip>
672
+ ) : (
673
+ <div key={item.href}>{link}</div>
674
+ );
675
+ })}
676
+ </nav>
677
+
641
678
  {!collapsed && session ? (
642
679
  <>
643
- <div className="px-2 py-2">
644
- <ExtensionsSidebarSection />
645
- </div>
646
-
647
680
  <div className="space-y-2 px-3 py-2">
648
681
  <DevDatabaseLink />
649
682
  <div className="flex items-center justify-end gap-1">
@@ -1,4 +1,4 @@
1
- import { ExtensionsListPage } from "@agent-native/core/client/extensions";
1
+ import { Navigate } from "react-router";
2
2
 
3
3
  import { APP_TITLE } from "@/lib/app-config";
4
4
 
@@ -7,5 +7,5 @@ export function meta() {
7
7
  }
8
8
 
9
9
  export default function ExtensionsRoute() {
10
- return <ExtensionsListPage />;
10
+ return <Navigate to="/settings#extensions" replace />;
11
11
  }
@@ -6,6 +6,7 @@ functions = "templates/plan/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
8
  GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
+ GTM_CONTAINER_ID = "GTM-N3WSTXZ"
9
10
  NITRO_PRESET = "netlify"
10
11
  NPM_CONFIG_PRODUCTION = "false"
11
12
  AGENT_CHAT_DURABLE_BACKGROUND = "true"
@@ -1,6 +1,5 @@
1
1
  import { appPath } from "@agent-native/core/client/api-path";
2
2
  import { DevDatabaseLink } from "@agent-native/core/client/db-admin";
3
- import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
4
3
  import { useT } from "@agent-native/core/client/i18n";
5
4
  import { OrgSwitcher } from "@agent-native/core/client/org";
6
5
  import { FeedbackButton } from "@agent-native/core/client/ui";
@@ -28,6 +27,9 @@ const navItems = [
28
27
  labelKey: "navigation.designSystems",
29
28
  href: "/design-systems",
30
29
  },
30
+ ];
31
+
32
+ const bottomNavItems = [
31
33
  { icon: IconHierarchy2, labelKey: "settings.agentTitle", href: "/agent" },
32
34
  { icon: IconSettings, labelKey: "navigation.settings", href: "/settings" },
33
35
  ];
@@ -92,6 +94,29 @@ export function Sidebar({ collapsed, onToggleCollapsed }: SidebarProps) {
92
94
  );
93
95
  })}
94
96
  </nav>
97
+ <nav className="flex shrink-0 flex-col items-center gap-1 py-1">
98
+ {bottomNavItems.map((item) => {
99
+ const Icon = item.icon;
100
+ return (
101
+ <Tooltip key={item.href} delayDuration={0}>
102
+ <TooltipTrigger asChild>
103
+ <Link
104
+ to={item.href}
105
+ aria-label={t(item.labelKey)}
106
+ className={cn(
107
+ "flex h-9 w-9 items-center justify-center rounded-md text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground",
108
+ isItemActive(item.href) &&
109
+ "bg-sidebar-accent text-sidebar-accent-foreground",
110
+ )}
111
+ >
112
+ <Icon className="h-4 w-4 shrink-0" />
113
+ </Link>
114
+ </TooltipTrigger>
115
+ <TooltipContent side="right">{t(item.labelKey)}</TooltipContent>
116
+ </Tooltip>
117
+ );
118
+ })}
119
+ </nav>
95
120
  </aside>
96
121
  );
97
122
  }
@@ -156,9 +181,27 @@ export function Sidebar({ collapsed, onToggleCollapsed }: SidebarProps) {
156
181
  </nav>
157
182
 
158
183
  <div className="mt-auto shrink-0">
159
- <div className="px-2 py-1">
160
- <ExtensionsSidebarSection />
161
- </div>
184
+ <nav className="space-y-1 px-2 py-1">
185
+ {bottomNavItems.map((item) => {
186
+ const Icon = item.icon;
187
+ const isActive = isItemActive(item.href);
188
+ return (
189
+ <Link
190
+ key={item.href}
191
+ to={item.href}
192
+ className={cn(
193
+ "flex items-center gap-3 rounded-lg px-3 py-2 text-sm",
194
+ isActive
195
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
196
+ : "text-muted-foreground hover:bg-sidebar-accent/50 hover:text-foreground",
197
+ )}
198
+ >
199
+ <Icon className="h-4 w-4 shrink-0" />
200
+ {t(item.labelKey)}
201
+ </Link>
202
+ );
203
+ })}
204
+ </nav>
162
205
 
163
206
  <div className="px-3 py-2">
164
207
  <OrgSwitcher />
@@ -1,5 +1,5 @@
1
- import { ExtensionsListPage } from "@agent-native/core/client/extensions";
1
+ import { Navigate } from "react-router";
2
2
 
3
3
  export default function ExtensionsRoute() {
4
- return <ExtensionsListPage />;
4
+ return <Navigate to="/settings#extensions" replace />;
5
5
  }
@@ -6,6 +6,7 @@ functions = "templates/slides/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
8
  GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
+ GTM_CONTAINER_ID = "GTM-N3WSTXZ"
9
10
  NITRO_PRESET = "netlify"
10
11
  NPM_CONFIG_PRODUCTION = "false"
11
12
  AGENT_CHAT_DURABLE_BACKGROUND = "true"
@@ -1,5 +1,4 @@
1
1
  import { appPath } from "@agent-native/core/client/api-path";
2
- import { ExtensionsSidebarSection } from "@agent-native/core/client/extensions";
3
2
  import { useT } from "@agent-native/core/client/i18n";
4
3
  import { OrgSwitcher } from "@agent-native/core/client/org";
5
4
  import { FeedbackButton } from "@agent-native/core/client/ui";
@@ -9,6 +8,7 @@ import {
9
8
  IconInbox,
10
9
  IconLayoutSidebarLeftCollapse,
11
10
  IconLayoutSidebarLeftExpand,
11
+ IconSettings,
12
12
  } from "@tabler/icons-react";
13
13
  import { Link, useLocation } from "react-router";
14
14
 
@@ -26,6 +26,10 @@ const NAV_ITEMS = [
26
26
  { icon: IconForms, labelKey: "sidebar.navFields", href: "/fields" },
27
27
  ];
28
28
 
29
+ const BOTTOM_NAV_ITEMS = [
30
+ { icon: IconSettings, labelKey: "header.pageSettings", href: "/settings" },
31
+ ];
32
+
29
33
  interface SidebarProps {
30
34
  collapsed?: boolean;
31
35
  collapsible?: boolean;
@@ -165,11 +169,38 @@ export function Sidebar({
165
169
  collapsed && "border-t border-sidebar-border py-2",
166
170
  )}
167
171
  >
168
- {!collapsed ? (
169
- <div className="border-t border-sidebar-border px-2 py-1">
170
- <ExtensionsSidebarSection />
171
- </div>
172
- ) : null}
172
+ <nav
173
+ className={cn(
174
+ "grid gap-1",
175
+ collapsed
176
+ ? "px-1 py-1"
177
+ : "border-t border-sidebar-border px-3 py-2",
178
+ )}
179
+ >
180
+ {BOTTOM_NAV_ITEMS.map((item) => {
181
+ const Icon = item.icon;
182
+ const isActive = location.pathname.startsWith(item.href);
183
+ return (
184
+ <Link
185
+ key={item.href}
186
+ to={item.href}
187
+ aria-label={collapsed ? t(item.labelKey) : undefined}
188
+ className={cn(
189
+ "flex items-center rounded-md text-sm",
190
+ collapsed ? "h-9 justify-center px-0" : "gap-3 px-3 py-2",
191
+ isActive
192
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
193
+ : "text-sidebar-foreground hover:bg-sidebar-accent/65 hover:text-sidebar-accent-foreground",
194
+ )}
195
+ >
196
+ <Icon className="size-4 shrink-0" />
197
+ <span className={collapsed ? "sr-only" : "truncate"}>
198
+ {t(item.labelKey)}
199
+ </span>
200
+ </Link>
201
+ );
202
+ })}
203
+ </nav>
173
204
 
174
205
  <div
175
206
  className={cn(
@@ -1,4 +1,4 @@
1
- import { ExtensionsListPage } from "@agent-native/core/client/extensions";
1
+ import { Navigate } from "react-router";
2
2
 
3
3
  import messages from "@/i18n/en-US";
4
4
  import { APP_TITLE } from "@/lib/app-config";
@@ -8,5 +8,5 @@ export function meta() {
8
8
  }
9
9
 
10
10
  export default function ExtensionsRoute() {
11
- return <ExtensionsListPage />;
11
+ return <Navigate to="/settings#extensions" replace />;
12
12
  }
@@ -0,0 +1,31 @@
1
+ import { useT } from "@agent-native/core/client/i18n";
2
+ import {
3
+ SettingsTabsPage,
4
+ useAgentSettingsTabs,
5
+ } from "@agent-native/core/client/settings";
6
+ import { useSetPageTitle } from "@agent-native/toolkit/app-shell";
7
+
8
+ import { APP_TITLE } from "@/lib/app-config";
9
+
10
+ export function meta() {
11
+ return [{ title: `Settings - ${APP_TITLE}` }];
12
+ }
13
+
14
+ export default function SettingsRoute() {
15
+ const t = useT();
16
+ const agentSettingsTabs = useAgentSettingsTabs();
17
+ useSetPageTitle(t("header.pageSettings"));
18
+
19
+ return (
20
+ <SettingsTabsPage
21
+ extraTabs={agentSettingsTabs}
22
+ general={
23
+ <div className="mx-auto w-full max-w-2xl">
24
+ <p className="text-sm leading-6 text-muted-foreground">
25
+ {t("header.pageSettings")}
26
+ </p>
27
+ </div>
28
+ }
29
+ />
30
+ );
31
+ }
@@ -6,5 +6,6 @@ functions = "templates/tasks/.netlify/functions-internal"
6
6
 
7
7
  [build.environment]
8
8
  GA_MEASUREMENT_ID = "G-ESF7FYXGN9"
9
+ GTM_CONTAINER_ID = "GTM-N3WSTXZ"
9
10
  NITRO_PRESET = "netlify"
10
11
  NPM_CONFIG_PRODUCTION = "false"