@agent-native/core 0.146.8 → 0.147.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 (169) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/turn-into-app/SKILL.md +18 -6
  3. package/corpus/templates/analytics/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  4. package/corpus/templates/analytics/app/routes/status.$slug.tsx +4 -2
  5. package/corpus/templates/analytics/scripts/first-party-analytics-bigquery-backfill.ts +56 -6
  6. package/corpus/templates/assets/.agents/skills/turn-into-app/SKILL.md +18 -6
  7. package/corpus/templates/assets/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  8. package/corpus/templates/brain/.agents/skills/adding-a-feature/SKILL.md +9 -0
  9. package/corpus/templates/brain/.agents/skills/turn-into-app/SKILL.md +18 -6
  10. package/corpus/templates/brain/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  11. package/corpus/templates/calendar/.agents/skills/turn-into-app/SKILL.md +18 -6
  12. package/corpus/templates/calendar/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  13. package/corpus/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  14. package/corpus/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  15. package/corpus/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  16. package/corpus/templates/clips/.agents/skills/turn-into-app/SKILL.md +18 -6
  17. package/corpus/templates/clips/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  18. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +16 -4
  19. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +14 -5
  20. package/corpus/templates/clips/package.json +1 -0
  21. package/corpus/templates/clips/react-router.config.ts +7 -0
  22. package/corpus/templates/clips/server/plugins/auth.ts +6 -1
  23. package/corpus/templates/clips/shared/prerendered-public-paths.ts +21 -0
  24. package/corpus/templates/clips/shared/share-meta.ts +8 -3
  25. package/corpus/templates/content/.agents/skills/turn-into-app/SKILL.md +18 -6
  26. package/corpus/templates/content/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  27. package/corpus/templates/crm/.agents/skills/turn-into-app/SKILL.md +18 -6
  28. package/corpus/templates/crm/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  29. package/corpus/templates/design/.agents/skills/turn-into-app/SKILL.md +18 -6
  30. package/corpus/templates/design/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  31. package/corpus/templates/dispatch/.agents/skills/turn-into-app/SKILL.md +18 -6
  32. package/corpus/templates/dispatch/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  33. package/corpus/templates/dispatch/app/chat-first-pages.ts +747 -0
  34. package/corpus/templates/dispatch/app/i18n-data.ts +181 -0
  35. package/corpus/templates/dispatch/app/routes/settings.tsx +62 -1
  36. package/corpus/templates/dispatch/changelog/2026-08-08-chat-first-navigation-keeps-conversations-central-while-open.md +6 -0
  37. package/corpus/templates/factory/.agents/skills/adding-a-feature/SKILL.md +9 -0
  38. package/corpus/templates/factory/.agents/skills/turn-into-app/SKILL.md +18 -6
  39. package/corpus/templates/factory/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  40. package/corpus/templates/factory/app/routes/factory.tsx +108 -76
  41. package/corpus/templates/factory/changelog/2026-08-08-scheduler-health-moves-to-settings.md +6 -0
  42. package/corpus/templates/forms/.agents/skills/turn-into-app/SKILL.md +18 -6
  43. package/corpus/templates/forms/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  44. package/corpus/templates/macros/.agents/skills/turn-into-app/SKILL.md +18 -6
  45. package/corpus/templates/macros/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  46. package/corpus/templates/mail/.agents/skills/turn-into-app/SKILL.md +18 -6
  47. package/corpus/templates/mail/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  48. package/corpus/templates/plan/.agents/skills/adding-a-feature/SKILL.md +9 -0
  49. package/corpus/templates/plan/.agents/skills/turn-into-app/SKILL.md +18 -6
  50. package/corpus/templates/plan/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  51. package/corpus/templates/plan/app/lib/plan-document-title.ts +3 -1
  52. package/corpus/templates/plan/app/root.tsx +1 -0
  53. package/corpus/templates/slides/.agents/skills/turn-into-app/SKILL.md +18 -6
  54. package/corpus/templates/slides/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  55. package/corpus/templates/tasks/.agents/skills/adding-a-feature/SKILL.md +9 -0
  56. package/corpus/templates/tasks/.agents/skills/turn-into-app/SKILL.md +18 -6
  57. package/corpus/templates/tasks/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  58. package/dist/agent/engine/builder-engine.d.ts +11 -1
  59. package/dist/agent/engine/builder-engine.js +11 -4
  60. package/dist/chat-threads/store.d.ts +2 -0
  61. package/dist/chat-threads/store.js +1 -1
  62. package/dist/cli/agent-plugin.d.ts +5 -2
  63. package/dist/cli/agent-plugin.js +17 -9
  64. package/dist/cli/code-agent-executor.js +25 -5
  65. package/dist/cli/code-agent-mcp-config.d.ts +21 -0
  66. package/dist/cli/code-agent-mcp-config.js +103 -0
  67. package/dist/client/NewWorkspaceAppFlow.js +4 -1
  68. package/dist/client/agent-chat/index.d.ts +4 -1
  69. package/dist/client/agent-chat/index.js +4 -1
  70. package/dist/client/agent-page/AgentTabsPage.d.ts +1 -0
  71. package/dist/client/agent-page/AgentTabsPage.js +4 -3
  72. package/dist/client/app-providers.d.ts +3 -1
  73. package/dist/client/app-providers.js +50 -5
  74. package/dist/client/chat/runtime.js +63 -0
  75. package/dist/client/chat-first/agents-pane.d.ts +2 -0
  76. package/dist/client/chat-first/agents-pane.js +6 -0
  77. package/dist/client/chat-first/app-pane.d.ts +2 -0
  78. package/dist/client/chat-first/app-pane.js +6 -0
  79. package/dist/client/chat-first/apps-rail.d.ts +2 -0
  80. package/dist/client/chat-first/apps-rail.js +103 -0
  81. package/dist/client/chat-first/browser-pane.d.ts +2 -0
  82. package/dist/client/chat-first/browser-pane.js +64 -0
  83. package/dist/client/chat-first/chat-history.d.ts +12 -0
  84. package/dist/client/chat-first/chat-history.js +10 -0
  85. package/dist/client/chat-first/copy.d.ts +2 -0
  86. package/dist/client/chat-first/copy.js +117 -0
  87. package/dist/client/chat-first/index.d.ts +13 -0
  88. package/dist/client/chat-first/index.js +12 -0
  89. package/dist/client/chat-first/primary-nav.d.ts +8 -0
  90. package/dist/client/chat-first/primary-nav.js +6 -0
  91. package/dist/client/chat-first/session-watch-pane.d.ts +2 -0
  92. package/dist/client/chat-first/session-watch-pane.js +9 -0
  93. package/dist/client/chat-first/surface-panel.d.ts +9 -0
  94. package/dist/client/chat-first/surface-panel.js +9 -0
  95. package/dist/client/chat-first/surface-tabs.d.ts +9 -0
  96. package/dist/client/chat-first/surface-tabs.js +74 -0
  97. package/dist/client/chat-first/types.d.ts +74 -0
  98. package/dist/client/chat-first/types.js +1 -0
  99. package/dist/client/chat-first-agent-activity.d.ts +11 -0
  100. package/dist/client/chat-first-agent-activity.js +51 -0
  101. package/dist/client/chat-first-surface-panel-toggle.d.ts +5 -0
  102. package/dist/client/chat-first-surface-panel-toggle.js +6 -0
  103. package/dist/client/chat-first.d.ts +208 -0
  104. package/dist/client/chat-first.js +816 -0
  105. package/dist/client/extensions/ExtensionViewer.js +8 -1
  106. package/dist/client/resources/McpIntegrationDialog.js +3 -2
  107. package/dist/client/resources/McpServerDetail.js +6 -11
  108. package/dist/client/resources/index.d.ts +1 -0
  109. package/dist/client/resources/index.js +1 -0
  110. package/dist/client/resources/use-mcp-servers.d.ts +20 -0
  111. package/dist/client/resources/use-mcp-servers.js +82 -46
  112. package/dist/client/settings/index.d.ts +1 -0
  113. package/dist/client/settings/index.js +1 -0
  114. package/dist/collab/awareness.d.ts +2 -2
  115. package/dist/collab/routes.d.ts +1 -1
  116. package/dist/collab/struct-routes.d.ts +1 -1
  117. package/dist/jobs/background-automation-runner.js +19 -2
  118. package/dist/jobs/scheduler-health.d.ts +20 -0
  119. package/dist/jobs/scheduler-health.js +86 -1
  120. package/dist/jobs/scheduler.js +38 -1
  121. package/dist/mcp-client/routes.d.ts +3 -0
  122. package/dist/mcp-client/routes.js +14 -0
  123. package/dist/notifications/routes.d.ts +1 -1
  124. package/dist/observability/routes.d.ts +5 -5
  125. package/dist/progress/routes.d.ts +1 -1
  126. package/dist/provider-api/actions/provider-api.d.ts +2 -2
  127. package/dist/resources/handlers.d.ts +1 -1
  128. package/dist/secrets/routes.d.ts +3 -3
  129. package/dist/server/agent-engine-api-key-route.d.ts +1 -1
  130. package/dist/server/agents-bundle.d.ts +2 -0
  131. package/dist/server/agents-bundle.js +31 -2
  132. package/dist/server/credential-provider.d.ts +8 -2
  133. package/dist/server/credential-provider.js +13 -9
  134. package/dist/server/realtime-token.d.ts +1 -1
  135. package/dist/server/transcribe-voice.d.ts +1 -1
  136. package/dist/shared/chat-first-app-creation.d.ts +19 -0
  137. package/dist/shared/chat-first-app-creation.js +75 -0
  138. package/dist/shared/document-title.d.ts +7 -0
  139. package/dist/shared/document-title.js +29 -0
  140. package/dist/shared/index.d.ts +2 -0
  141. package/dist/shared/index.js +2 -0
  142. package/dist/styles/chat-history-list.css +16 -0
  143. package/dist/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  144. package/dist/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  145. package/dist/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  146. package/dist/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
  147. package/dist/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
  148. package/dist/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  149. package/dist/templates/default/react-router.config.ts +18 -0
  150. package/dist/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
  151. package/dist/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  152. package/dist/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
  153. package/dist/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
  154. package/dist/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  155. package/dist/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
  156. package/package.json +3 -2
  157. package/src/templates/chat/.agents/skills/adding-a-feature/SKILL.md +9 -0
  158. package/src/templates/chat/.agents/skills/turn-into-app/SKILL.md +18 -6
  159. package/src/templates/chat/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  160. package/src/templates/default/.agents/skills/adding-a-feature/SKILL.md +9 -0
  161. package/src/templates/default/.agents/skills/turn-into-app/SKILL.md +18 -6
  162. package/src/templates/default/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  163. package/src/templates/default/react-router.config.ts +18 -0
  164. package/src/templates/headless/.agents/skills/turn-into-app/SKILL.md +18 -6
  165. package/src/templates/headless/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  166. package/src/templates/workspace-core/.agents/skills/adding-a-feature/SKILL.md +9 -0
  167. package/src/templates/workspace-core/.agents/skills/turn-into-app/SKILL.md +18 -6
  168. package/src/templates/workspace-core/.agents/skills/turn-into-app/references/fresh-project.md +8 -1
  169. package/src/templates/workspace-core/.agents/skills/workspace-conventions/SKILL.md +7 -0
@@ -52,7 +52,9 @@ import { Toaster } from "@agent-native/toolkit/ui/sonner";
52
52
  import { TooltipProvider } from "@radix-ui/react-tooltip";
53
53
  import { QueryClientProvider } from "@tanstack/react-query";
54
54
  import { ThemeProvider } from "next-themes";
55
+ import { useEffect, useRef } from "react";
55
56
  import { useInRouterContext } from "react-router";
57
+ import { isHumanReadableDocumentTitle, normalizeDocumentTitle, } from "../shared/document-title.js";
56
58
  import { ClientOnly } from "./ClientOnly.js";
57
59
  import { DefaultSpinner } from "./DefaultSpinner.js";
58
60
  import { AgentNativeI18nProvider, } from "./i18n.js";
@@ -67,14 +69,57 @@ function RoutedAppEnhancements() {
67
69
  return null;
68
70
  return (_jsxs(_Fragment, { children: [_jsx(AgentNativeRouteWarmup, {}), _jsx(RouteTransitionIndicator, {})] }));
69
71
  }
70
- function ProvidersInner({ queryClient, defaultTheme = "system", themeAttribute = "class", tooltipDelayDuration, toaster = DEFAULT_TOASTER, disableThemeTransitions = true, i18n, children, }) {
72
+ function readDocumentTitleFallback() {
73
+ const selectors = [
74
+ 'meta[name="application-name"]',
75
+ 'meta[name="apple-mobile-web-app-title"]',
76
+ 'meta[property="og:site_name"]',
77
+ ];
78
+ const metadataTitle = selectors
79
+ .map((selector) => document.querySelector(selector)?.content ?? "")
80
+ .find((title) => isHumanReadableDocumentTitle(title));
81
+ return normalizeDocumentTitle(metadataTitle, "Agent Native");
82
+ }
83
+ /** Repairs route metadata that would otherwise expose a structured payload in the tab. */
84
+ function DocumentTitleGuard({ fallbackTitle }) {
85
+ const initialTitleRef = useRef(null);
86
+ if (initialTitleRef.current === null && typeof document !== "undefined") {
87
+ const initialTitle = document.title.trim();
88
+ if (isHumanReadableDocumentTitle(initialTitle)) {
89
+ initialTitleRef.current = initialTitle;
90
+ }
91
+ }
92
+ useEffect(() => {
93
+ let lastKnownTitle = normalizeDocumentTitle(initialTitleRef.current ?? fallbackTitle ?? readDocumentTitleFallback(), fallbackTitle ?? "Agent Native");
94
+ const repairTitle = () => {
95
+ const currentTitle = document.title.trim();
96
+ if (isHumanReadableDocumentTitle(currentTitle)) {
97
+ lastKnownTitle = currentTitle;
98
+ return;
99
+ }
100
+ const nextTitle = normalizeDocumentTitle(lastKnownTitle, "Agent Native");
101
+ if (currentTitle !== nextTitle)
102
+ document.title = nextTitle;
103
+ };
104
+ repairTitle();
105
+ const observer = new MutationObserver(repairTitle);
106
+ observer.observe(document.head, {
107
+ characterData: true,
108
+ childList: true,
109
+ subtree: true,
110
+ });
111
+ return () => observer.disconnect();
112
+ }, [fallbackTitle]);
113
+ return null;
114
+ }
115
+ function ProvidersInner({ queryClient, defaultTheme = "system", themeAttribute = "class", tooltipDelayDuration, toaster = DEFAULT_TOASTER, disableThemeTransitions = true, i18n, documentTitleFallback, children, }) {
71
116
  const localizedChildren = i18n === false ? (children) : (_jsx(AgentNativeI18nProvider, { ...(i18n ?? {}), children: children }));
72
- return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemeProvider, { attribute: themeAttribute, defaultTheme: defaultTheme, enableSystem: true, disableTransitionOnChange: disableThemeTransitions, children: _jsxs(TooltipProvider, { delayDuration: tooltipDelayDuration, children: [localizedChildren, _jsx(RuntimeConfigNotice, {}), _jsx(RoutedAppEnhancements, {}), toaster] }) }) }));
117
+ return (_jsx(QueryClientProvider, { client: queryClient, children: _jsx(ThemeProvider, { attribute: themeAttribute, defaultTheme: defaultTheme, enableSystem: true, disableTransitionOnChange: disableThemeTransitions, children: _jsxs(TooltipProvider, { delayDuration: tooltipDelayDuration, children: [localizedChildren, _jsx(DocumentTitleGuard, { fallbackTitle: documentTitleFallback }), _jsx(RuntimeConfigNotice, {}), _jsx(RoutedAppEnhancements, {}), toaster] }) }) }));
73
118
  }
74
- export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFallback, sessionBypass = false, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, children, }) {
119
+ export function AppProviders({ queryClient, isPublicPath = false, clientOnlyFallback, sessionBypass = false, defaultTheme, themeAttribute, tooltipDelayDuration, toaster, disableThemeTransitions, i18n, documentTitleFallback, children, }) {
75
120
  const fallback = clientOnlyFallback ?? _jsx(DefaultSpinner, {});
76
121
  if (isPublicPath) {
77
- return (_jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, children: children }));
122
+ return (_jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, documentTitleFallback: documentTitleFallback, children: children }));
78
123
  }
79
- return (_jsx(ClientOnly, { fallback: fallback, children: _jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, children: _jsx(RequireSession, { bypass: sessionBypass, fallback: fallback, children: children }) }) }));
124
+ return (_jsx(ClientOnly, { fallback: fallback, children: _jsx(ProvidersInner, { queryClient: queryClient, defaultTheme: defaultTheme, themeAttribute: themeAttribute, tooltipDelayDuration: tooltipDelayDuration, toaster: toaster, disableThemeTransitions: disableThemeTransitions, i18n: i18n, documentTitleFallback: documentTitleFallback, children: _jsx(RequireSession, { bypass: sessionBypass, fallback: fallback, children: children }) }) }));
80
125
  }
@@ -1,4 +1,5 @@
1
1
  import { agentNativePath } from "../api-path.js";
2
+ import { emitChatFirstOpenApp, emitChatFirstOpenBrowser, } from "../chat-first.js";
2
3
  import { formatChatErrorText, normalizeChatError } from "../error-format.js";
3
4
  import { settleInterruptedToolCalls, } from "../sse-event-processor.js";
4
5
  const DEFAULT_RUNTIME_CAPABILITIES = {
@@ -977,6 +978,7 @@ export function createAgentChatRuntimeAdapter(runtime, options = {}) {
977
978
  };
978
979
  try {
979
980
  for await (const event of turn.events) {
981
+ emitChatFirstOpenAppFromRuntimeEvent(event);
980
982
  const result = applyRuntimeEventToContent(event, projection);
981
983
  if (result) {
982
984
  const metadata = (result.metadata ?? {});
@@ -1007,3 +1009,64 @@ export function createAgentChatRuntimeAdapter(runtime, options = {}) {
1007
1009
  },
1008
1010
  };
1009
1011
  }
1012
+ function emitChatFirstOpenAppFromRuntimeEvent(event) {
1013
+ if (event.type !== "tool-done")
1014
+ return;
1015
+ const toolEvent = event;
1016
+ if (toolEvent.status !== "completed" ||
1017
+ (!isOpenAppTool(toolEvent.toolName) &&
1018
+ !isOpenBrowserTool(toolEvent.toolName))) {
1019
+ return;
1020
+ }
1021
+ const result = asRecord(toolEvent.result) ?? parseResultRecord(toolEvent.resultText);
1022
+ if (!result) {
1023
+ console.warn(`[chat-first] ${toolEvent.toolName} completed without a readable result`);
1024
+ return;
1025
+ }
1026
+ if (isOpenBrowserTool(toolEvent.toolName)) {
1027
+ const delivery = emitChatFirstOpenBrowser({
1028
+ url: readString(result.url ?? result.href),
1029
+ title: readString(result.title ?? result.name),
1030
+ });
1031
+ warnWhenChatFirstDeliveryIsNotObserved(toolEvent.toolName, delivery);
1032
+ return;
1033
+ }
1034
+ const detail = {
1035
+ app: readString(result.app ?? result.appId ?? result.application),
1036
+ path: readString(result.path ?? result.targetPath),
1037
+ url: readString(result.url ?? result.href),
1038
+ view: readString(result.view),
1039
+ };
1040
+ const delivery = emitChatFirstOpenApp(detail);
1041
+ warnWhenChatFirstDeliveryIsNotObserved(toolEvent.toolName, delivery);
1042
+ }
1043
+ function warnWhenChatFirstDeliveryIsNotObserved(toolName, delivery) {
1044
+ if (delivery.delivered)
1045
+ return;
1046
+ console.warn(`[chat-first] ${toolName} was completed but not delivered (${delivery.reason ?? "unknown"})`);
1047
+ }
1048
+ function isOpenAppTool(toolName) {
1049
+ return toolName === "open_app";
1050
+ }
1051
+ function isOpenBrowserTool(toolName) {
1052
+ return toolName === "open_browser";
1053
+ }
1054
+ function asRecord(value) {
1055
+ return value && typeof value === "object" && !Array.isArray(value)
1056
+ ? value
1057
+ : null;
1058
+ }
1059
+ function readString(value) {
1060
+ return typeof value === "string" && value.trim() ? value : undefined;
1061
+ }
1062
+ function parseResultRecord(value) {
1063
+ if (!value?.trim())
1064
+ return null;
1065
+ try {
1066
+ return asRecord(JSON.parse(value));
1067
+ }
1068
+ catch {
1069
+ // coercion-ok: malformed tool output is an unreadable absence; the caller logs it.
1070
+ return null;
1071
+ }
1072
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstAgentsPaneProps } from "./types.js";
2
+ export declare function ChatFirstAgentsPane({ activities, loading, error, onRefresh, onWatch, copy, }: ChatFirstAgentsPaneProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { ChatFirstAgentActivityPanel } from "../chat-first-agent-activity.js";
3
+ import { defaultChatFirstCopy } from "./copy.js";
4
+ export function ChatFirstAgentsPane({ activities, loading = false, error, onRefresh, onWatch, copy = defaultChatFirstCopy, }) {
5
+ return (_jsx("section", { "data-chat-first-agents-pane": true, className: "flex h-full min-h-0 flex-col overflow-y-auto bg-background", "aria-label": copy("agentsTitle"), children: _jsx(ChatFirstAgentActivityPanel, { activities: activities, loading: loading, error: error ?? null, onRefresh: onRefresh, onWatch: onWatch, copy: copy }) }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstAppPaneProps } from "./types.js";
2
+ export declare function ChatFirstAppPane({ app, status, embedUrl, errorMessage, onRetry, renderEmbed, copy, }: ChatFirstAppPaneProps): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Skeleton } from "@agent-native/toolkit/ui";
3
+ import { defaultChatFirstCopy } from "./copy.js";
4
+ export function ChatFirstAppPane({ app, status, embedUrl, errorMessage, onRetry, renderEmbed, copy = defaultChatFirstCopy, }) {
5
+ return (_jsx("section", { "data-chat-first-app-pane": true, className: "flex h-full min-h-0 w-full flex-col overflow-hidden bg-background", "aria-label": app ? `${app.name} app` : copy("appUnavailable"), children: status === "loading" ? (_jsxs("div", { className: "space-y-3 p-4", children: [_jsx(Skeleton, { className: "h-5 w-40" }), _jsx(Skeleton, { className: "h-4 w-full" }), _jsx(Skeleton, { className: "h-4 w-2/3" })] })) : status === "ready" && app && embedUrl ? (_jsx("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: renderEmbed({ url: embedUrl, title: app.name }) })) : status === "error" ? (_jsxs("div", { className: "flex h-full flex-col items-center justify-center gap-3 p-6 text-center", children: [_jsx("p", { className: "text-sm text-muted-foreground", children: errorMessage || copy("appUnavailable") }), onRetry ? (_jsx("button", { type: "button", className: "rounded-md border border-border px-3 py-1.5 text-xs text-foreground hover:bg-accent", onClick: onRetry, children: copy("retry") })) : null] })) : (_jsx("div", { className: "flex h-full items-center justify-center p-6 text-center text-sm text-muted-foreground", children: copy("appUnavailable") })) }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstAppRailProps } from "./types.js";
2
+ export declare function ChatFirstAppsRail({ apps, activeAppId, loading, error, collapsed, layout: controlledLayout, onLayoutChange, onLayoutError, onRetry, onOpenApp, onCreateApp, createAppTrigger, renderIcon, copy, }: ChatFirstAppRailProps): import("react").JSX.Element;
@@ -0,0 +1,103 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ContextMenu, ContextMenuContent, ContextMenuItem, ContextMenuSeparator, ContextMenuTrigger, Skeleton, Tooltip, TooltipContent, TooltipTrigger, } from "@agent-native/toolkit/ui";
3
+ import { IconChevronDown, IconChevronUp, IconPin, IconPlus, } from "@tabler/icons-react";
4
+ import { useMemo, useState } from "react";
5
+ import { orderChatFirstAppIds, readChatFirstAppLayout, writeChatFirstAppLayout, } from "../chat-first.js";
6
+ import { cn } from "../utils.js";
7
+ import { defaultChatFirstCopy } from "./copy.js";
8
+ function AppRows({ apps, activeAppId, layout, onDragStart, onDrop, onDragEnd, onOpenApp, onTogglePinned, onMove, renderIcon, copy, }) {
9
+ const orderedIds = orderChatFirstAppIds(apps.map((app) => app.id), layout);
10
+ const appsById = new Map(apps.map((app) => [app.id, app]));
11
+ const orderedApps = orderedIds
12
+ .map((id) => appsById.get(id))
13
+ .filter((app) => Boolean(app));
14
+ return (_jsx("ul", { className: "space-y-px", children: orderedApps.map((app) => {
15
+ const active = activeAppId === app.id;
16
+ const pinned = layout.pinnedIds.includes(app.id);
17
+ const index = orderedApps.indexOf(app);
18
+ return (_jsxs(ContextMenu, { children: [_jsx(ContextMenuTrigger, { asChild: true, children: _jsxs("li", { draggable: true, "data-chat-first-app": true, "data-app-id": app.id, className: cn("group flex h-6 w-full min-w-0 items-center gap-1 rounded-md px-1 text-sm transition-colors", active
19
+ ? "bg-sidebar-accent font-medium text-sidebar-accent-foreground"
20
+ : "text-sidebar-foreground/75 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), onDragStart: (event) => {
21
+ event.dataTransfer.effectAllowed = "move";
22
+ onDragStart(app.id);
23
+ }, onDragOver: (event) => event.preventDefault(), onDrop: () => onDrop(app.id), onDragEnd: onDragEnd, children: [_jsxs("button", { type: "button", className: "flex min-w-0 flex-1 items-center gap-2 px-1 text-start", onClick: () => onOpenApp(app), onKeyDown: (event) => {
24
+ if (!event.altKey)
25
+ return;
26
+ if (event.key === "ArrowUp") {
27
+ event.preventDefault();
28
+ onMove(app.id, -1);
29
+ }
30
+ else if (event.key === "ArrowDown") {
31
+ event.preventDefault();
32
+ onMove(app.id, 1);
33
+ }
34
+ }, "aria-keyshortcuts": "Alt+ArrowUp Alt+ArrowDown", "aria-label": copy("openApp", { name: app.name }), title: app.name, children: [renderIcon(app), _jsx("span", { className: "truncate", children: app.name })] }), _jsx("button", { type: "button", className: cn("flex size-6 shrink-0 items-center justify-center rounded text-sidebar-foreground/45 opacity-0 transition-opacity hover:bg-sidebar-accent hover:text-sidebar-foreground group-hover:opacity-100 focus-visible:opacity-100", pinned && "text-sidebar-foreground/70 opacity-100"), "aria-label": copy(pinned ? "unpinApp" : "pinApp", {
35
+ name: app.name,
36
+ }), "aria-pressed": pinned, title: pinned ? copy("removePinned") : copy("pinTop"), onClick: () => onTogglePinned(app.id), children: _jsx(IconPin, { size: 13, strokeWidth: pinned ? 2.2 : 1.6, "aria-hidden": "true" }) }), _jsx("span", { className: "sr-only", children: `${index + 1} of ${orderedApps.length}` })] }) }), _jsxs(ContextMenuContent, { children: [_jsxs(ContextMenuItem, { onSelect: () => onTogglePinned(app.id), children: [_jsx(IconPin, { size: 14, "aria-hidden": "true" }), pinned ? copy("removePinned") : copy("pinTop")] }), _jsx(ContextMenuSeparator, {}), _jsxs(ContextMenuItem, { disabled: index === 0, onSelect: () => onMove(app.id, -1), children: [_jsx(IconChevronUp, { size: 14, "aria-hidden": "true" }), copy("moveUp")] }), _jsxs(ContextMenuItem, { disabled: index === orderedApps.length - 1, onSelect: () => onMove(app.id, 1), children: [_jsx(IconChevronDown, { size: 14, "aria-hidden": "true" }), copy("moveDown")] })] })] }, app.id));
37
+ }) }));
38
+ }
39
+ export function ChatFirstAppsRail({ apps, activeAppId, loading = false, error, collapsed = false, layout: controlledLayout, onLayoutChange, onLayoutError, onRetry, onOpenApp, onCreateApp, createAppTrigger, renderIcon, copy = defaultChatFirstCopy, }) {
40
+ const [localLayout, setLocalLayout] = useState(() => readChatFirstAppLayout());
41
+ const layout = controlledLayout ?? localLayout;
42
+ const [draggedAppId, setDraggedAppId] = useState(null);
43
+ const [showAllApps, setShowAllApps] = useState(false);
44
+ const orderedApps = useMemo(() => {
45
+ const orderedIds = orderChatFirstAppIds(apps.map((app) => app.id), layout);
46
+ const appsById = new Map(apps.map((app) => [app.id, app]));
47
+ return orderedIds
48
+ .map((id) => appsById.get(id))
49
+ .filter((app) => Boolean(app));
50
+ }, [apps, layout]);
51
+ const visibleApps = showAllApps ? orderedApps : orderedApps.slice(0, 5);
52
+ const hasMoreApps = orderedApps.length > visibleApps.length;
53
+ const createTrigger = createAppTrigger ??
54
+ (onCreateApp ? (_jsx("button", { type: "button", className: "flex size-6 items-center justify-center rounded text-sidebar-foreground/55 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: onCreateApp, "aria-label": copy("createWorkspaceApp"), title: copy("createWorkspaceApp"), children: _jsx(IconPlus, { size: 14, "aria-hidden": "true" }) })) : null);
55
+ function persistLayout(next) {
56
+ setLocalLayout(next);
57
+ onLayoutChange?.(next);
58
+ const result = writeChatFirstAppLayout(next);
59
+ if (!result.ok)
60
+ onLayoutError?.(result.reason);
61
+ }
62
+ function togglePinned(appId) {
63
+ const pinnedIds = layout.pinnedIds.includes(appId)
64
+ ? layout.pinnedIds.filter((id) => id !== appId)
65
+ : [appId, ...layout.pinnedIds];
66
+ persistLayout({ ...layout, pinnedIds });
67
+ }
68
+ function reorderApps(targetId) {
69
+ if (!draggedAppId || draggedAppId === targetId)
70
+ return;
71
+ const currentOrder = orderChatFirstAppIds(apps.map((app) => app.id), layout);
72
+ const fromIndex = currentOrder.indexOf(draggedAppId);
73
+ const toIndex = currentOrder.indexOf(targetId);
74
+ if (fromIndex < 0 || toIndex < 0)
75
+ return;
76
+ const nextOrder = [...currentOrder];
77
+ nextOrder.splice(fromIndex, 1);
78
+ nextOrder.splice(toIndex, 0, draggedAppId);
79
+ persistLayout({ ...layout, orderedIds: nextOrder });
80
+ setDraggedAppId(null);
81
+ }
82
+ function moveApp(appId, direction) {
83
+ const currentOrder = orderChatFirstAppIds(apps.map((app) => app.id), layout);
84
+ const index = currentOrder.indexOf(appId);
85
+ const nextIndex = index + direction;
86
+ if (index < 0 || nextIndex < 0 || nextIndex >= currentOrder.length)
87
+ return;
88
+ const nextOrder = [...currentOrder];
89
+ [nextOrder[index], nextOrder[nextIndex]] = [
90
+ nextOrder[nextIndex],
91
+ nextOrder[index],
92
+ ];
93
+ persistLayout({ ...layout, orderedIds: nextOrder });
94
+ }
95
+ if (collapsed) {
96
+ return (_jsxs("section", { "data-chat-first-apps-rail": true, className: "flex flex-col items-center gap-1 px-1.5 pt-2", "aria-label": copy("workspaceApps"), children: [createTrigger, loading && apps.length === 0
97
+ ? [0, 1, 2].map((index) => (_jsx(Skeleton, { className: "size-9 rounded-md" }, index)))
98
+ : visibleApps.map((app) => (_jsx("button", { type: "button", "data-chat-first-app": true, "data-app-id": app.id, className: cn("flex size-9 items-center justify-center rounded-md transition-colors", activeAppId === app.id
99
+ ? "bg-sidebar-accent text-sidebar-accent-foreground"
100
+ : "text-sidebar-foreground/70 hover:bg-sidebar-accent hover:text-sidebar-accent-foreground"), onClick: () => onOpenApp(app), "aria-label": copy("openApp", { name: app.name }), title: app.name, children: renderIcon(app) }, app.id))), error ? (_jsx("span", { className: "size-1.5 rounded-full bg-destructive", title: error, "aria-label": error })) : null] }));
101
+ }
102
+ return (_jsxs("section", { "data-chat-first-apps-rail": true, className: "mt-3 px-2 pb-2 pt-2", "aria-label": copy("workspaceApps"), children: [_jsxs("div", { className: "mb-1 flex items-center gap-1.5 px-1 text-[11px] font-medium text-sidebar-foreground/50", children: [_jsx("span", { children: copy("workspaceApps") }), _jsx("span", { className: "ml-auto", children: createTrigger })] }), loading && apps.length === 0 ? (_jsx("div", { className: "space-y-0.5 px-1", children: [0, 1, 2].map((index) => (_jsx(Skeleton, { className: "h-7 w-full rounded-md" }, index))) })) : apps.length === 0 ? (_jsxs("div", { className: "px-1", children: [_jsx("p", { className: "text-xs text-sidebar-foreground/55", children: copy("noWorkspaceApps") }), createAppTrigger ? (createTrigger) : onCreateApp ? (_jsxs("button", { type: "button", className: "mt-1 inline-flex h-6 items-center gap-1.5 rounded-md border border-sidebar-border px-2 text-xs text-sidebar-foreground/75 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: onCreateApp, children: [_jsx(IconPlus, { size: 13, "aria-hidden": "true" }), copy("createApp")] })) : (createTrigger)] })) : (_jsx(AppRows, { apps: visibleApps, activeAppId: activeAppId, layout: layout, onDragStart: setDraggedAppId, onDrop: reorderApps, onDragEnd: () => setDraggedAppId(null), onOpenApp: onOpenApp, onTogglePinned: togglePinned, onMove: moveApp, renderIcon: renderIcon, copy: copy })), hasMoreApps || showAllApps ? (_jsxs("button", { type: "button", className: "mt-0.5 flex h-6 w-full items-center gap-2 rounded-md px-2 text-xs text-sidebar-foreground/50 hover:bg-sidebar-accent hover:text-sidebar-foreground", onClick: () => setShowAllApps((value) => !value), children: [showAllApps ? (_jsx(IconChevronUp, { size: 14, "aria-hidden": "true" })) : (_jsx(IconChevronDown, { size: 14, "aria-hidden": "true" })), showAllApps ? copy("showLess") : copy("showMore")] })) : null, error ? (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "mt-1 flex items-center gap-1 px-1 text-[10px] text-destructive/80", onClick: onRetry, "aria-label": error, children: [_jsx("span", { className: "size-1.5 rounded-full bg-destructive" }), onRetry ? copy("retry") : copy("appsLoadError")] }) }), _jsx(TooltipContent, { side: "right", children: error })] })) : null] }));
103
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstBrowserPaneProps } from "./types.js";
2
+ export declare function ChatFirstBrowserPane({ url, title, status, statusMessage, onClose, renderEmbed, copy, }: ChatFirstBrowserPaneProps): import("react").JSX.Element;
@@ -0,0 +1,64 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconArrowLeft, IconArrowRight, IconExternalLink, IconRefresh, IconWorld, IconX, } from "@tabler/icons-react";
3
+ import { useEffect, useState } from "react";
4
+ import { resolveChatFirstBrowserTarget } from "../chat-first.js";
5
+ import { defaultChatFirstCopy } from "./copy.js";
6
+ export function ChatFirstBrowserPane({ url, title, status, statusMessage, onClose, renderEmbed, copy = defaultChatFirstCopy, }) {
7
+ const [currentUrl, setCurrentUrl] = useState(url);
8
+ const [draftUrl, setDraftUrl] = useState(url);
9
+ const [reloadKey, setReloadKey] = useState(0);
10
+ const [history, setHistory] = useState([url]);
11
+ const [historyIndex, setHistoryIndex] = useState(0);
12
+ const [navigationError, setNavigationError] = useState(null);
13
+ useEffect(() => {
14
+ setCurrentUrl(url);
15
+ setDraftUrl(url);
16
+ setHistory([url]);
17
+ setHistoryIndex(0);
18
+ setNavigationError(null);
19
+ }, [url]);
20
+ function navigate(event) {
21
+ event.preventDefault();
22
+ const target = resolveChatFirstBrowserTarget({ url: draftUrl });
23
+ if (target.status !== "ready") {
24
+ setNavigationError(copy("browserInvalidUrl"));
25
+ return;
26
+ }
27
+ const nextUrl = target.target.url;
28
+ setNavigationError(null);
29
+ setCurrentUrl(nextUrl);
30
+ setDraftUrl(nextUrl);
31
+ setHistory((current) => [...current.slice(0, historyIndex + 1), nextUrl]);
32
+ setHistoryIndex((index) => index + 1);
33
+ setReloadKey((key) => key + 1);
34
+ }
35
+ function goBack() {
36
+ if (historyIndex <= 0)
37
+ return;
38
+ const nextIndex = historyIndex - 1;
39
+ const nextUrl = history[nextIndex];
40
+ setHistoryIndex(nextIndex);
41
+ setCurrentUrl(nextUrl);
42
+ setDraftUrl(nextUrl);
43
+ setNavigationError(null);
44
+ setReloadKey((key) => key + 1);
45
+ }
46
+ function goForward() {
47
+ if (historyIndex >= history.length - 1)
48
+ return;
49
+ const nextIndex = historyIndex + 1;
50
+ const nextUrl = history[nextIndex];
51
+ setHistoryIndex(nextIndex);
52
+ setCurrentUrl(nextUrl);
53
+ setDraftUrl(nextUrl);
54
+ setNavigationError(null);
55
+ setReloadKey((key) => key + 1);
56
+ }
57
+ return (_jsxs("section", { "data-chat-first-browser-pane": true, className: "flex h-full min-h-0 w-full flex-col overflow-hidden bg-background", "aria-label": copy("surface.browser.label"), children: [_jsxs("header", { className: "flex h-12 shrink-0 items-center gap-1.5 border-b border-border bg-card px-2", children: [_jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [_jsx("button", { type: "button", disabled: historyIndex <= 0, onClick: goBack, "aria-label": copy("browserBack"), title: copy("browserBack"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-35", children: _jsx(IconArrowLeft, { size: 15 }) }), _jsx("button", { type: "button", disabled: historyIndex >= history.length - 1, onClick: goForward, "aria-label": copy("browserForward"), title: copy("browserForward"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground disabled:opacity-35", children: _jsx(IconArrowRight, { size: 15 }) }), _jsx("button", { type: "button", onClick: () => setReloadKey((key) => key + 1), "aria-label": copy("browserReload"), title: copy("browserReload"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconRefresh, { size: 15 }) })] }), _jsxs("form", { className: "flex min-w-0 flex-1 items-center gap-1.5 rounded-md border border-input bg-background px-2", onSubmit: navigate, children: [_jsx(IconWorld, { size: 13, className: "shrink-0 text-muted-foreground", "aria-hidden": "true" }), _jsx("input", { value: draftUrl, onChange: (event) => setDraftUrl(event.target.value), "aria-label": copy("browserAddress"), spellCheck: false, className: "h-7 min-w-0 flex-1 bg-transparent text-xs text-foreground outline-none placeholder:text-muted-foreground" })] }), _jsxs("div", { className: "flex shrink-0 items-center gap-0.5", children: [title ? (_jsx("span", { className: "hidden max-w-28 truncate px-1 text-xs text-muted-foreground xl:block", title: title, children: title })) : null, _jsx("button", { type: "button", onClick: () => window.open(currentUrl, "_blank", "noopener,noreferrer"), "aria-label": copy("browserOpenExternal"), title: copy("browserOpenExternal"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconExternalLink, { size: 15 }) }), _jsx("button", { type: "button", onClick: onClose, "aria-label": copy("browserClose"), title: copy("browserClose"), className: "flex size-7 items-center justify-center rounded-md text-muted-foreground hover:bg-accent hover:text-foreground", children: _jsx(IconX, { size: 15 }) })] })] }), navigationError ? (_jsx("p", { className: "border-b border-destructive/30 bg-destructive/10 px-3 py-1.5 text-xs text-destructive", role: "alert", children: navigationError })) : null, _jsx("div", { className: "relative min-h-0 flex-1 overflow-hidden", children: status === "starting" || status === "error" ? (_jsx("div", { className: "flex h-full items-center justify-center px-6 text-center", role: status === "error" ? "alert" : "status", "aria-live": "polite", children: _jsxs("div", { className: "max-w-xs space-y-1", children: [_jsx("p", { className: "text-sm font-medium text-foreground", children: status === "starting"
58
+ ? copy("browserPreviewStarting")
59
+ : copy("browserPreviewError") }), statusMessage ? (_jsx("p", { className: "text-xs text-muted-foreground", children: statusMessage })) : null] }) })) : (renderEmbed({
60
+ url: currentUrl,
61
+ title: title || copy("browserPage"),
62
+ key: `${currentUrl}:${reloadKey}`,
63
+ })) })] }));
64
+ }
@@ -0,0 +1,12 @@
1
+ import type { ReactNode } from "react";
2
+ import { type ChatHistoryItem, type ChatHistoryListProps } from "../chat/ChatHistoryList.js";
3
+ export interface ChatFirstChatHistoryProps extends Omit<ChatHistoryListProps, "items" | "sections" | "variant"> {
4
+ items: ChatHistoryItem[];
5
+ label?: ReactNode;
6
+ }
7
+ /**
8
+ * The single chat-list presentation used by the chat-first rail on every
9
+ * host. Hosts still own thread fetching and actions, but row rhythm and the
10
+ * Chats section treatment stay identical.
11
+ */
12
+ export declare function ChatFirstChatHistory({ items, label, className, ...props }: ChatFirstChatHistoryProps): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { ChatHistoryList, } from "../chat/ChatHistoryList.js";
3
+ /**
4
+ * The single chat-list presentation used by the chat-first rail on every
5
+ * host. Hosts still own thread fetching and actions, but row rhythm and the
6
+ * Chats section treatment stay identical.
7
+ */
8
+ export function ChatFirstChatHistory({ items, label = "Chats", className, ...props }) {
9
+ return (_jsxs("section", { "data-chat-first-chat-history": true, className: ["min-h-0 min-w-0", className].filter(Boolean).join(" "), children: [_jsx("p", { className: "mb-1 px-2 text-[11px] font-medium text-sidebar-foreground/50", children: label }), _jsx(ChatHistoryList, { ...props, items: items, variant: "rail", className: "min-w-0" })] }));
10
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstCopy } from "./types.js";
2
+ export declare const defaultChatFirstCopy: ChatFirstCopy;
@@ -0,0 +1,117 @@
1
+ const DEFAULT_COPY = {
2
+ newChat: "New chat",
3
+ search: "Search",
4
+ workspaceApps: "Apps",
5
+ integrations: "Integrations",
6
+ scheduled: "Scheduled",
7
+ createWorkspaceApp: "Create app",
8
+ openApp: "Open {name}",
9
+ appsLoadError: "Apps could not be loaded",
10
+ noWorkspaceApps: "No apps yet",
11
+ createApp: "Create app",
12
+ retry: "Retry",
13
+ dismiss: "Dismiss",
14
+ unpinApp: "Unpin {name}",
15
+ pinApp: "Pin {name}",
16
+ removePinned: "Remove from pinned apps",
17
+ pinTop: "Pin app to the top",
18
+ moveUp: "Move up",
19
+ moveDown: "Move down",
20
+ showMore: "Show more",
21
+ showLess: "Show less",
22
+ appOrderUnavailable: "App order could not be saved on this device.",
23
+ openSideSurfaces: "Open side surfaces",
24
+ sideSurfaces: "Side surfaces",
25
+ resizeSideSurface: "Resize side surface",
26
+ closeTab: "Close {name}",
27
+ close: "Close",
28
+ closeOthers: "Close others",
29
+ closeToRight: "Close to the right",
30
+ closeAll: "Close all",
31
+ deferred: "Deferred",
32
+ openActivity: "Open activity",
33
+ unavailable: "This surface is not available here.",
34
+ browserBack: "Back",
35
+ browserForward: "Forward",
36
+ browserReload: "Reload page",
37
+ browserAddress: "Browser address",
38
+ browserOpenExternal: "Open in external browser",
39
+ browserClose: "Close browser",
40
+ browserPage: "Browser page",
41
+ browserInvalidUrl: "Enter a full http(s) URL to navigate.",
42
+ browserPreviewStarting: "Starting preview…",
43
+ browserPreviewError: "Preview unavailable",
44
+ appUnavailable: "This workspace app is no longer available.",
45
+ appLoading: "Loading app",
46
+ agentActivityEyebrow: "Workspace",
47
+ agentActivityTitle: "Agent activity",
48
+ agentActivityDescription: "Follow runs and open a second session beside this chat.",
49
+ refreshAgentActivity: "Refresh agent activity",
50
+ noAgentSessions: "No agent sessions yet",
51
+ startAgentSession: "Start an agent run and it will appear here.",
52
+ watchSession: "Watch",
53
+ copySessionId: "Copy session ID",
54
+ copySessionIdFor: "Copy session ID for {name}",
55
+ sessionIdCopied: "Session ID copied",
56
+ sessionIdShort: "ID",
57
+ copied: "Copied",
58
+ agentActivityStatusQueued: "Queued",
59
+ agentActivityStatusRunning: "Running",
60
+ agentActivityStatusPaused: "Paused",
61
+ agentActivityStatusNeedsApproval: "Needs approval",
62
+ agentActivityStatusCompleted: "Completed",
63
+ agentActivityStatusErrored: "Needs attention",
64
+ agentActivityStatusRecent: "Recent",
65
+ agentActivityStatusUnknown: "Unknown",
66
+ watchingSession: "Watching {name}",
67
+ session: "session",
68
+ stopWatchingSession: "Stop watching session",
69
+ stopWatching: "Stop watching",
70
+ watchedSession: "Watched session",
71
+ agentsTitle: "Subagents",
72
+ };
73
+ const SURFACE_COPY = {
74
+ app: {
75
+ label: "App",
76
+ reason: "Open a workspace app beside the conversation.",
77
+ },
78
+ browser: {
79
+ label: "Browser",
80
+ reason: "Ask the agent to open a web URL.",
81
+ },
82
+ terminal: {
83
+ label: "Terminal",
84
+ reason: "Deferred: an embedded PTY lifecycle is not connected in this release.",
85
+ },
86
+ files: {
87
+ label: "Files",
88
+ reason: "Deferred: a bounded workspace tree is not connected in this release.",
89
+ },
90
+ diff: {
91
+ label: "Diff",
92
+ reason: "Deferred: changed-file data is not connected in this release.",
93
+ },
94
+ "side-chat": {
95
+ label: "Side chat",
96
+ reason: "Choose Watch and message from any chat row.",
97
+ },
98
+ agents: {
99
+ label: "Agents",
100
+ reason: "Review recent runs or watch one beside this conversation.",
101
+ },
102
+ };
103
+ function interpolate(value, values) {
104
+ if (!values)
105
+ return value;
106
+ return value.replace(/\{(\w+)\}/g, (_, key) => values[key] ?? "");
107
+ }
108
+ export const defaultChatFirstCopy = (key, values) => {
109
+ if (key.startsWith("surface.")) {
110
+ const [, kind, field] = key.split(".");
111
+ const surface = SURFACE_COPY[kind];
112
+ if (surface && (field === "label" || field === "reason")) {
113
+ return surface[field];
114
+ }
115
+ }
116
+ return interpolate(DEFAULT_COPY[key] ?? key, values);
117
+ };
@@ -0,0 +1,13 @@
1
+ export { ChatFirstAgentsPane } from "./agents-pane.js";
2
+ export { ChatFirstAppPane } from "./app-pane.js";
3
+ export { ChatFirstAppsRail } from "./apps-rail.js";
4
+ export { ChatFirstBrowserPane } from "./browser-pane.js";
5
+ export { defaultChatFirstCopy } from "./copy.js";
6
+ export { ChatFirstChatHistory, type ChatFirstChatHistoryProps, } from "./chat-history.js";
7
+ export { ChatFirstSessionWatchPane } from "./session-watch-pane.js";
8
+ export { ChatFirstSurfacePanel, type ChatFirstSurfacePanelProps, } from "./surface-panel.js";
9
+ export { ChatFirstPrimaryNavigation } from "./primary-nav.js";
10
+ export { emitChatFirstOpenApp, resolveChatFirstAppTarget, CHAT_FIRST_DEFAULT_APP_IDS, type ChatFirstOpenAppDetail, } from "../chat-first.js";
11
+ export { buildChatFirstAppCreationPrompt, titleFromChatFirstAppPrompt, type ChatFirstAppCreationPromptInput, type ChatFirstAppCreationResource, type ChatFirstAppCreationVaultAccessMode, } from "../../shared/chat-first-app-creation.js";
12
+ export { ChatFirstSurfaceContent, ChatFirstSurfaceTabs, } from "./surface-tabs.js";
13
+ export type { ChatFirstAgentActivity, ChatFirstAgentsPaneProps, ChatFirstAppItem, ChatFirstAppPaneProps, ChatFirstAppRailProps, ChatFirstBrowserPaneProps, ChatFirstCopy, ChatFirstEmbedTarget, ChatFirstSessionWatchPaneProps, ChatFirstSurfaceTabsProps, } from "./types.js";
@@ -0,0 +1,12 @@
1
+ export { ChatFirstAgentsPane } from "./agents-pane.js";
2
+ export { ChatFirstAppPane } from "./app-pane.js";
3
+ export { ChatFirstAppsRail } from "./apps-rail.js";
4
+ export { ChatFirstBrowserPane } from "./browser-pane.js";
5
+ export { defaultChatFirstCopy } from "./copy.js";
6
+ export { ChatFirstChatHistory, } from "./chat-history.js";
7
+ export { ChatFirstSessionWatchPane } from "./session-watch-pane.js";
8
+ export { ChatFirstSurfacePanel, } from "./surface-panel.js";
9
+ export { ChatFirstPrimaryNavigation } from "./primary-nav.js";
10
+ export { emitChatFirstOpenApp, resolveChatFirstAppTarget, CHAT_FIRST_DEFAULT_APP_IDS, } from "../chat-first.js";
11
+ export { buildChatFirstAppCreationPrompt, titleFromChatFirstAppPrompt, } from "../../shared/chat-first-app-creation.js";
12
+ export { ChatFirstSurfaceContent, ChatFirstSurfaceTabs, } from "./surface-tabs.js";
@@ -0,0 +1,8 @@
1
+ import type { ChatFirstCopy } from "./types.js";
2
+ export declare function ChatFirstPrimaryNavigation({ onNewChat, onOpenIntegrations, onOpenScheduled, onSearch, copy, }: {
3
+ onNewChat?: () => void;
4
+ onOpenIntegrations: () => void;
5
+ onOpenScheduled: () => void;
6
+ onSearch?: () => void;
7
+ copy?: ChatFirstCopy;
8
+ }): import("react").JSX.Element;
@@ -0,0 +1,6 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconClock, IconPlus, IconPlugConnected, IconSearch, } from "@tabler/icons-react";
3
+ import { defaultChatFirstCopy } from "./copy.js";
4
+ export function ChatFirstPrimaryNavigation({ onNewChat, onOpenIntegrations, onOpenScheduled, onSearch, copy = defaultChatFirstCopy, }) {
5
+ return (_jsxs(_Fragment, { children: [onNewChat ? (_jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onNewChat, children: [_jsx(IconPlus, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("newChat") })] })) : null, _jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onOpenIntegrations, children: [_jsx(IconPlugConnected, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("integrations") })] }), _jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onOpenScheduled, children: [_jsx(IconClock, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("scheduled") })] }), onSearch ? (_jsxs("button", { type: "button", className: "flex h-8 w-full items-center gap-2 rounded-md px-2 text-[13px] font-medium text-sidebar-foreground/80 transition-colors hover:bg-sidebar-accent hover:text-sidebar-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", onClick: onSearch, children: [_jsx(IconSearch, { size: 15, className: "shrink-0", "aria-hidden": "true" }), _jsx("span", { children: copy("search") })] })) : null] }));
6
+ }
@@ -0,0 +1,2 @@
1
+ import type { ChatFirstSessionWatchPaneProps } from "./types.js";
2
+ export declare function ChatFirstSessionWatchPane({ target, onClose, renderChat, copy, }: ChatFirstSessionWatchPaneProps): import("react").JSX.Element | null;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { IconEye, IconX } from "@tabler/icons-react";
3
+ import { defaultChatFirstCopy } from "./copy.js";
4
+ export function ChatFirstSessionWatchPane({ target, onClose, renderChat, copy = defaultChatFirstCopy, }) {
5
+ if (!target)
6
+ return null;
7
+ const sessionName = target.title || copy("session");
8
+ return (_jsxs("section", { "data-chat-first-watch-pane": true, className: "flex h-full min-h-0 w-full flex-col overflow-hidden bg-background", "aria-label": copy("watchedSession"), children: [_jsxs("header", { className: "flex h-12 shrink-0 items-center gap-2 border-b border-border bg-card px-3", children: [_jsx(IconEye, { size: 16, className: "shrink-0 text-primary", "aria-hidden": "true" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "truncate text-xs font-semibold text-foreground", children: copy("watchingSession", { name: sessionName }) }), _jsx("p", { className: "truncate font-mono text-[10px] text-muted-foreground", children: target.sessionId })] }), _jsx("button", { type: "button", className: "flex size-7 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent hover:text-foreground", "aria-label": copy("stopWatchingSession"), title: copy("stopWatching"), onClick: onClose, children: _jsx(IconX, { size: 16, "aria-hidden": "true" }) })] }), _jsx("div", { className: "min-h-0 flex-1", children: renderChat(target) })] }));
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { PointerEvent, ReactNode } from "react";
2
+ import type { ChatFirstCopy } from "./types.js";
3
+ export interface ChatFirstSurfacePanelProps {
4
+ width: number;
5
+ onResizePointerDown: (event: PointerEvent<HTMLDivElement>) => void;
6
+ children: ReactNode;
7
+ copy?: ChatFirstCopy;
8
+ }
9
+ export declare function ChatFirstSurfacePanel({ width, onResizePointerDown, children, copy, }: ChatFirstSurfacePanelProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { clampChatFirstSurfaceWidth } from "../chat-first.js";
3
+ import { defaultChatFirstCopy } from "./copy.js";
4
+ export function ChatFirstSurfacePanel({ width, onResizePointerDown, children, copy = defaultChatFirstCopy, }) {
5
+ const panelWidth = clampChatFirstSurfaceWidth(width);
6
+ return (_jsxs("aside", { "data-chat-first-surface-panel": true, "aria-label": copy("sideSurfaces"), className: "chat-first-surface-panel relative flex h-full w-[var(--chat-first-surface-width)] min-w-0 shrink-0 flex-col overflow-hidden border-s border-border bg-background max-[767px]:absolute max-[767px]:inset-0 max-[767px]:z-10 max-[767px]:w-full max-[767px]:min-w-0", style: {
7
+ "--chat-first-surface-width": `${panelWidth}px`,
8
+ }, children: [_jsx("div", { className: "chat-first-surface-resize-handle absolute inset-y-0 -start-1 z-[3] w-2 cursor-col-resize hover:bg-ring/35 max-[767px]:hidden", role: "separator", "aria-label": copy("resizeSideSurface"), "aria-orientation": "vertical", onPointerDown: onResizePointerDown }), children] }));
9
+ }
@@ -0,0 +1,9 @@
1
+ import type { ReactNode } from "react";
2
+ import { type ChatFirstSurfaceTab } from "../chat-first.js";
3
+ import type { ChatFirstSurfaceTabsProps } from "./types.js";
4
+ export declare function ChatFirstSurfaceTabs({ tabs, activeTabId, onActivate, onClose, onCloseOthers, onCloseToRight, onCloseAll, onOpenSurface, copy, }: ChatFirstSurfaceTabsProps): import("react").JSX.Element;
5
+ export declare function ChatFirstSurfaceContent({ tabs, activeTabId, renderTab, }: {
6
+ tabs: readonly ChatFirstSurfaceTab[];
7
+ activeTabId: string | null;
8
+ renderTab: (tab: ChatFirstSurfaceTab) => ReactNode;
9
+ }): import("react").JSX.Element;