@agent-native/core 0.154.5 → 0.157.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 (263) hide show
  1. package/corpus/README.md +1 -1
  2. package/corpus/templates/analytics/.agents/skills/account-health/SKILL.md +76 -0
  3. package/corpus/templates/analytics/.agents/skills/bigquery/SKILL.md +3 -0
  4. package/corpus/templates/analytics/.agents/skills/cross-source-analysis/SKILL.md +2 -1
  5. package/corpus/templates/analytics/.agents/skills/data-querying/SKILL.md +6 -5
  6. package/corpus/templates/analytics/AGENTS.md +3 -0
  7. package/corpus/templates/analytics/actions/account-deep-dive.ts +3 -2
  8. package/corpus/templates/analytics/actions/bigquery.ts +1 -1
  9. package/corpus/templates/analytics/app/components/dashboard/SqlChart.tsx +4 -1
  10. package/corpus/templates/analytics/app/components/layout/NewDashboardDialog.tsx +1 -0
  11. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyCombobox.tsx +12 -4
  12. package/corpus/templates/analytics/app/pages/adhoc/explorer/components/PropertyValueCombobox.tsx +5 -2
  13. package/corpus/templates/analytics/app/pages/adhoc/explorer/property-label.ts +32 -0
  14. package/corpus/templates/analytics/changelog/2026-08-13-account-health-readouts-verify-customer-scope-and-contract-metrics.md +7 -0
  15. package/corpus/templates/analytics/server/jobs/analytics-bigquery-backfill.ts +43 -17
  16. package/corpus/templates/analytics/server/lib/analytics-query-catalog.ts +17 -0
  17. package/corpus/templates/analytics/server/plugins/agent-chat.ts +4 -0
  18. package/corpus/templates/assets/app/components/asset/AssetPreviewDialog.tsx +3 -1
  19. package/corpus/templates/assets/app/i18n-data.ts +21 -1
  20. package/corpus/templates/assets/app/routes/brand-kits.$id.tsx +17 -13
  21. package/corpus/templates/calendar/AGENTS.md +2 -0
  22. package/corpus/templates/calendar/DEVELOPING.md +4 -4
  23. package/corpus/templates/calendar/actions/get-settings.ts +4 -11
  24. package/corpus/templates/calendar/actions/update-availability.ts +15 -4
  25. package/corpus/templates/calendar/actions/update-settings.ts +15 -4
  26. package/corpus/templates/calendar/app/components/booking/DatePicker.tsx +9 -3
  27. package/corpus/templates/calendar/app/components/calendar/CreateEventDialog.tsx +21 -19
  28. package/corpus/templates/calendar/app/components/calendar/EventDetailPopover.tsx +9 -6
  29. package/corpus/templates/calendar/app/components/calendar/FindTimePanel.tsx +25 -3
  30. package/corpus/templates/calendar/app/components/calendar/InlineEventPickers.tsx +10 -3
  31. package/corpus/templates/calendar/app/components/calendar/MonthView.tsx +9 -9
  32. package/corpus/templates/calendar/app/components/calendar/WeekView.tsx +11 -3
  33. package/corpus/templates/calendar/app/components/layout/Sidebar.tsx +10 -4
  34. package/corpus/templates/calendar/app/i18n-data.ts +30 -0
  35. package/corpus/templates/calendar/app/lib/availability-schedule.ts +53 -0
  36. package/corpus/templates/calendar/app/lib/event-form-utils.ts +5 -0
  37. package/corpus/templates/calendar/app/pages/AvailabilitySettings.tsx +90 -28
  38. package/corpus/templates/calendar/app/pages/BookingLinksPage.tsx +135 -61
  39. package/corpus/templates/calendar/app/pages/BookingPage.tsx +2 -0
  40. package/corpus/templates/calendar/app/pages/CalendarView.tsx +30 -15
  41. package/corpus/templates/calendar/app/pages/Settings.tsx +60 -1
  42. package/corpus/templates/calendar/changelog/2026-08-13-find-a-time-now-closes-from-a-clear-header-action.md +6 -0
  43. package/corpus/templates/calendar/server/handlers/bookings.ts +2 -1
  44. package/corpus/templates/calendar/server/handlers/settings.ts +12 -16
  45. package/corpus/templates/calendar/shared/api.ts +1 -0
  46. package/corpus/templates/calendar/shared/availability-schedule.ts +64 -0
  47. package/corpus/templates/calendar/shared/calendar-week.ts +21 -0
  48. package/corpus/templates/calendar/shared/settings.ts +44 -0
  49. package/corpus/templates/clips/AGENTS.md +2 -0
  50. package/corpus/templates/clips/actions/add-comment.ts +5 -2
  51. package/corpus/templates/clips/actions/finalize-recording.ts +31 -1
  52. package/corpus/templates/clips/actions/get-recording-player-data.ts +9 -0
  53. package/corpus/templates/clips/actions/lib/ensure-seekable-video.ts +21 -1
  54. package/corpus/templates/clips/actions/reply-to-comment.ts +5 -2
  55. package/corpus/templates/clips/actions/update-comment.ts +9 -2
  56. package/corpus/templates/clips/app/components/library/search-bar.tsx +26 -13
  57. package/corpus/templates/clips/app/components/meetings/share-meeting-dialog.tsx +135 -3
  58. package/corpus/templates/clips/app/components/player/comments-panel.tsx +5 -99
  59. package/corpus/templates/clips/app/components/player/playback-comment-overlay.tsx +7 -3
  60. package/corpus/templates/clips/app/components/player/share-dialog.tsx +102 -59
  61. package/corpus/templates/clips/app/components/player/video-player.tsx +84 -24
  62. package/corpus/templates/clips/app/components/workspace/notifications-list.tsx +11 -3
  63. package/corpus/templates/clips/app/i18n/en-US.ts +12 -0
  64. package/corpus/templates/clips/app/lib/public-meeting.ts +11 -3
  65. package/corpus/templates/clips/app/lib/search-focus.ts +15 -0
  66. package/corpus/templates/clips/app/root.tsx +2 -1
  67. package/corpus/templates/clips/app/routes/_app.meetings._index.tsx +94 -26
  68. package/corpus/templates/clips/app/routes/_app.settings._index.tsx +24 -7
  69. package/corpus/templates/clips/app/routes/embed.$shareId.tsx +8 -4
  70. package/corpus/templates/clips/app/routes/r.$recordingId.tsx +29 -8
  71. package/corpus/templates/clips/app/routes/share.$shareId.tsx +24 -6
  72. package/corpus/templates/clips/app/routes/share.meeting.$meetingId.tsx +72 -26
  73. package/corpus/templates/clips/changelog/2026-08-13-inline-markdown-comments.md +6 -0
  74. package/corpus/templates/clips/changelog/2026-08-13-private-meeting-agent-links.md +6 -0
  75. package/corpus/templates/clips/desktop/src/app.tsx +116 -19
  76. package/corpus/templates/clips/desktop/src/lib/recorder.ts +13 -29
  77. package/corpus/templates/clips/desktop/src/lib/recording-request.ts +39 -0
  78. package/corpus/templates/clips/desktop/src/lib/settings-navigation.ts +11 -0
  79. package/corpus/templates/clips/desktop/src/lib/whisper-model-picker.ts +7 -0
  80. package/corpus/templates/clips/desktop/src/styles.css +117 -0
  81. package/corpus/templates/clips/server/db/index.ts +10 -0
  82. package/corpus/templates/clips/server/db/schema.ts +1 -0
  83. package/corpus/templates/clips/server/lib/recordings.ts +3 -1
  84. package/corpus/templates/clips/server/lib/seekable-media-state.ts +90 -0
  85. package/corpus/templates/clips/server/plugins/db.ts +5 -0
  86. package/corpus/templates/clips/server/routes/api/public-meeting.get.ts +37 -4
  87. package/corpus/templates/clips/server/routes/api/public-recording.get.ts +16 -5
  88. package/corpus/templates/clips/shared/clips-ai-prefs.ts +3 -0
  89. package/corpus/templates/clips/shared/meeting-agent-access.ts +5 -0
  90. package/corpus/templates/content/actions/add-comment.ts +2 -1
  91. package/corpus/templates/content/actions/update-comment.ts +1 -1
  92. package/corpus/templates/content/app/components/editor/CommentsSidebar.tsx +24 -15
  93. package/corpus/templates/design/actions/generate-design.ts +10 -7
  94. package/corpus/templates/design/actions/present-design-variants.ts +35 -6
  95. package/corpus/templates/design/actions/run-design-audit.ts +33 -0
  96. package/corpus/templates/design/changelog/2026-08-13-the-design-audit-now-catches-a-screen-that-renders-behind-an.md +6 -0
  97. package/corpus/templates/design/shared/design-review.ts +1 -0
  98. package/corpus/templates/design/shared/html-integrity.ts +66 -0
  99. package/corpus/templates/dispatch/.env.example +5 -0
  100. package/corpus/templates/dispatch/AGENTS.md +24 -19
  101. package/corpus/templates/dispatch/app/i18n-data.ts +20 -0
  102. package/corpus/templates/dispatch/server/lib/identity-sso.ts +21 -90
  103. package/corpus/templates/dispatch/server/plugins/identity-sso.ts +3 -12
  104. package/corpus/templates/dispatch/shared/feature-flags.ts +4 -0
  105. package/corpus/templates/factory/AGENTS.md +5 -1
  106. package/corpus/templates/factory/README.md +23 -0
  107. package/corpus/templates/factory/actions/view-screen.ts +17 -0
  108. package/corpus/templates/factory/app/components/factory/FactoryAgentsView.tsx +239 -0
  109. package/corpus/templates/factory/app/components/factory/FactoryCanvas.tsx +2 -0
  110. package/corpus/templates/factory/app/components/factory/FactoryInspector.tsx +130 -7
  111. package/corpus/templates/factory/app/i18n/en-US.ts +20 -0
  112. package/corpus/templates/factory/app/routes/factory.tsx +41 -0
  113. package/corpus/templates/factory/package.json +1 -0
  114. package/corpus/templates/factory/server/factory-graph/contracts.ts +2 -0
  115. package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -0
  116. package/corpus/templates/factory/server/plugins/dispatch-db.ts +1 -0
  117. package/corpus/templates/factory/server/plugins/setup-dispatch.ts +3 -0
  118. package/corpus/templates/mail/app/lib/native-mcp-exclusions.ts +3 -0
  119. package/corpus/templates/mail/vite.config.ts +7 -0
  120. package/corpus/templates/plan/actions/reply-to-plan-comment.ts +7 -2
  121. package/corpus/templates/plan/actions/resolve-plan-comment.ts +2 -2
  122. package/corpus/templates/plan/actions/update-visual-plan.ts +1 -1
  123. package/corpus/templates/plan/app/pages/PlansPage.tsx +29 -20
  124. package/corpus/templates/slides/actions/add-slide-comment.ts +1 -1
  125. package/corpus/templates/slides/actions/update-slide-comment.ts +1 -1
  126. package/corpus/templates/slides/app/components/comments/SlideCommentsPanel.tsx +9 -6
  127. package/corpus/templates/slides/app/components/editor/AddSlidePopover.tsx +98 -29
  128. package/corpus/templates/slides/app/components/editor/EditorActionCluster.tsx +45 -91
  129. package/corpus/templates/slides/app/components/editor/EditorSidebar.tsx +94 -2
  130. package/corpus/templates/slides/app/components/editor/EditorToolbar.tsx +17 -29
  131. package/corpus/templates/slides/app/components/editor/SlideContextToolbar.tsx +1 -1
  132. package/corpus/templates/slides/app/context/DeckContext.tsx +42 -2
  133. package/corpus/templates/slides/app/global.css +7 -40
  134. package/corpus/templates/slides/app/i18n/en-US.ts +4 -0
  135. package/corpus/templates/slides/app/pages/DeckEditor.tsx +130 -45
  136. package/dist/agent/index.d.ts +1 -1
  137. package/dist/agent/production-agent.d.ts +30 -0
  138. package/dist/agent/production-agent.js +105 -9
  139. package/dist/agent/thread-data-builder.js +17 -1
  140. package/dist/agent/types.d.ts +9 -0
  141. package/dist/cli/skills-content/help.js +6 -4
  142. package/dist/cli/skills.js +17 -2
  143. package/dist/cli/workspacify.d.ts +5 -0
  144. package/dist/cli/workspacify.js +65 -8
  145. package/dist/client/AgentPanel.d.ts +5 -0
  146. package/dist/client/AgentPanel.js +32 -13
  147. package/dist/client/AssistantChat.d.ts +36 -1
  148. package/dist/client/AssistantChat.js +175 -110
  149. package/dist/client/MultiTabAssistantChat.js +44 -27
  150. package/dist/client/active-run-state.d.ts +14 -1
  151. package/dist/client/active-run-state.js +0 -0
  152. package/dist/client/agent-chat-adapter.js +107 -5
  153. package/dist/client/analytics.js +9 -2
  154. package/dist/client/chat/markdown-renderer.js +4 -2
  155. package/dist/client/chat/message-components.d.ts +2 -2
  156. package/dist/client/chat/message-components.js +69 -35
  157. package/dist/client/chat/run-recovery.d.ts +4 -1
  158. package/dist/client/chat/run-recovery.js +62 -30
  159. package/dist/client/chat/tool-call-display.d.ts +12 -3
  160. package/dist/client/chat/tool-call-display.js +79 -40
  161. package/dist/client/chat/widgets/DataChartRenderer.js +3 -1
  162. package/dist/client/chat/widgets/DataChartWidget.js +8 -2
  163. package/dist/client/chat/widgets/DataInsightsWidget.js +3 -1
  164. package/dist/client/chat/widgets/DataTableWidget.js +23 -9
  165. package/dist/client/chat/widgets/builtin-tool-renderers.js +3 -1
  166. package/dist/client/chat-first/apps-rail.js +9 -4
  167. package/dist/client/chat-first/primary-nav.d.ts +2 -1
  168. package/dist/client/chat-first/primary-nav.js +3 -3
  169. package/dist/client/chat-first/types.d.ts +5 -1
  170. package/dist/client/components/ui/message-scroller.d.ts +1 -1
  171. package/dist/client/components/ui/message-scroller.js +7 -3
  172. package/dist/client/composer/runtime-adapters.js +3 -2
  173. package/dist/client/context-xray/ContextMeter.js +5 -1
  174. package/dist/client/context-xray/ContextXRayPanel.js +5 -5
  175. package/dist/client/error-format.d.ts +4 -0
  176. package/dist/client/error-format.js +93 -5
  177. package/dist/client/i18n.js +83 -17
  178. package/dist/client/markdown/InlineMarkdown.d.ts +23 -0
  179. package/dist/client/markdown/InlineMarkdown.js +65 -0
  180. package/dist/client/markdown/index.d.ts +1 -0
  181. package/dist/client/markdown/index.js +1 -0
  182. package/dist/client/observability/ThumbsFeedback.js +10 -8
  183. package/dist/client/review/ReviewThreadPanel.js +2 -1
  184. package/dist/client/run-stream-ownership.d.ts +39 -0
  185. package/dist/client/run-stream-ownership.js +65 -0
  186. package/dist/client/sharing/ShareButton.js +160 -54
  187. package/dist/coding-tools/run-code.js +2 -1
  188. package/dist/coding-tools/sandbox/background.d.ts +1 -0
  189. package/dist/coding-tools/sandbox/background.js +8 -1
  190. package/dist/coding-tools/sandbox/executions-store.d.ts +2 -0
  191. package/dist/coding-tools/sandbox/executions-store.js +41 -3
  192. package/dist/collab/awareness.d.ts +2 -2
  193. package/dist/collab/routes.d.ts +1 -1
  194. package/dist/collab/struct-routes.d.ts +1 -1
  195. package/dist/feature-flags/index.d.ts +1 -1
  196. package/dist/feature-flags/index.js +1 -1
  197. package/dist/feature-flags/store.d.ts +10 -0
  198. package/dist/feature-flags/store.js +112 -1
  199. package/dist/guards/no-env-credentials.js +4 -0
  200. package/dist/index.d.ts +2 -2
  201. package/dist/index.js +1 -1
  202. package/dist/integrations/adapters/slack.js +5 -1
  203. package/dist/localization/core-messages/ar-SA.d.ts +3 -0
  204. package/dist/localization/core-messages/ar-SA.js +541 -0
  205. package/dist/localization/core-messages/de-DE.d.ts +3 -0
  206. package/dist/localization/core-messages/de-DE.js +513 -0
  207. package/dist/localization/core-messages/en-US.d.ts +513 -0
  208. package/dist/localization/core-messages/en-US.js +513 -0
  209. package/dist/localization/core-messages/es-ES.d.ts +3 -0
  210. package/dist/localization/core-messages/es-ES.js +520 -0
  211. package/dist/localization/core-messages/fr-FR.d.ts +3 -0
  212. package/dist/localization/core-messages/fr-FR.js +520 -0
  213. package/dist/localization/core-messages/hi-IN.d.ts +3 -0
  214. package/dist/localization/core-messages/hi-IN.js +513 -0
  215. package/dist/localization/core-messages/ja-JP.d.ts +3 -0
  216. package/dist/localization/core-messages/ja-JP.js +506 -0
  217. package/dist/localization/core-messages/ko-KR.d.ts +3 -0
  218. package/dist/localization/core-messages/ko-KR.js +506 -0
  219. package/dist/localization/core-messages/pt-BR.d.ts +3 -0
  220. package/dist/localization/core-messages/pt-BR.js +520 -0
  221. package/dist/localization/core-messages/zh-CN.d.ts +3 -0
  222. package/dist/localization/core-messages/zh-CN.js +506 -0
  223. package/dist/localization/core-messages/zh-TW.d.ts +3 -0
  224. package/dist/localization/core-messages/zh-TW.js +506 -0
  225. package/dist/localization/core-messages.d.ts +524 -0
  226. package/dist/localization/core-messages.js +124 -0
  227. package/dist/localization/default-messages.d.ts +3 -0
  228. package/dist/localization/default-messages.js +3 -0
  229. package/dist/notifications/routes.d.ts +1 -1
  230. package/dist/observability/routes.d.ts +2 -2
  231. package/dist/progress/routes.d.ts +1 -1
  232. package/dist/provider-api/actions/custom-provider-registration.d.ts +11 -11
  233. package/dist/provider-api/actions/provider-api.d.ts +15 -15
  234. package/dist/resources/agents.js +40 -5
  235. package/dist/resources/metadata.d.ts +10 -0
  236. package/dist/resources/metadata.js +7 -3
  237. package/dist/review/actions/create-review-comment.js +1 -1
  238. package/dist/review/actions/reply-review-comment.js +1 -1
  239. package/dist/review/actions/resolve-review-thread.js +1 -1
  240. package/dist/secrets/routes.d.ts +6 -6
  241. package/dist/server/action-routes.js +32 -6
  242. package/dist/server/agent-chat/plugin-options.d.ts +7 -2
  243. package/dist/server/agent-chat-plugin.d.ts +10 -0
  244. package/dist/server/agent-chat-plugin.js +144 -41
  245. package/dist/server/agent-discovery.js +14 -3
  246. package/dist/server/agent-run-context.d.ts +7 -1
  247. package/dist/server/agent-run-context.js +9 -2
  248. package/dist/server/agent-teams-run-queue.d.ts +3 -0
  249. package/dist/server/agent-teams.js +38 -9
  250. package/dist/server/core-routes-plugin.js +1 -1
  251. package/dist/server/identity-sso-migrations.d.ts +7 -0
  252. package/dist/server/identity-sso-migrations.js +36 -0
  253. package/dist/server/identity-sso-store.d.ts +3 -2
  254. package/dist/server/identity-sso-store.js +8 -3
  255. package/dist/server/index.d.ts +1 -1
  256. package/dist/server/realtime-token.d.ts +1 -1
  257. package/dist/server/release-migrations.js +4 -0
  258. package/dist/server/request-context.d.ts +7 -0
  259. package/dist/server/request-context.js +15 -0
  260. package/dist/tracking/providers.js +13 -3
  261. package/dist/workspace-files/tool.js +1 -1
  262. package/docs/content/agent-surfaces.mdx +30 -0
  263. package/package.json +3 -2
@@ -94,8 +94,24 @@ export function buildAssistantMessage(events, runId, options = {}) {
94
94
  continue;
95
95
  }
96
96
  if (event.type === "tool_start") {
97
+ const explicitToolCallId = event.id?.trim();
98
+ // A tool_start whose id is already in this turn is a REPLAY, not a new
99
+ // call: the tool-call journal and zombie-ledger recovery paths re-emit
100
+ // tool_start/tool_done for calls that already ran in an interrupted
101
+ // chunk. The live client coalesces those onto the original card, so a
102
+ // blind push here persisted a second copy of a call the user had only
103
+ // ever seen once — the duplicate that appears only after a reload.
104
+ // Matching the tool name too, so an id reused across different tools
105
+ // stays two cards rather than being silently merged into one.
106
+ if (explicitToolCallId) {
107
+ const replayed = content.some((part) => part.type === "tool-call" &&
108
+ part.toolCallId === explicitToolCallId &&
109
+ part.toolName === (event.tool ?? "unknown"));
110
+ if (replayed)
111
+ continue;
112
+ }
97
113
  toolCallCounter += 1;
98
- const toolCallId = event.id?.trim() ||
114
+ const toolCallId = explicitToolCallId ||
99
115
  (runId ? `${runId}:tc_${toolCallCounter}` : `tc_${toolCallCounter}`);
100
116
  const args = (event.input ?? {});
101
117
  content.push({
@@ -186,6 +186,15 @@ export interface AgentChatRequest {
186
186
  */
187
187
  payloadRef?: boolean;
188
188
  };
189
+ /**
190
+ * Server-resolved action authorization carried across authenticated durable
191
+ * background dispatches. Normal client requests must not trust this field;
192
+ * the foreground handler deletes and replaces it before persistence.
193
+ */
194
+ __resolvedActionSurface?: {
195
+ orgId: string | null;
196
+ allowedActionNames: string[];
197
+ };
189
198
  /**
190
199
  * Stable identity for the logical assistant turn this request belongs to.
191
200
  * The client sends the SAME turnId for the initial POST and every
@@ -73,7 +73,9 @@ run "npx @agent-native/core@latest recap setup" / "npx @agent-native/core@latest
73
73
  verify GitHub Actions. Docs: ${docsUrl("pr-visual-recap")}.
74
74
 
75
75
  The status/update commands inspect copied Agent Native skill folders and refresh
76
- their instruction files from the current @agent-native/core package. In generated
77
- apps/workspaces, "skills update scaffold --project" refreshes the framework
78
- skills copied into the scaffold and repairs AGENTS.md / CLAUDE.md and
79
- .agents/skills / .claude/skills compatibility links.`;
76
+ their instruction files from the current @agent-native/core package. In a
77
+ standalone generated app, "skills update scaffold --project" refreshes the
78
+ framework skill copies. In a generated workspace, it refreshes workspace-core,
79
+ removes stale generic framework copies, repairs inherited .agents/skills links
80
+ for every app, and repairs AGENTS.md / CLAUDE.md / .claude/skills compatibility
81
+ links.`;
@@ -20,6 +20,7 @@ import { PR_VISUAL_RECAP_SETUP, writePrVisualRecapWorkflow } from "./recap.js";
20
20
  import { setupAgentSymlinks } from "./setup-agents.js";
21
21
  import { ASSETS_SKILL_MD, CANVAS_REFERENCE_MD, CONNECTION_REFERENCE_MD, CONTENT_SKILL_MD, DESIGN_EXPLORATION_SKILL_MD, DESIGN_VISUAL_EDIT_SKILL_MD, DOCUMENT_QUALITY_REFERENCE_MD, EXEMPLAR_REFERENCE_MD, HELP, LOCAL_FILES_REFERENCE_MD, REWIND_SKILL_MD, VISUAL_PLANS_SKILL_MD, VISUAL_RECAP_SKILL_MD, VISUALIZE_REPO_SKILL_MD, WIREFRAME_REFERENCE_MD, } from "./skills-content/index.js";
22
22
  import { createCliTelemetry } from "./telemetry.js";
23
+ import { linkDefaultWorkspaceSkills, removeCopiedFrameworkSkills, } from "./workspacify.js";
23
24
  export { CANVAS_REFERENCE_MD, CONNECTION_REFERENCE_MD, DOCUMENT_QUALITY_REFERENCE_MD, EXEMPLAR_REFERENCE_MD, LOCAL_FILES_REFERENCE_MD, VISUAL_PLANS_SKILL_MD, VISUAL_RECAP_SKILL_MD, VISUALIZE_REPO_SKILL_MD, WIREFRAME_REFERENCE_MD, };
24
25
  export const BUILT_IN_APP_SKILLS = {
25
26
  assets: {
@@ -1401,6 +1402,17 @@ function repairScaffoldAgentLinks(states) {
1401
1402
  continue;
1402
1403
  const appDir = path.join(appsDir, entry.name);
1403
1404
  if (fs.existsSync(path.join(appDir, "package.json"))) {
1405
+ const preserved = new Set([
1406
+ ...removeCopiedFrameworkSkills(appDir, {
1407
+ workspaceRoot: state.workspaceRoot,
1408
+ }),
1409
+ ...linkDefaultWorkspaceSkills(appDir, state.workspaceRoot),
1410
+ ]);
1411
+ if (preserved.size > 0) {
1412
+ console.warn(`[skills] Preserved app-local framework-named skills in ${appDir}: ${[
1413
+ ...preserved,
1414
+ ].join(", ")}. Migrate them explicitly before inheriting workspace copies.`);
1415
+ }
1404
1416
  setupAgentSymlinks(appDir);
1405
1417
  refreshCopiedClaudeSkills(appDir);
1406
1418
  }
@@ -3171,8 +3183,11 @@ function runSkillsStatusOrUpdate(parsed, options, update) {
3171
3183
  const scaffoldChanged = update
3172
3184
  ? updateScaffoldGuidanceStates(scaffoldBefore, parsed.dryRun)
3173
3185
  : [];
3174
- if (update && !parsed.dryRun && scaffoldChanged.length > 0) {
3175
- repairScaffoldAgentLinks(scaffoldChanged);
3186
+ if (update && !parsed.dryRun) {
3187
+ const workspaceStates = scaffoldBefore.filter((state) => state.workspaceRoot && state.sharedPackageDir);
3188
+ if (scaffoldChanged.length > 0 || workspaceStates.length > 0) {
3189
+ repairScaffoldAgentLinks([...scaffoldChanged, ...workspaceStates]);
3190
+ }
3176
3191
  }
3177
3192
  const skillAfter = update && !parsed.dryRun
3178
3193
  ? collectSkillInstallStates(parsed, options)
@@ -17,6 +17,11 @@ export interface WorkspacifyOptions {
17
17
  toolkitDependencyVersion?: string;
18
18
  }
19
19
  export declare function workspacifyApp(opts: WorkspacifyOptions): void;
20
+ export declare function removeCopiedFrameworkSkills(appDir: string, options?: {
21
+ workspaceRoot?: string;
22
+ allowUnverified?: boolean;
23
+ }): string[];
24
+ export declare function linkDefaultWorkspaceSkills(appDir: string, workspaceRoot: string): string[];
20
25
  /**
21
26
  * Parse a workspace core package name into its npm scope.
22
27
  * "@my-company/shared" → "my-company"
@@ -144,27 +144,83 @@ export function workspacifyApp(opts) {
144
144
  }
145
145
  }
146
146
  function linkInheritedWorkspaceSkills(opts) {
147
- const appSkillsDir = path.join(opts.appDir, ".agents", "skills");
148
147
  const workspaceSkillsDir = path.join(opts.workspaceRoot, ".agents", "skills");
149
148
  if (!fs.existsSync(workspaceSkillsDir))
150
149
  return;
151
- fs.mkdirSync(appSkillsDir, { recursive: true });
150
+ removeCopiedFrameworkSkills(opts.appDir, { allowUnverified: true });
151
+ linkDefaultWorkspaceSkills(opts.appDir, opts.workspaceRoot);
152
+ }
153
+ function skillDirContentsMatch(sourceDir, targetDir) {
154
+ const sourceStat = fs.lstatSync(sourceDir, { throwIfNoEntry: false });
155
+ const targetStat = fs.lstatSync(targetDir, { throwIfNoEntry: false });
156
+ if (!sourceStat?.isDirectory() || !targetStat?.isDirectory())
157
+ return false;
158
+ const sourceEntries = fs.readdirSync(sourceDir, { withFileTypes: true });
159
+ const targetEntries = fs.readdirSync(targetDir, { withFileTypes: true });
160
+ if (sourceEntries.length !== targetEntries.length)
161
+ return false;
162
+ return sourceEntries.every((sourceEntry) => {
163
+ const sourcePath = path.join(sourceDir, sourceEntry.name);
164
+ const targetPath = path.join(targetDir, sourceEntry.name);
165
+ const targetEntry = targetEntries.find((entry) => entry.name === sourceEntry.name);
166
+ if (!targetEntry)
167
+ return false;
168
+ if (sourceEntry.isSymbolicLink()) {
169
+ return (targetEntry.isSymbolicLink() &&
170
+ fs.readlinkSync(sourcePath) === fs.readlinkSync(targetPath));
171
+ }
172
+ if (sourceEntry.isDirectory()) {
173
+ return (targetEntry.isDirectory() &&
174
+ skillDirContentsMatch(sourcePath, targetPath));
175
+ }
176
+ return (sourceEntry.isFile() &&
177
+ targetEntry.isFile() &&
178
+ fs.readFileSync(sourcePath).equals(fs.readFileSync(targetPath)));
179
+ });
180
+ }
181
+ export function removeCopiedFrameworkSkills(appDir, options = {}) {
182
+ const appSkillsDir = path.join(appDir, ".agents", "skills");
183
+ const workspaceSkillsDir = options.workspaceRoot
184
+ ? path.join(options.workspaceRoot, ".agents", "skills")
185
+ : undefined;
186
+ const preserved = [];
152
187
  for (const skill of FRAMEWORK_TEMPLATE_SHARED_SKILLS) {
153
188
  const localPath = path.join(appSkillsDir, skill);
154
- if (fs.existsSync(localPath) ||
155
- fs.lstatSync(localPath, { throwIfNoEntry: false })) {
156
- fs.rmSync(localPath, { recursive: true, force: true });
189
+ const stat = fs.lstatSync(localPath, { throwIfNoEntry: false });
190
+ if (!stat || stat.isSymbolicLink())
191
+ continue;
192
+ const workspacePath = workspaceSkillsDir
193
+ ? path.join(workspaceSkillsDir, skill)
194
+ : undefined;
195
+ if (!options.allowUnverified &&
196
+ (!workspacePath || !skillDirContentsMatch(workspacePath, localPath))) {
197
+ preserved.push(skill);
198
+ continue;
157
199
  }
200
+ fs.rmSync(localPath, { recursive: true, force: true });
158
201
  }
202
+ return preserved;
203
+ }
204
+ export function linkDefaultWorkspaceSkills(appDir, workspaceRoot) {
205
+ const appSkillsDir = path.join(appDir, ".agents", "skills");
206
+ const workspaceSkillsDir = path.join(workspaceRoot, ".agents", "skills");
207
+ if (!fs.existsSync(workspaceSkillsDir))
208
+ return [];
209
+ fs.mkdirSync(appSkillsDir, { recursive: true });
210
+ const preserved = [];
159
211
  for (const skill of DEFAULT_WORKSPACE_SKILLS) {
160
212
  const inheritedPath = path.join(workspaceSkillsDir, skill);
161
213
  if (!fs.existsSync(inheritedPath))
162
214
  continue;
163
215
  const linkPath = path.join(appSkillsDir, skill);
164
- if (fs.existsSync(linkPath) ||
165
- fs.lstatSync(linkPath, { throwIfNoEntry: false })) {
166
- fs.rmSync(linkPath, { recursive: true, force: true });
216
+ const existing = fs.lstatSync(linkPath, { throwIfNoEntry: false });
217
+ if (existing &&
218
+ !existing.isSymbolicLink() &&
219
+ !skillDirContentsMatch(inheritedPath, linkPath)) {
220
+ preserved.push(skill);
221
+ continue;
167
222
  }
223
+ fs.rmSync(linkPath, { recursive: true, force: true });
168
224
  try {
169
225
  fs.symlinkSync(path.relative(appSkillsDir, inheritedPath), linkPath, "dir");
170
226
  }
@@ -172,6 +228,7 @@ function linkInheritedWorkspaceSkills(opts) {
172
228
  throw new Error(`Could not link inherited workspace skill ${skill} into ${appSkillsDir}: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
173
229
  }
174
230
  }
231
+ return preserved;
175
232
  }
176
233
  /**
177
234
  * The version an existing workspace already pins for a framework package.
@@ -29,6 +29,11 @@ export declare function normalizeAgentPanelModeForSurface(mode: PanelMode, allow
29
29
  export declare function deferAgentPanelOverlayOpen(event: {
30
30
  preventDefault: () => void;
31
31
  }, closeMenu: () => void, openOverlay: () => void): void;
32
+ export declare function consumeAgentPanelOverlayFocusRestore(pendingOverlayRef: {
33
+ current: boolean;
34
+ }, event: {
35
+ preventDefault: () => void;
36
+ }): void;
32
37
  export declare function getAgentPanelChatTabGroups(tabs: MultiTabAssistantChatHeaderProps["tabs"], activeTabId: string): {
33
38
  activeTab: import("./MultiTabAssistantChat.js").ChatTab | undefined;
34
39
  childTabs: import("./MultiTabAssistantChat.js").ChatTab[];
@@ -157,6 +157,12 @@ export function deferAgentPanelOverlayOpen(event, closeMenu, openOverlay) {
157
157
  setTimeout(openOverlay, 0);
158
158
  }
159
159
  }
160
+ export function consumeAgentPanelOverlayFocusRestore(pendingOverlayRef, event) {
161
+ if (!pendingOverlayRef.current)
162
+ return;
163
+ pendingOverlayRef.current = false;
164
+ event.preventDefault();
165
+ }
160
166
  function useAvailableClis() {
161
167
  const [clis, setClis] = useState([]);
162
168
  useEffect(() => {
@@ -194,6 +200,7 @@ function IconTooltip({ content, children, }) {
194
200
  return (_jsx(DesignSystemTooltip, { trigger: children, content: normalizeTooltipText(content), placement: "bottom", delayMs: 250, className: "z-[300] overflow-hidden rounded-md border border-border bg-popover px-2 py-1 text-[11px] text-foreground shadow-md" }));
195
201
  }
196
202
  function ChatLoadingSkeleton({ renderHeader, centerComposerWhenEmpty = false, composerSlot, composerAreaClassName, composerLayoutVariant = "default", }) {
203
+ const t = useT();
197
204
  // Provide empty no-op implementations so renderHeader can render the real
198
205
  // tab/mode buttons without needing actual chat state.
199
206
  const noop = useCallback(() => { }, []);
@@ -213,7 +220,7 @@ function ChatLoadingSkeleton({ renderHeader, centerComposerWhenEmpty = false, co
213
220
  toggleHistory: noop,
214
221
  };
215
222
  if (centerComposerWhenEmpty) {
216
- return (_jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [renderHeader ? renderHeader(stubProps) : null, _jsxs("div", { "data-agent-empty-state": "centered", className: "relative flex flex-1 flex-col h-full min-h-0 text-foreground", children: [_jsx("div", { className: "agent-chat-scroll flex-1 overflow-y-auto overflow-x-hidden min-h-0", children: _jsx("div", { className: "agent-empty-state sr-only", "aria-busy": "true", children: "Loading chat..." }) }), composerSlot, _jsx("div", { className: "agent-composer-stack", children: _jsx("div", { className: cn("agent-composer-area shrink-0 px-3 py-2", composerLayoutVariant !== "default" &&
223
+ return (_jsxs("div", { className: "flex flex-col flex-1 min-h-0", children: [renderHeader ? renderHeader(stubProps) : null, _jsxs("div", { "data-agent-empty-state": "centered", className: "relative flex flex-1 flex-col h-full min-h-0 text-foreground", children: [_jsx("div", { className: "agent-chat-scroll flex-1 overflow-y-auto overflow-x-hidden min-h-0", children: _jsx("div", { className: "agent-empty-state sr-only", "aria-busy": "true", children: t("agentChat.empty.loadingChat") }) }), composerSlot, _jsx("div", { className: "agent-composer-stack", children: _jsx("div", { className: cn("agent-composer-area shrink-0 px-3 py-2", composerLayoutVariant !== "default" &&
217
224
  `agent-composer-area--${composerLayoutVariant}`, composerAreaClassName), children: _jsxs("div", { className: cn("agent-composer-root flex flex-col rounded-lg border border-input bg-muted/45 transition-colors", composerLayoutVariant !== "default" &&
218
225
  `agent-composer-root--${composerLayoutVariant}`), children: [_jsx("div", { className: "px-3 pt-3", children: _jsx("div", { className: "h-5 w-3/5 rounded bg-muted animate-pulse motion-reduce:animate-none" }) }), _jsxs("div", { className: "mt-auto flex items-center gap-2 px-3 py-2", children: [_jsx("div", { className: "h-5 w-5 rounded bg-muted animate-pulse motion-reduce:animate-none" }), _jsx("div", { className: "ml-auto h-4 w-28 rounded bg-muted animate-pulse motion-reduce:animate-none" }), _jsx("div", { className: "h-7 w-7 rounded-md bg-muted animate-pulse motion-reduce:animate-none" })] })] }) }) })] })] }));
219
226
  }
@@ -667,6 +674,11 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
667
674
  const [headerMenuOpen, setHeaderMenuOpen] = useState(false);
668
675
  const [feedbackOpen, setFeedbackOpen] = useState(false);
669
676
  const [shareFromMenuOpen, setShareFromMenuOpen] = useState(false);
677
+ const preventHeaderMenuFocusRestoreRef = useRef(false);
678
+ const closeHeaderMenuForOverlay = useCallback(() => {
679
+ preventHeaderMenuFocusRestoreRef.current = true;
680
+ setHeaderMenuOpen(false);
681
+ }, []);
670
682
  const getChatThreadShareUrl = useCallback((threadId) => {
671
683
  if (typeof window === "undefined")
672
684
  return undefined;
@@ -710,9 +722,13 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
710
722
  (activeTabMessageCount <= 0 && activeTab.status === "idle")) {
711
723
  return null;
712
724
  }
713
- return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7", defaultOpen: onCollapse && shareFromMenuOpen, onOpenChange: onCollapse ? setShareFromMenuOpen : undefined }));
725
+ return (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || t("agentPanel.chat"), shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-7 w-7", defaultOpen: onCollapse && shareFromMenuOpen, onOpenChange: onCollapse ? setShareFromMenuOpen : undefined }));
714
726
  })(), feedbackEnabled ? (_jsx(FeedbackButton, { variant: "icon", side: "bottom", align: "end", chatSessionId: activeChatSessionId, chatStorageKey: storageKey, open: feedbackOpen, onOpenChange: setFeedbackOpen, trigger: _jsx("button", { type: "button", tabIndex: -1, "aria-hidden": "true", className: "pointer-events-none absolute end-0 top-full h-px w-px opacity-0" }) })) : null, mode === "chat" && (_jsx(IconTooltip, { content: t("agentPanel.newChat"), children: _jsx("button", { onClick: addTab, "aria-label": t("agentPanel.newChat"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), !onCollapse && mode === "cli" && canUseCodeTools && (_jsx(IconTooltip, { content: t("agentPanel.newTerminal"), children: _jsx("button", { onClick: addCliTab, "aria-label": t("agentPanel.newTerminal"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconPlus, { size: 14 }) }) })), _jsxs(DropdownMenu, { open: headerMenuOpen, onOpenChange: setHeaderMenuOpen, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx("button", { className: cn("flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", (headerMenuOpen || mode === "settings") &&
715
- "bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: fullViewAction.href, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
727
+ "bg-accent text-foreground"), "aria-label": t("agentPanel.panelOptions"), children: _jsx(IconDotsVertical, { size: 14 }) }) }), _jsxs(DropdownMenuContent, { align: "end", sideOffset: 6, className: "w-48", onCloseAutoFocus: (event) => {
728
+ // A sibling overlay owns focus next; restoring it to the menu
729
+ // trigger would dismiss that overlay as an outside interaction.
730
+ consumeAgentPanelOverlayFocusRestore(preventHeaderMenuFocusRestoreRef, event);
731
+ }, children: [onCollapse && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: onCollapse, children: [_jsx(IconLayoutSidebarRightCollapse, { size: 14, className: "shrink-0" }), t("agentPanel.collapseSidebar"), _jsx(DropdownMenuShortcut, { children: toggleSidebarHint })] }), _jsx(DropdownMenuSeparator, {})] })), onCollapse && mode === "chat" && wideDrawerAction ? (_jsxs(DropdownMenuItem, { onSelect: wideDrawerAction, children: [_jsx(IconArrowsHorizontal, { size: 14, className: "shrink-0" }), wideDrawerLabel, _jsx(DropdownMenuShortcut, { children: widenChatHint })] })) : null, fullViewAction?.kind === "callback" && onFullViewRequest ? (_jsxs(DropdownMenuItem, { onSelect: onFullViewRequest, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] })) : fullViewAction?.kind === "link" ? (_jsx(DropdownMenuItem, { asChild: true, children: _jsxs(Link, { to: fullViewAction.href, "aria-label": t("agentPanel.openFullView"), children: [_jsx(IconArrowsMaximize, { size: 14, className: "shrink-0" }), t("agentPanel.openFullView")] }) })) : null, (onCollapse && mode === "chat" && wideDrawerAction) ||
716
732
  fullViewAction ? (_jsx(DropdownMenuSeparator, {})) : null, onCollapse && mode === "chat" && (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: addTab, children: [_jsx(IconPlus, { size: 14, className: "shrink-0" }), t("agentPanel.newChat")] }), (() => {
717
733
  const activeTab = activeChatSessionId
718
734
  ? tabs.find((tab) => tab.id === activeChatSessionId)
@@ -721,18 +737,19 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
721
737
  (activeTabMessageCount <= 0 && activeTab.status === "idle")) {
722
738
  return null;
723
739
  }
724
- return (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, () => setHeaderMenuOpen(false), () => setShareFromMenuOpen(true)), children: [_jsx(IconShare3, { size: 14, className: "shrink-0" }), "Share"] }));
725
- })()] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, () => setHeaderMenuOpen(false), toggleHistory), children: [_jsx(IconHistory, { size: 14, className: "shrink-0" }), showHistory
740
+ return (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, closeHeaderMenuForOverlay, () => setShareFromMenuOpen(true)), children: [_jsx(IconShare3, { size: 14, className: "shrink-0" }), "Share"] }));
741
+ })()] })), mode === "chat" && toggleHistory && (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, closeHeaderMenuForOverlay, toggleHistory), children: [_jsx(IconHistory, { size: 14, className: "shrink-0" }), showHistory
726
742
  ? t("agentPanel.hideChats")
727
743
  : t("agentPanel.allChats")] })), mode === "chat" && (_jsx(RunsTrayMenuItem, { pollMs: 0, limit: 12, showRecent: true, onOpenThread: openRunThread })), mode === "chat" && _jsx(DropdownMenuSeparator, {}), mode === "cli" && availableClis.length > 0 && (_jsxs(_Fragment, { children: [availableClis.map((cli) => (_jsxs(DropdownMenuItem, { onSelect: () => selectCli(cli.command), className: cn(cli.command === selectedCli
728
744
  ? "font-medium"
729
- : "text-muted-foreground"), children: [cli.command === selectedCli ? (_jsx(IconCheck, { size: 12, className: "shrink-0" })) : (_jsx("span", { className: "w-3" })), cli.label] }, cli.command))), _jsx(DropdownMenuSeparator, {})] })), allowSettingsMode && (_jsxs(DropdownMenuItem, { onSelect: () => switchMode("settings"), className: cn(mode === "settings" ? "font-medium" : "text-muted-foreground"), children: [_jsx(IconSettings, { size: 14, className: "shrink-0" }), t("agentPanel.settings")] })), feedbackEnabled ? (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, () => setHeaderMenuOpen(false), () => setFeedbackOpen(true)), children: [_jsx(IconMessageDots, { size: 14, className: "shrink-0" }), t("agentPanel.feedback")] })) : null, ((mode === "chat" && activeTabId) ||
745
+ : "text-muted-foreground"), children: [cli.command === selectedCli ? (_jsx(IconCheck, { size: 12, className: "shrink-0" })) : (_jsx("span", { className: "w-3" })), cli.label] }, cli.command))), _jsx(DropdownMenuSeparator, {})] })), allowSettingsMode && (_jsxs(DropdownMenuItem, { onSelect: () => switchMode("settings"), className: cn(mode === "settings" ? "font-medium" : "text-muted-foreground"), children: [_jsx(IconSettings, { size: 14, className: "shrink-0" }), t("agentPanel.settings")] })), feedbackEnabled ? (_jsxs(DropdownMenuItem, { onSelect: (event) => deferAgentPanelOverlayOpen(event, closeHeaderMenuForOverlay, () => setFeedbackOpen(true)), children: [_jsx(IconMessageDots, { size: 14, className: "shrink-0" }), t("agentPanel.feedback")] })) : null, ((mode === "chat" && activeTabId) ||
730
746
  (mode === "cli" && canUseCodeTools && activeCliTab)) && (_jsxs(_Fragment, { children: [_jsx(DropdownMenuSeparator, {}), mode === "chat" ? (shouldShowAgentPanelChatTabBar(tabs, activeTabId) ? (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: () => closeTab(activeTabId), children: [_jsx(IconX, { size: 14, className: "shrink-0" }), t("agentPanel.closeTab"), _jsx(DropdownMenuShortcut, { children: closeTabHint })] }), _jsx(DropdownMenuItem, { onSelect: () => closeOtherTabs(activeTabId), children: t("agentPanel.closeOtherTabs") }), _jsxs(DropdownMenuItem, { onSelect: () => closeAllTabs(), children: [t("agentPanel.closeAllTabs"), _jsx(DropdownMenuShortcut, { children: closeAllTabsHint })] })] })) : (_jsxs(DropdownMenuItem, { onSelect: clearActiveTab, children: [_jsx(IconX, { size: 14, className: "shrink-0" }), t("agentPanel.clearChat")] }))) : (_jsxs(_Fragment, { children: [_jsxs(DropdownMenuItem, { onSelect: () => closeCliTab(activeCliTab), children: [_jsx(IconX, { size: 14, className: "shrink-0" }), t("agentPanel.closeTab"), _jsx(DropdownMenuShortcut, { children: closeTabHint })] }), _jsx(DropdownMenuItem, { onSelect: () => closeOtherCliTabs(activeCliTab), children: t("agentPanel.closeOtherTabs") }), _jsxs(DropdownMenuItem, { onSelect: () => closeAllCliTabs(), children: [t("agentPanel.closeAllTabs"), _jsx(DropdownMenuShortcut, { children: closeAllTabsHint })] })] }))] }))] })] }), onCollapse && (_jsx(IconTooltip, { content: t("agentPanel.collapseSidebar"), children: _jsx("button", { type: "button", onClick: onCollapse, "aria-label": t("agentPanel.collapseSidebar"), className: "flex h-6 w-6 items-center justify-center rounded text-muted-foreground hover:text-foreground hover:bg-accent/50", children: _jsx(IconX, { size: 14 }) }) }))] })), [
731
747
  activeCliTab,
732
748
  addCliTab,
733
749
  allowSettingsMode,
734
750
  availableClis,
735
751
  canUseCodeTools,
752
+ closeHeaderMenuForOverlay,
736
753
  closeAllCliTabs,
737
754
  closeAllTabsHint,
738
755
  closeCliTab,
@@ -769,7 +786,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
769
786
  ? tabs.find((tab) => tab.id === activeTabId)
770
787
  : undefined;
771
788
  const canShareActiveTab = activeTab && (activeTabMessageCount > 0 || activeTab.status !== "idle");
772
- return (_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", "data-agent-page-chat-fade": "", className: "pointer-events-none absolute inset-x-0 top-0 z-50 h-16 bg-gradient-to-b from-background via-background/90 to-transparent opacity-0 transition-opacity duration-150" }), _jsx("div", { className: "pointer-events-none absolute inset-x-0 top-3 z-[60] flex justify-end px-3 sm:top-4 sm:px-4", children: _jsxs("div", { className: "pointer-events-auto flex items-center gap-1", children: [canShareActiveTab ? (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || "Chat", shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-8 w-8 border border-border bg-background/95 shadow-sm backdrop-blur hover:bg-accent" })) : null, _jsxs("button", { type: "button", "data-agent-page-new-chat": "", "aria-label": t("agentPanel.newChat"), onClick: () => {
789
+ return (_jsxs(_Fragment, { children: [_jsx("div", { "aria-hidden": "true", "data-agent-page-chat-fade": "", className: "pointer-events-none absolute inset-x-0 top-0 z-50 h-16 bg-gradient-to-b from-background via-background/90 to-transparent opacity-0 transition-opacity duration-150" }), _jsx("div", { className: "pointer-events-none absolute inset-x-0 top-3 z-[60] flex justify-end px-3 sm:top-4 sm:px-4", children: _jsxs("div", { className: "pointer-events-auto flex items-center gap-1", children: [canShareActiveTab ? (_jsx(ShareButton, { resourceType: "chat_thread", resourceId: activeTab.id, allowedRoles: ["viewer", "editor", "admin"], resourceTitle: activeTab.label || t("agentPanel.chat"), shareUrl: getChatThreadShareUrl(activeTab.id), trigger: "icon", triggerClassName: "h-8 w-8 border border-border bg-background/95 shadow-sm backdrop-blur hover:bg-accent" })) : null, _jsxs("button", { type: "button", "data-agent-page-new-chat": "", "aria-label": t("agentPanel.newChat"), onClick: () => {
773
790
  addTab();
774
791
  }, className: "inline-flex h-8 items-center gap-1.5 rounded-md border border-border bg-background/95 px-2.5 text-xs font-medium text-foreground shadow-sm backdrop-blur transition-colors hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", children: [_jsx(IconPlus, { size: 14 }), _jsx("span", { children: t("agentPanel.newChat") })] })] }) })] }));
775
792
  }, [getChatThreadShareUrl, t]);
@@ -813,7 +830,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
813
830
  activeTab?.parentThreadId === tab.id);
814
831
  return (_jsxs("div", { role: "button", tabIndex: 0, ref: isActive ? activeTabRefCb : undefined, onClick: () => setActiveTabId(tab.id), onKeyDown: activateOnKeyDown(() => setActiveTabId(tab.id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer max-w-[150px]", isActive
815
832
  ? "bg-accent text-foreground"
816
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
833
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
817
834
  e.stopPropagation();
818
835
  closeTab(tab.id);
819
836
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -856,7 +873,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
856
873
  activeTab?.parentThreadId === tab.id);
857
874
  return (_jsxs("div", { role: "button", tabIndex: 0, ref: isActive ? activeTabRefCb : undefined, onClick: () => setActiveTabId(tab.id), onKeyDown: activateOnKeyDown(() => setActiveTabId(tab.id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer max-w-[150px]", isActive
858
875
  ? "bg-accent text-foreground"
859
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
876
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1.5 w-1.5 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
860
877
  e.stopPropagation();
861
878
  closeTab(tab.id);
862
879
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -874,7 +891,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
874
891
  ? activeTabRefCb
875
892
  : undefined, onClick: () => setActiveCliTab(id), onKeyDown: activateOnKeyDown(() => setActiveCliTab(id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2.5 py-1.5 text-[11px] font-medium cursor-pointer", id === activeCliTab
876
893
  ? "bg-accent text-foreground"
877
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsxs("span", { children: ["Terminal ", i + 1] }), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
894
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsxs("span", { children: ["Terminal ", i + 1] }), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
878
895
  e.stopPropagation();
879
896
  closeCliTab(id);
880
897
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -892,7 +909,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
892
909
  ? activeTabRefCb
893
910
  : undefined, onClick: () => setActiveTabId(tab.id), onKeyDown: activateOnKeyDown(() => setActiveTabId(tab.id)), className: cn("agent-tab relative flex shrink-0 items-center gap-1 rounded-md px-2 py-1 text-[10px] font-medium cursor-pointer max-w-[140px]", tab.id === activeTabId
894
911
  ? "bg-accent text-foreground"
895
- : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.subAgentName || tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1 w-1 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": "Close tab", onClick: (e) => {
912
+ : "text-muted-foreground hover:bg-accent hover:text-foreground"), children: [_jsx("span", { className: "truncate pe-1", children: tab.subAgentName || tab.label }), tab.status === "running" && (_jsx("span", { className: "h-1 w-1 shrink-0 rounded-full bg-muted-foreground/50 animate-pulse" })), _jsx("button", { type: "button", "aria-label": t("agentPanel.closeTab"), onClick: (e) => {
896
913
  e.stopPropagation();
897
914
  closeTab(tab.id);
898
915
  }, className: "agent-tab-close flex items-center justify-end text-muted-foreground hover:text-foreground", style: {
@@ -921,6 +938,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
921
938
  activeTabRefCb,
922
939
  activateOnKeyDown,
923
940
  closeCliTab,
941
+ t,
924
942
  ]);
925
943
  return (_jsxs("div", { className: cn("agent-panel-root flex flex-1 flex-col min-h-0 h-full text-[13px] leading-[1.2] antialiased", className), style: {
926
944
  ...AGENT_PANEL_ROOT_STYLE,
@@ -956,7 +974,7 @@ function AgentPanelInner({ defaultMode = "chat", className, style, apiUrl, empty
956
974
  ? mode === "cli" &&
957
975
  cliTabs.map((id) => (_jsx("div", { className: "min-h-0 relative flex-1", style: {
958
976
  display: id === activeCliTab ? undefined : "none",
959
- }, children: _jsx(Suspense, { fallback: _jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground text-sm", children: "Loading terminal..." }), children: _jsx(AgentTerminal, { command: selectedCli, hideInFrame: false, className: "h-full", style: { background: "transparent" } }) }) }, id)))
977
+ }, children: _jsx(Suspense, { fallback: _jsx("div", { className: "flex items-center justify-center h-full text-muted-foreground text-sm", children: t("agentPanel.loadingTerminal") }), children: _jsx(AgentTerminal, { command: selectedCli, hideInFrame: false, className: "h-full", style: { background: "transparent" } }) }) }, id)))
960
978
  : mode === "cli" && (_jsx("div", { className: "flex flex-1 flex-col items-center justify-center min-h-0 px-6 gap-3", children: _jsx(CodeAccessUnavailablePanel, { title: codeAccessEnabled
961
979
  ? t("agentPanel.cliRequiresDevMode")
962
980
  : codeUnavailableTitle, description: codeAccessEnabled
@@ -1941,6 +1959,7 @@ export function focusAgentChat() {
1941
1959
  * Dispatches a custom event that AgentSidebar listens for.
1942
1960
  */
1943
1961
  export function AgentToggleButton({ className }) {
1962
+ const t = useT();
1944
1963
  const [open, setOpen] = useState(false);
1945
1964
  useEffect(() => {
1946
1965
  const handler = (event) => {
@@ -1956,5 +1975,5 @@ export function AgentToggleButton({ className }) {
1956
1975
  // own close button.
1957
1976
  if (open)
1958
1977
  return null;
1959
- return (_jsx(DesignSystemTooltip, { trigger: _jsx("button", { type: "button", "aria-label": "Toggle agent", onClick: () => window.dispatchEvent(new Event("agent-panel:toggle")), className: cn("inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", className), children: _jsx(IconMessageDots, { size: 20, "aria-hidden": true }) }), content: "Toggle agent", delayMs: 200 }));
1978
+ return (_jsx(DesignSystemTooltip, { trigger: _jsx("button", { type: "button", "aria-label": t("agentPanel.toggleAgent"), onClick: () => window.dispatchEvent(new Event("agent-panel:toggle")), className: cn("inline-flex h-8 w-8 shrink-0 items-center justify-center rounded-md text-muted-foreground transition-colors hover:bg-accent/40 hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring", className), children: _jsx(IconMessageDots, { size: 20, "aria-hidden": true }) }), content: t("agentPanel.toggleAgent"), delayMs: 200 }));
1960
1979
  }
@@ -90,6 +90,27 @@ export declare function settleInterruptedAssistantToolCallsInRepo<T extends {
90
90
  };
91
91
  export declare function waitForThreadRunToClear(apiUrl: string, threadId?: string): Promise<boolean>;
92
92
  export declare function reconnectActivityFallbackContent(toolName: string | null | undefined): ContentPart[];
93
+ /**
94
+ * Whether the reconnect overlay — a SECOND fold of a run, rendered as a sibling
95
+ * of the message list — may appear.
96
+ *
97
+ * The adapter runtime and the reconnect reader both fold the same SSE events
98
+ * into their own accumulator. Whenever both are on screen the user sees the
99
+ * turn twice: duplicate tool cards (one spinning, one static) and the final
100
+ * message streaming in two places. Content-similarity dedupe cannot reliably
101
+ * hide the second copy, because the two readers disagree on tool-call identity
102
+ * (id-less activity cards get reader-local ids) and on how a turn is split
103
+ * across assistant messages.
104
+ *
105
+ * So ownership decides visibility, not similarity: if a runtime owns the turn,
106
+ * the overlay does not render. Keep this a pure function — it is the invariant
107
+ * the duplicate-render bug kept violating, and it must stay falsifiable.
108
+ */
109
+ export declare function shouldShowReconnectOverlay(state: {
110
+ isRuntimeRunning: boolean;
111
+ isReconnecting: boolean;
112
+ reconnectFrozen: boolean;
113
+ }): boolean;
93
114
  export declare function dedupeReconnectContentAgainstMessages(content: ContentPart[], messages: readonly unknown[], options?: {
94
115
  suppressToolRepeats?: boolean;
95
116
  trimTailTextOverlap?: boolean;
@@ -111,11 +132,22 @@ export declare function resolveAssistantChatRunningState({ forceStopped, isRunti
111
132
  isRunning: boolean;
112
133
  showRunningInUI: boolean;
113
134
  };
114
- export declare function resolveAssistantChatRunningStatusLabel({ runningActivityLabel, isAutoResuming, isReconnecting, hasReconnectContent, }: {
135
+ export declare function resolveAssistantChatRunningStatusLabel({ runningActivityLabel, isAutoResuming, isReconnecting, hasReconnectContent, labels, }: {
115
136
  runningActivityLabel: string | null | undefined;
116
137
  isAutoResuming: boolean;
117
138
  isReconnecting: boolean;
118
139
  hasReconnectContent: boolean;
140
+ labels?: {
141
+ thinking: string;
142
+ resuming: string;
143
+ stillWorking: string;
144
+ working?: string;
145
+ contactingModel?: string;
146
+ starting?: (activity: string) => string;
147
+ preparing?: (activity: string) => string;
148
+ writing?: (activity: string) => string;
149
+ stillGenerating?: (activity: string) => string;
150
+ };
119
151
  }): string;
120
152
  export declare function resolveAssistantChatComposerPlaceholder(composerPlaceholder: string | null | undefined): string;
121
153
  export declare function shouldShowGlobalRunningStatus({ showRunningInUI, runningActivityLabel, runningActivityTool, latestMessage, reconnectContent, }: {
@@ -290,6 +322,8 @@ export interface AssistantChatProps {
290
322
  composerToolbarSlot?: React.ReactNode;
291
323
  /** Optional action rendered beside the voice/send controls. */
292
324
  composerExtraActionButton?: React.ReactNode;
325
+ /** Show the framework model picker in the shared composer. Defaults to true. */
326
+ showModelSelector?: boolean;
293
327
  /** Disable the composer for capability-gated surfaces while still showing history. */
294
328
  composerDisabled?: boolean;
295
329
  /** Placeholder to show while the composer is disabled by the host surface. */
@@ -389,6 +423,7 @@ export interface AssistantChatProps {
389
423
  onAlwaysAllow?: (approvalKey: string) => void;
390
424
  };
391
425
  }
426
+ export declare function shouldShowAssistantChatModelSelector(showModelSelector: boolean | undefined): boolean;
392
427
  export declare const CHAT_STORAGE_PREFIX = "agent-chat:";
393
428
  /** Remove persisted chat for a given tabId (or "default"). */
394
429
  export declare function clearChatStorage(tabId?: string): void;