@ai-matrx/chat 0.4.22 → 0.4.24

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 (54) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/dist/agents/components/context-items/bodies/UnregisteredBody.d.ts +6 -3
  3. package/dist/agents/components/context-items/bodies/UnregisteredBody.js +3 -9
  4. package/dist/agents/components/inputs/resources/attach-resource.js +1 -0
  5. package/dist/agents/components/inputs/smart-input/SmartAgentInput.js +16 -1
  6. package/dist/agents/components/inputs/smart-input/composer/ComposerMenu.js +3 -2
  7. package/dist/agents/components/inputs/smart-input/composer/ComposerPlusMenu.js +41 -35
  8. package/dist/agents/components/messages-display/user/AgentUserMessage.js +3 -1
  9. package/dist/agents/components/shared/AgentConversationColumn.d.ts +10 -1
  10. package/dist/agents/components/shared/AgentConversationColumn.js +26 -2
  11. package/dist/agents/redux/execution-system/messages/messages.slice.js +6 -1
  12. package/dist/agents/redux/execution-system/thunks/await-launching-conversation.d.ts +16 -0
  13. package/dist/agents/redux/execution-system/thunks/await-launching-conversation.js +16 -0
  14. package/dist/agents/redux/execution-system/thunks/execute-instance.thunk.js +34 -1
  15. package/dist/agents/redux/execution-system/thunks/process-stream.js +11 -0
  16. package/dist/agents/redux/execution-system/thunks/smart-execute.thunk.js +10 -0
  17. package/dist/host/app-data-slots.d.ts +0 -1
  18. package/dist/host/app-data-slots.js +25 -5
  19. package/dist/host/bare-host-chrome.js +4 -0
  20. package/dist/host/contract.d.ts +1 -1
  21. package/dist/host/contract.js +2 -1
  22. package/dist/host/conversation-hooks-react.d.ts +2 -0
  23. package/dist/host/conversation-hooks-react.js +12 -0
  24. package/dist/host/conversation-hooks.d.ts +79 -0
  25. package/dist/host/conversation-hooks.js +91 -0
  26. package/dist/host/defaults/bare-block-dispatch.d.ts +6 -0
  27. package/dist/host/defaults/bare-block-dispatch.js +60 -0
  28. package/dist/host/defaults/files-host.d.ts +26 -0
  29. package/dist/host/defaults/files-host.js +212 -0
  30. package/dist/host/defaults/resource-picker-menu.d.ts +14 -0
  31. package/dist/host/defaults/resource-picker-menu.js +117 -0
  32. package/dist/host/defaults/setting-control-input.d.ts +11 -0
  33. package/dist/host/defaults/setting-control-input.js +91 -0
  34. package/dist/host/index.d.ts +1 -0
  35. package/dist/host/index.js +1 -0
  36. package/dist/host/react.d.ts +1 -0
  37. package/dist/host/react.js +2 -0
  38. package/dist/host/ui-slots.d.ts +25 -1
  39. package/dist/host/ui-slots.js +59 -15
  40. package/dist/host/window-openers.d.ts +2 -0
  41. package/dist/host/window-openers.js +4 -0
  42. package/dist/react.cjs +1 -1
  43. package/dist/react.cjs.map +1 -1
  44. package/dist/react.js +1 -1
  45. package/dist/react.js.map +1 -1
  46. package/dist/tool-call-visualization/registry/registry.js +4 -4
  47. package/dist/ui/chat-panel/ChatPanel.d.ts +50 -0
  48. package/dist/ui/chat-panel/ChatPanel.js +175 -0
  49. package/dist/ui/chat-panel/drag.d.ts +87 -0
  50. package/dist/ui/chat-panel/drag.js +194 -0
  51. package/dist/window-panels/windows/agents/AgentRunWindow.js +17 -0
  52. package/dist/window-panels/windows/agents/agentRunWindowAddress.d.ts +19 -0
  53. package/dist/window-panels/windows/agents/agentRunWindowAddress.js +11 -1
  54. package/package.json +6 -6
@@ -0,0 +1,91 @@
1
+ "use client";
2
+ import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useState } from "react";
4
+ import { Input, Switch, Textarea } from "@ai-matrx/design-system";
5
+ const FIELD = "h-8 w-full text-sm";
6
+ function JsonField({ id, value, disabled, onChange }) {
7
+ const text = value === void 0 || value === null ? "" : JSON.stringify(value, null, 2);
8
+ const [draft, setDraft] = useState(text);
9
+ const [invalid, setInvalid] = useState(false);
10
+ useEffect(() => setDraft(text), [text]);
11
+ return /* @__PURE__ */ jsx(
12
+ Textarea,
13
+ {
14
+ id,
15
+ value: draft,
16
+ disabled,
17
+ rows: 3,
18
+ "aria-invalid": invalid || void 0,
19
+ className: "w-full font-mono text-xs",
20
+ onChange: (event) => setDraft(event.target.value),
21
+ onBlur: () => {
22
+ if (draft.trim() === "") return onChange(void 0);
23
+ try {
24
+ onChange(JSON.parse(draft));
25
+ setInvalid(false);
26
+ } catch {
27
+ setInvalid(true);
28
+ }
29
+ }
30
+ }
31
+ );
32
+ }
33
+ function DefaultSettingControlInput({ settingKey, control, value, onChange, disabled, id }) {
34
+ const fieldId = id ?? `setting-${settingKey}`;
35
+ switch (control.type) {
36
+ case "boolean":
37
+ return /* @__PURE__ */ jsx(Switch, { id: fieldId, checked: value === true, disabled, onCheckedChange: (checked) => onChange(checked) });
38
+ case "enum":
39
+ return /* @__PURE__ */ jsxs(
40
+ "select",
41
+ {
42
+ id: fieldId,
43
+ className: `${FIELD} rounded-md border border-input bg-background px-2`,
44
+ value: typeof value === "string" ? value : "",
45
+ disabled,
46
+ onChange: (event) => onChange(event.target.value === "" ? void 0 : event.target.value),
47
+ children: [
48
+ /* @__PURE__ */ jsx("option", { value: "", children: "Default" }),
49
+ (control.enum ?? []).map((option) => /* @__PURE__ */ jsx("option", { value: option, children: option }, option))
50
+ ]
51
+ }
52
+ );
53
+ case "number":
54
+ case "integer":
55
+ return /* @__PURE__ */ jsx(
56
+ Input,
57
+ {
58
+ id: fieldId,
59
+ type: "number",
60
+ className: FIELD,
61
+ value: typeof value === "number" ? String(value) : "",
62
+ min: control.min,
63
+ max: control.max,
64
+ step: control.type === "integer" ? 1 : "any",
65
+ disabled,
66
+ onChange: (event) => {
67
+ const raw = event.target.value;
68
+ if (raw === "") return onChange(void 0);
69
+ const parsed = control.type === "integer" ? Number.parseInt(raw, 10) : Number(raw);
70
+ if (Number.isFinite(parsed)) onChange(parsed);
71
+ }
72
+ }
73
+ );
74
+ case "string":
75
+ return /* @__PURE__ */ jsx(
76
+ Input,
77
+ {
78
+ id: fieldId,
79
+ className: FIELD,
80
+ value: typeof value === "string" ? value : value === void 0 || value === null ? "" : String(value),
81
+ disabled,
82
+ onChange: (event) => onChange(event.target.value === "" ? void 0 : event.target.value)
83
+ }
84
+ );
85
+ default:
86
+ return /* @__PURE__ */ jsx(JsonField, { id: fieldId, value, disabled, onChange });
87
+ }
88
+ }
89
+ export {
90
+ DefaultSettingControlInput
91
+ };
@@ -24,4 +24,5 @@ export { createClient, getClaimsUser, schedulerDb, supabase, type ChatClaimsUser
24
24
  export type { ChatDatabase } from "./db-types.js";
25
25
  export { ChatNoDatabaseError, NO_DATABASE_CODE_PREFIX, createNoDatabaseStandIn, isChatNoDatabaseError, isNoDatabase, } from "./no-database.js";
26
26
  export * from "./source.js";
27
+ export * from "./conversation-hooks.js";
27
28
  export * from "../agents/routing/confidential-routing.js";
@@ -55,6 +55,7 @@ import {
55
55
  isNoDatabase
56
56
  } from "./no-database.js";
57
57
  export * from "./source.js";
58
+ export * from "./conversation-hooks.js";
58
59
  export * from "../agents/routing/confidential-routing.js";
59
60
  export {
60
61
  CHAT_ACTIVE_ORG_STORAGE_KEY,
@@ -31,3 +31,4 @@ export declare function useMaybeChatHost(): ResolvedChatHost | null;
31
31
  /** The host from the nearest <ChatProvider>. Throws the named, remedied error outside one. */
32
32
  export declare function useChatHost(): ResolvedChatHost;
33
33
  export { Link, usePathname, useRouter, useSearchParams } from "./navigation.js";
34
+ export { useConversationHeld } from "./conversation-hooks-react.js";
@@ -65,10 +65,12 @@ function useChatHost() {
65
65
  return host;
66
66
  }
67
67
  import { Link, usePathname, useRouter, useSearchParams } from "./navigation.js";
68
+ import { useConversationHeld } from "./conversation-hooks-react.js";
68
69
  export {
69
70
  ChatProvider,
70
71
  Link,
71
72
  useChatHost,
73
+ useConversationHeld,
72
74
  useMaybeChatHost,
73
75
  usePathname,
74
76
  useRouter,
@@ -1,4 +1,4 @@
1
- import { type ComponentType, type ChangeEvent, type ReactNode } from "react";
1
+ import { Component, type ComponentType, type ChangeEvent, type ReactNode } from "react";
2
2
  import type { EditableContextMenuProps, NonEditableContextMenuProps } from "../context-menu/types.js";
3
3
  /** The host context menu's props (its registration is typed against them). */
4
4
  export type { EditableContextMenuProps, NonEditableContextMenuProps };
@@ -419,6 +419,28 @@ export interface ChatUiSlots {
419
419
  export declare function registerChatUi(next: Partial<ChatUiSlots>): void;
420
420
  /** Test seam: forget every registration. */
421
421
  export declare function resetChatUiForTests(): void;
422
+ /** True when the host registered `name` (a door that only a host implementation can open shows only then). */
423
+ export declare function isHostSlotRegistered(name: keyof ChatUiSlots): boolean;
424
+ /**
425
+ * EVERY SLOT DEGRADES, NEVER CRASHES (P29a finding 1). A host panel that throws while rendering
426
+ * (a hook slot it needs is missing, its own bug) draws nothing in its place; the failure is
427
+ * reported once through the diagnostics port. The page around it keeps working.
428
+ */
429
+ export declare class SlotBoundary extends Component<{
430
+ name: string;
431
+ children?: ReactNode;
432
+ }, {
433
+ failed: boolean;
434
+ }> {
435
+ state: {
436
+ failed: boolean;
437
+ };
438
+ static getDerivedStateFromError(): {
439
+ failed: boolean;
440
+ };
441
+ componentDidCatch(error: unknown): void;
442
+ render(): ReactNode;
443
+ }
422
444
  /**
423
445
  * A named slot with the caller's own stand-in (for a package default richer than one line,
424
446
  * e.g. a context-item body falling back to `GenericBody`). Same contract as the wrappers above:
@@ -498,6 +520,7 @@ export declare const WindowPanel: AnyComponent;
498
520
  /** A bare host draws a plain full-screen tabbed sheet. */
499
521
  export declare const FullScreenOverlay: AnyComponent;
500
522
  export declare const ResourcePickerWindow: AnyComponent;
523
+ /** A bare host gets the package's own Files + Link picker (`defaults/resource-picker-menu`); the app registers its full one. */
501
524
  export declare const ResourcePickerMenu: SlotComponent<ResourcePickerMenuProps>;
502
525
  export declare const FilesResourcePicker: SlotComponent<FilesPickerProps>;
503
526
  export declare const NotePickerPopover: SlotComponent<NotePickerProps>;
@@ -736,6 +759,7 @@ export declare const CreatorRunPanel: SlotComponent<{
736
759
  tabs?: string[];
737
760
  }>;
738
761
  export declare const AgentSettingsCore: AnyComponent;
762
+ /** A bare host gets the package's own per-type setting control (`defaults/setting-control-input`). */
739
763
  export declare const SettingControlInput: AnyComponent;
740
764
  export declare const InputCapabilitiesEditor: AnyComponent;
741
765
  export declare const CustomDataBindingSummary: AnyComponent;
@@ -1,12 +1,22 @@
1
1
  "use client";
2
2
  import { defaultResourcePickerItems } from "../agents/resources/default-picker-items.js";
3
3
  import { isRfc9562Uuid } from "@ai-matrx/kit/uuid";
4
- import { createElement, Fragment, useRef } from "react";
4
+ import { Component, createElement, Fragment, useRef } from "react";
5
5
  import { formatCost, usdToPoints } from "@ai-matrx/kit/format";
6
+ import { announceOnce } from "./errors.js";
6
7
  import { reportUnregisteredHostSlot as reportUnregistered } from "./diagnostics.js";
7
8
  import { DefaultWebpageSnapshotView } from "./defaults/webpage-snapshot-view.js";
8
9
  import { DefaultWorkspaceGate } from "./defaults/workspace-gate.js";
9
10
  import { DefaultFullScreenOverlay, DefaultWindowPanel } from "./defaults/window-panel.js";
11
+ import { DefaultSettingControlInput } from "./defaults/setting-control-input.js";
12
+ import { DefaultResourcePickerMenu } from "./defaults/resource-picker-menu.js";
13
+ import { captureReactRenderError } from "./diagnostics.js";
14
+ import { ConfirmDialog as PackageConfirmDialog } from "@ai-matrx/design-system";
15
+ import {
16
+ ClampedNumberInput as PackageClampedNumberInput,
17
+ LightSwitchToggle as PackageLightSwitchToggle,
18
+ NumberStepper as PackageNumberStepper
19
+ } from "@ai-matrx/design-system/controls";
10
20
  const slots = {};
11
21
  function registerChatUi(next) {
12
22
  Object.assign(slots, next);
@@ -14,26 +24,45 @@ function registerChatUi(next) {
14
24
  function resetChatUiForTests() {
15
25
  for (const key of Object.keys(slots)) delete slots[key];
16
26
  }
27
+ function isHostSlotRegistered(name) {
28
+ return slots[name] !== void 0;
29
+ }
30
+ class SlotBoundary extends Component {
31
+ state = { failed: false };
32
+ static getDerivedStateFromError() {
33
+ return { failed: true };
34
+ }
35
+ componentDidCatch(error) {
36
+ if (announceOnce(`chat-host-slot-failed:${this.props.name}`, `The chat slot "${this.props.name}" failed to render, so it is left out.`)) {
37
+ captureReactRenderError(error, { boundary: `ChatUi(${this.props.name})` });
38
+ }
39
+ }
40
+ render() {
41
+ return this.state.failed ? null : this.props.children ?? null;
42
+ }
43
+ }
17
44
  function slotComponent(name, Fallback) {
18
45
  const Wrapper = (props) => {
19
46
  const Impl = slots[name];
20
47
  if (!Impl) {
21
48
  const absent = !Fallback || Fallback.optionalAbsent;
22
49
  reportUnregistered(name, absent ? "it renders nothing here" : "a plain stand-in is drawn");
23
- return Fallback ? createElement(Fallback, props) : null;
50
+ return Fallback ? createElement(SlotBoundary, { name }, createElement(Fallback, props)) : null;
24
51
  }
25
- return createElement(Impl, props);
52
+ return createElement(SlotBoundary, { name }, createElement(Impl, props));
26
53
  };
27
54
  Wrapper.displayName = `ChatUi(${name})`;
28
55
  return Wrapper;
29
56
  }
57
+ function withPackageDefault(Component2) {
58
+ const PackageDefault = (props) => createElement(Component2, props);
59
+ PackageDefault.displayName = `PackageDefault(${Component2.displayName ?? Component2.name ?? "component"})`;
60
+ return PackageDefault;
61
+ }
30
62
  function unregisteredWidget(name) {
31
- const UnregisteredWidget = () => createElement(
32
- "span",
33
- { className: "text-[11px] text-muted-foreground", "data-chat-slot-fallback": name },
34
- `${name} is not set up here`
35
- );
63
+ const UnregisteredWidget = ({ children }) => createElement(Fragment, null, children ?? null);
36
64
  UnregisteredWidget.displayName = `UnregisteredWidget(${name})`;
65
+ UnregisteredWidget.optionalAbsent = true;
37
66
  return UnregisteredWidget;
38
67
  }
39
68
  function optionalWidget(name) {
@@ -241,7 +270,7 @@ const SystemInstructionModal = slotComponent("SystemInstructionModal", optionalW
241
270
  const WindowPanel = slotComponent("WindowPanel", DefaultWindowPanel);
242
271
  const FullScreenOverlay = slotComponent("FullScreenOverlay", DefaultFullScreenOverlay);
243
272
  const ResourcePickerWindow = slotComponent("ResourcePickerWindow", optionalWidget("ResourcePickerWindow"));
244
- const ResourcePickerMenu = slotComponent("ResourcePickerMenu", optionalWidget("ResourcePickerMenu"));
273
+ const ResourcePickerMenu = slotComponent("ResourcePickerMenu", (props) => createElement(DefaultResourcePickerMenu, props));
245
274
  const FilesResourcePicker = slotComponent("FilesResourcePicker", optionalWidget("FilesResourcePicker"));
246
275
  const NotePickerPopover = slotComponent("NotePickerPopover", optionalWidget("NotePickerPopover"));
247
276
  const SmartInputMessageTemplatePicker = slotComponent(
@@ -310,7 +339,7 @@ const StaleDataNotice = slotComponent("StaleDataNotice", PlainStaleDataNotice);
310
339
  const WorkspaceGate = slotComponent("WorkspaceGate", DefaultWorkspaceGate);
311
340
  const OrganizationContextNotice = slotComponent("OrganizationContextNotice", unregisteredWidget("OrganizationContextNotice"));
312
341
  const JsonInspector = slotComponent("JsonInspector", unregisteredWidget("JsonInspector"));
313
- const ConfirmDialog = slotComponent("ConfirmDialog", unregisteredWidget("ConfirmDialog"));
342
+ const ConfirmDialog = slotComponent("ConfirmDialog", withPackageDefault(PackageConfirmDialog));
314
343
  import { ModelListDropdown } from "@ai-matrx/agents/models/react";
315
344
  const TextWithDoors = slotComponent("TextWithDoors", unregisteredWidget("TextWithDoors"));
316
345
  const EntityDoorControls = slotComponent("EntityDoorControls", unregisteredWidget("EntityDoorControls"));
@@ -319,10 +348,10 @@ const KindValueFrontDoor = slotComponent("KindValueFrontDoor", unregisteredWidge
319
348
  const KindDataGate = slotComponent("KindDataGate", unregisteredWidget("KindDataGate"));
320
349
  const ServerNotes = slotComponent("ServerNotes", unregisteredWidget("ServerNotes"));
321
350
  const OptionCombobox = slotComponent("OptionCombobox", unregisteredWidget("OptionCombobox"));
322
- const NumberStepper = slotComponent("NumberStepper", unregisteredWidget("NumberStepper"));
351
+ const NumberStepper = slotComponent("NumberStepper", withPackageDefault(PackageNumberStepper));
323
352
  const MatrxFloatingFrame = slotComponent("MatrxFloatingFrame", unregisteredWidget("MatrxFloatingFrame"));
324
353
  const ItemMenu = slotComponent("ItemMenu", unregisteredWidget("ItemMenu"));
325
- const ClampedNumberInput = slotComponent("ClampedNumberInput", unregisteredWidget("ClampedNumberInput"));
354
+ const ClampedNumberInput = slotComponent("ClampedNumberInput", withPackageDefault(PackageClampedNumberInput));
326
355
  const AspectRatioSelect = slotComponent("AspectRatioSelect", unregisteredWidget("AspectRatioSelect"));
327
356
  const AnswerTextPreview = slotComponent("AnswerTextPreview", unregisteredWidget("AnswerTextPreview"));
328
357
  const AccessGate = slotComponent("AccessGate", unregisteredWidget("AccessGate"));
@@ -343,7 +372,7 @@ const VoiceTextarea = slotComponent("VoiceTextarea", (props) => {
343
372
  const FloatingSheet = slotComponent("FloatingSheet", unregisteredWidget("FloatingSheet"));
344
373
  const AppLink = slotComponent("AppLink", ({ href, children, className, ...rest }) => createElement("a", { href, className, ...rest }, children));
345
374
  const IconButton = slotComponent("IconButton", unregisteredWidget("IconButton"));
346
- const LightSwitchToggle = slotComponent("LightSwitchToggle", unregisteredWidget("LightSwitchToggle"));
375
+ const LightSwitchToggle = slotComponent("LightSwitchToggle", withPackageDefault(PackageLightSwitchToggle));
347
376
  const CitationChip = slotComponent("CitationChip", unregisteredWidget("CitationChip"));
348
377
  const MatrxEnvelopeBlock = slotComponent("MatrxEnvelopeBlock", unregisteredWidget("MatrxEnvelopeBlock"));
349
378
  const ErrorBoundaryWithCapture = slotComponent("ErrorBoundaryWithCapture", ({ children }) => children ?? null);
@@ -377,7 +406,20 @@ const useSkills = slotFn("useSkills");
377
406
  const useAutoLabel = slotFn("useAutoLabel", () => void 0);
378
407
  const generateLabelFromContent = slotFn("generateLabelFromContent");
379
408
  const usePickListForSelection = slotFn("usePickListForSelection");
380
- const useGitHubConnection = slotFn("useGitHubConnection");
409
+ const NO_GITHUB = { connection: null, repositories: NONE, account: null, installations: NONE, syncedRepositoryCount: 0, lastSyncedAt: null };
410
+ const noGitHubAction = async () => void 0;
411
+ const useGitHubConnection = slotFn("useGitHubConnection", () => ({
412
+ inventory: NO_GITHUB,
413
+ loading: false,
414
+ busy: false,
415
+ error: null,
416
+ readError: null,
417
+ reload: noGitHubAction,
418
+ connect: noGitHubAction,
419
+ install: noGitHubAction,
420
+ sync: noGitHubAction,
421
+ disconnect: noGitHubAction
422
+ }));
381
423
  const useOutputFeedback = slotFn("useOutputFeedback");
382
424
  const saveOutputFeedback = slotFn("saveOutputFeedback");
383
425
  const precedingQuestion = slotFn("precedingQuestion");
@@ -451,7 +493,7 @@ const AgentSaveTapButton = slotComponent("AgentSaveTapButton");
451
493
  const AgentPeekDuplicateButton = slotComponent("AgentPeekDuplicateButton");
452
494
  const CreatorRunPanel = slotComponent("CreatorRunPanel");
453
495
  const AgentSettingsCore = slotComponent("AgentSettingsCore", unregisteredWidget("AgentSettingsCore"));
454
- const SettingControlInput = slotComponent("SettingControlInput", unregisteredWidget("SettingControlInput"));
496
+ const SettingControlInput = slotComponent("SettingControlInput", (props) => createElement(DefaultSettingControlInput, props));
455
497
  const InputCapabilitiesEditor = slotComponent("InputCapabilitiesEditor", unregisteredWidget("InputCapabilitiesEditor"));
456
498
  const CustomDataBindingSummary = slotComponent("CustomDataBindingSummary", unregisteredWidget("CustomDataBindingSummary"));
457
499
  const CustomDataBindingPreview = slotComponent("CustomDataBindingPreview", unregisteredWidget("CustomDataBindingPreview"));
@@ -571,6 +613,7 @@ export {
571
613
  ShareButton,
572
614
  ShareModal,
573
615
  SimpleTerminal,
616
+ SlotBoundary,
574
617
  SmartInputMessageTemplatePicker,
575
618
  SpeakerButton,
576
619
  StaleDataNotice,
@@ -629,6 +672,7 @@ export {
629
672
  humanLines,
630
673
  invalidateCanvasItemCache,
631
674
  invalidateMandateCatalogueCache,
675
+ isHostSlotRegistered,
632
676
  isSkillStreamEvent,
633
677
  isUuidValue,
634
678
  isWarRoomThreadAgentSurface,
@@ -326,6 +326,8 @@ export interface ChatWindowOpeners {
326
326
  export type ChatWindowOpenerName = keyof ChatWindowOpeners;
327
327
  /** What a host that registers no openers gets — every one announces itself. */
328
328
  export declare const UNHOSTED_WINDOW_OPENERS: ChatWindowOpeners;
329
+ /** True when the host can actually open this window (a bare host has no window host: draw the surface inline instead). */
330
+ export declare function useHasChatWindowOpener(name: ChatWindowOpenerName): boolean;
329
331
  export declare function useOpenAgentAdminFindUsagesWindow(): (opts?: OpenAgentAdminFindUsagesWindowOptions) => ChatWindowHandle;
330
332
  export declare function useOpenAgentShortcutQuickCreateWindow(): (opts?: OpenAgentShortcutQuickCreateWindowOptions) => ChatWindowHandle;
331
333
  export declare function useOpenAgentContentWindow(): (opts?: OpenAgentContentWindowOptions) => ChatWindowHandle;
@@ -61,6 +61,9 @@ const UNHOSTED_WINDOW_OPENERS = {
61
61
  openWorkingDocumentPanel: unhosted("openWorkingDocumentPanel"),
62
62
  openWorkingDocumentWindow: unhosted("openWorkingDocumentWindow")
63
63
  };
64
+ function useHasChatWindowOpener(name) {
65
+ return Boolean(useChatWindows().openers?.[name]);
66
+ }
64
67
  function useOpener(name) {
65
68
  return useChatWindows().openers?.[name] ?? UNHOSTED_WINDOW_OPENERS[name];
66
69
  }
@@ -236,6 +239,7 @@ function useOpenWorkingDocumentWindow() {
236
239
  export {
237
240
  UNHOSTED_WINDOW_OPENERS,
238
241
  useFloatingLiveRun,
242
+ useHasChatWindowOpener,
239
243
  useOpenAgentAdminFindUsagesWindow,
240
244
  useOpenAgentContentWindow,
241
245
  useOpenAgentConvertSystemWindow,
package/dist/react.cjs CHANGED
@@ -3975,7 +3975,7 @@ function joinHeaderClass(...parts) {
3975
3975
  return parts.filter((part) => part !== void 0 && part !== "").join(" ");
3976
3976
  }
3977
3977
 
3978
- // src/compat/react/shells/drag.ts
3978
+ // src/ui/chat-panel/drag.ts
3979
3979
  var import_react18 = require("react");
3980
3980
  var KEYBOARD_STEP_PX = 24;
3981
3981
  function useResizableWidth(options) {