@tangle-network/agent-app 0.43.9 → 0.43.11

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 (38) hide show
  1. package/dist/{DesignCanvas-GUTCY763.js → DesignCanvas-5DJAFDNC.js} +2 -2
  2. package/dist/DesignCanvasEditor-XUJZARSN.js +13 -0
  3. package/dist/{TimelineEditor-SNOAGBV6.js → TimelineEditor-I35SJJAJ.js} +2 -2
  4. package/dist/assistant/index.d.ts +47 -3
  5. package/dist/assistant/index.js +125 -44
  6. package/dist/assistant/index.js.map +1 -1
  7. package/dist/{chunk-LVD37K5V.js → chunk-47C6PJCW.js} +3 -1
  8. package/dist/{chunk-LVD37K5V.js.map → chunk-47C6PJCW.js.map} +1 -1
  9. package/dist/{chunk-6JYDS34Y.js → chunk-4QN75UHX.js} +14 -5
  10. package/dist/chunk-4QN75UHX.js.map +1 -0
  11. package/dist/{chunk-EX3LD5G6.js → chunk-7SUPA2YT.js} +2 -2
  12. package/dist/{chunk-EX3LD5G6.js.map → chunk-7SUPA2YT.js.map} +1 -1
  13. package/dist/{chunk-AFQXKJAE.js → chunk-BN2USWIR.js} +20 -3
  14. package/dist/{chunk-AFQXKJAE.js.map → chunk-BN2USWIR.js.map} +1 -1
  15. package/dist/{chunk-OVUQNKLM.js → chunk-H5FM75MR.js} +8 -7
  16. package/dist/chunk-H5FM75MR.js.map +1 -0
  17. package/dist/{chunk-A5Z53E3A.js → chunk-R4NOKZMD.js} +3 -3
  18. package/dist/{command-stack-CcWi_2bN.d.ts → command-stack-B_-WNfZU.d.ts} +6 -2
  19. package/dist/design-canvas-react/engine.d.ts +3 -2
  20. package/dist/design-canvas-react/engine.js +1 -1
  21. package/dist/design-canvas-react/index.d.ts +4 -4
  22. package/dist/design-canvas-react/index.js +19 -7
  23. package/dist/design-canvas-react/index.js.map +1 -1
  24. package/dist/design-canvas-react/lazy.d.ts +2 -2
  25. package/dist/design-canvas-react/lazy.js +1 -1
  26. package/dist/index.js +1 -1
  27. package/dist/{lazy-2XBVp1_e.d.ts → lazy-C7LiVeFt.d.ts} +1 -1
  28. package/dist/sequences-react/index.js +2 -2
  29. package/dist/theme/index.js +1 -1
  30. package/dist/theme/tokens.css +7 -0
  31. package/package.json +1 -1
  32. package/dist/DesignCanvasEditor-ZO4V7H6A.js +0 -13
  33. package/dist/chunk-6JYDS34Y.js.map +0 -1
  34. package/dist/chunk-OVUQNKLM.js.map +0 -1
  35. /package/dist/{DesignCanvas-GUTCY763.js.map → DesignCanvas-5DJAFDNC.js.map} +0 -0
  36. /package/dist/{DesignCanvasEditor-ZO4V7H6A.js.map → DesignCanvasEditor-XUJZARSN.js.map} +0 -0
  37. /package/dist/{TimelineEditor-SNOAGBV6.js.map → TimelineEditor-I35SJJAJ.js.map} +0 -0
  38. /package/dist/{chunk-A5Z53E3A.js.map → chunk-R4NOKZMD.js.map} +0 -0
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  DesignCanvas,
3
3
  DesignCanvas_default
4
- } from "./chunk-OVUQNKLM.js";
4
+ } from "./chunk-H5FM75MR.js";
5
5
  import "./chunk-XWJXZ6WE.js";
6
6
  import "./chunk-M2EBUDZ7.js";
7
7
  import "./chunk-HFC4BTWJ.js";
@@ -9,4 +9,4 @@ export {
9
9
  DesignCanvas,
10
10
  DesignCanvas_default as default
11
11
  };
12
- //# sourceMappingURL=DesignCanvas-GUTCY763.js.map
12
+ //# sourceMappingURL=DesignCanvas-5DJAFDNC.js.map
@@ -0,0 +1,13 @@
1
+ import {
2
+ DesignCanvasEditor
3
+ } from "./chunk-4QN75UHX.js";
4
+ import "./chunk-H5FM75MR.js";
5
+ import "./chunk-BN2USWIR.js";
6
+ import "./chunk-XWJXZ6WE.js";
7
+ import "./chunk-47C6PJCW.js";
8
+ import "./chunk-M2EBUDZ7.js";
9
+ import "./chunk-HFC4BTWJ.js";
10
+ export {
11
+ DesignCanvasEditor
12
+ };
13
+ //# sourceMappingURL=DesignCanvasEditor-XUJZARSN.js.map
@@ -2,11 +2,11 @@ import {
2
2
  SEQUENCE_MEDIA_DRAG_TYPE,
3
3
  TimelineEditor,
4
4
  TimelineEditor_default
5
- } from "./chunk-EX3LD5G6.js";
5
+ } from "./chunk-7SUPA2YT.js";
6
6
  import "./chunk-ZYBWGSAZ.js";
7
7
  export {
8
8
  SEQUENCE_MEDIA_DRAG_TYPE,
9
9
  TimelineEditor,
10
10
  TimelineEditor_default as default
11
11
  };
12
- //# sourceMappingURL=TimelineEditor-SNOAGBV6.js.map
12
+ //# sourceMappingURL=TimelineEditor-I35SJJAJ.js.map
@@ -82,6 +82,19 @@ interface ConnectionRequirement {
82
82
  * app slug); the card then shows the requirement without a connect link. */
83
83
  connectUrl?: string | null;
84
84
  }
85
+ /**
86
+ * Outcome of a host-driven, in-place connect for a single proposal requirement
87
+ * (see {@link AssistantDockProps.onConnectRequirement}). The host owns the whole
88
+ * connect experience — an OAuth popup, an api-key entry modal, an app install,
89
+ * and any error surfacing — and the assistant stays agnostic to how it happens:
90
+ * the host reports back only whether the requirement is now satisfied, which the
91
+ * card uses to flip that requirement to connected without a reload. `connected:
92
+ * false` (a failed or cancelled connect) leaves the card unchanged so the user
93
+ * can retry.
94
+ */
95
+ interface ConnectRequirementResult {
96
+ connected: boolean;
97
+ }
85
98
  interface ToolProposalEventData {
86
99
  /** Null only if the server has no proposal store wired (tools then unusable). */
87
100
  proposalId: string | null;
@@ -428,6 +441,17 @@ interface UseAssistantChatOptions {
428
441
  * signal the platform used.
429
442
  */
430
443
  onWorkflowMutation?: () => void;
444
+ /**
445
+ * Called when the user activates a proposal requirement's connect affordance.
446
+ * The host runs whatever connect flow it owns — an OAuth popup, an api-key
447
+ * modal, an app install — and resolves whether the requirement is now
448
+ * satisfied; the card then flips that requirement to connected. Host-agnostic:
449
+ * the assistant never learns how the connection is made, so any host (platform,
450
+ * sandbox, intelligence, …) can supply its own. When omitted, the card falls
451
+ * back to navigating the requirement's connect target (see
452
+ * {@link ProposalCardProps.navigate}).
453
+ */
454
+ onConnectRequirement?: (requirement: ConnectionRequirement) => Promise<ConnectRequirementResult>;
431
455
  }
432
456
  interface AssistantChat {
433
457
  state: AssistantState;
@@ -441,6 +465,14 @@ interface AssistantChat {
441
465
  stop: () => void;
442
466
  confirm: (proposal: PendingProposal) => Promise<void>;
443
467
  cancel: (proposal: PendingProposal) => void;
468
+ /** True when the host supplied an in-place connect handler
469
+ * ({@link UseAssistantChatOptions.onConnectRequirement}); the proposal card
470
+ * uses this to offer in-place connect instead of navigating away. */
471
+ canConnectRequirement: boolean;
472
+ /** Run the host's in-place connect for one of a proposal's requirements and,
473
+ * on success, flip that requirement to connected on the card. Resolves (a
474
+ * no-op) when no host handler is set or the connect didn't complete. */
475
+ connectRequirement: (proposal: PendingProposal, requirement: ConnectionRequirement) => Promise<void>;
444
476
  reset: () => void;
445
477
  /** Open an existing thread from history, loading its transcript. */
446
478
  switchThread: (threadId: string) => void;
@@ -518,6 +550,12 @@ interface AssistantDockProps {
518
550
  renderGraph?: (yaml: string) => ReactNode;
519
551
  /** Called after a workflow-mutating tool is confirmed (host re-fetches its list). */
520
552
  onWorkflowMutation?: () => void;
553
+ /** In-place connect handler for a proposal's integration requirements. The host
554
+ * runs its own connect flow (OAuth popup, api-key modal, app install) and
555
+ * resolves whether the requirement is now satisfied; the proposal card then
556
+ * flips it to connected. Host-agnostic — when omitted, the card falls back to
557
+ * navigating the requirement's connect target via `navigate`. */
558
+ onConnectRequirement?: (requirement: ConnectionRequirement) => Promise<ConnectRequirementResult>;
521
559
  /** Markdown renderer for assistant message content (plain text when absent). */
522
560
  renderMarkdown?: (content: string) => ReactNode;
523
561
  /** Per-tool custom detail renderers for expanded tool cards in the transcript. */
@@ -527,7 +565,7 @@ interface AssistantDockProps {
527
565
  * transport, and proposal flow stay owned by the panel. */
528
566
  renderTranscript?: (view: AssistantTranscriptView) => ReactNode;
529
567
  }
530
- declare function AssistantDock({ userId, navigate, balanceUsd, formatMoney, renderGraph, onWorkflowMutation, renderMarkdown, toolRenderers, renderTranscript, }: AssistantDockProps): react.JSX.Element;
568
+ declare function AssistantDock({ userId, navigate, balanceUsd, formatMoney, renderGraph, onWorkflowMutation, onConnectRequirement, renderMarkdown, toolRenderers, renderTranscript, }: AssistantDockProps): react.JSX.Element;
531
569
 
532
570
  interface AssistantPanelProps {
533
571
  chat: AssistantChat;
@@ -608,11 +646,17 @@ interface ProposalCardProps {
608
646
  onCancel: () => void;
609
647
  /** Host navigation for connect targets / the integrations page. */
610
648
  navigate?: (path: string) => void;
649
+ /** In-place connect handler for a requirement. When provided, a requirement's
650
+ * connect affordance calls this (showing a busy state) instead of navigating
651
+ * to `connectUrl`/the integrations page — the host runs its own connect flow
652
+ * and the card flips the requirement to connected on success. Host-agnostic;
653
+ * wired by the panel from {@link UseAssistantChatOptions.onConnectRequirement}. */
654
+ onConnect?: (requirement: ConnectionRequirement) => void | Promise<void>;
611
655
  /** Render the workflow YAML as a node graph (the `./workflows` WorkflowGraph).
612
656
  * When absent, the YAML is shown as text. */
613
657
  renderGraph?: (yaml: string) => ReactNode;
614
658
  }
615
- declare function ProposalCard({ proposal, confirming, onConfirm, onCancel, navigate, renderGraph, }: ProposalCardProps): react.JSX.Element;
659
+ declare function ProposalCard({ proposal, confirming, onConfirm, onCancel, navigate, onConnect, renderGraph, }: ProposalCardProps): react.JSX.Element;
616
660
 
617
661
  interface AssistantLauncher {
618
662
  /** Whether the assistant drawer is open. */
@@ -630,4 +674,4 @@ declare function AssistantLauncherProvider({ children, }: {
630
674
  }): react.JSX.Element;
631
675
  declare function useAssistantLauncher(): AssistantLauncher;
632
676
 
633
- export { type AssistantChat, type AssistantClient, type AssistantClientConfig, AssistantClientInputError, AssistantClientProvider, type AssistantDeliveryMode, AssistantDock, type AssistantDockProps, type AssistantLauncher, AssistantLauncherProvider, type AssistantModelOption, type AssistantModels, type AssistantModelsResult, AssistantPanel, type AssistantPanelProps, type AssistantSendOptions, type AssistantStreamEvent, type AssistantThreadSummary, type AssistantThreads, AssistantTranscript, type AssistantTranscriptProps, type AssistantTranscriptView, type ChatMessage, type ChatRequest, type ChatRole, type ConfirmResult, type ConnectionRequirement, type ConnectionRequirementKind, type DeltaEventData, type DoneEventData, type ErrorEventData, type PendingProposal, ProposalCard, type ProposalCardProps, type ReasoningEventData, type ThreadEventData, type ThreadHistoryResult, type ToolActivityStatus, type ToolCallEventData, type ToolOutcome, type ToolProposalEventData, type ToolResultEventData, type UsageEventData, type UsageInfo, type UseAssistantChatOptions, adaptTranscript, assistantIsThinking, createAssistantClient, useAssistantChat, useAssistantClient, useAssistantLauncher, useAssistantModels, useAssistantThreads };
677
+ export { type AssistantChat, type AssistantClient, type AssistantClientConfig, AssistantClientInputError, AssistantClientProvider, type AssistantDeliveryMode, AssistantDock, type AssistantDockProps, type AssistantLauncher, AssistantLauncherProvider, type AssistantModelOption, type AssistantModels, type AssistantModelsResult, AssistantPanel, type AssistantPanelProps, type AssistantSendOptions, type AssistantStreamEvent, type AssistantThreadSummary, type AssistantThreads, AssistantTranscript, type AssistantTranscriptProps, type AssistantTranscriptView, type ChatMessage, type ChatRequest, type ChatRole, type ConfirmResult, type ConnectRequirementResult, type ConnectionRequirement, type ConnectionRequirementKind, type DeltaEventData, type DoneEventData, type ErrorEventData, type PendingProposal, ProposalCard, type ProposalCardProps, type ReasoningEventData, type ThreadEventData, type ThreadHistoryResult, type ToolActivityStatus, type ToolCallEventData, type ToolOutcome, type ToolProposalEventData, type ToolResultEventData, type UsageEventData, type UsageInfo, type UseAssistantChatOptions, adaptTranscript, assistantIsThinking, createAssistantClient, useAssistantChat, useAssistantClient, useAssistantLauncher, useAssistantModels, useAssistantThreads };
@@ -1029,6 +1029,25 @@ function assistantReducer(state, action) {
1029
1029
  status: pendingProposals.length > 0 ? "awaiting_confirm" : state.status === "awaiting_confirm" ? "idle" : state.status
1030
1030
  };
1031
1031
  }
1032
+ case "requirement_connected": {
1033
+ const kind = action.kind ?? "integration";
1034
+ let changed = false;
1035
+ const pendingProposals = state.pendingProposals.map((p) => {
1036
+ if (p.callId !== action.callId || !p.requirements) return p;
1037
+ let rowChanged = false;
1038
+ const requirements = p.requirements.map((r) => {
1039
+ if (!r.connected && r.provider === action.provider && (r.kind ?? "integration") === kind) {
1040
+ rowChanged = true;
1041
+ return { ...r, connected: true };
1042
+ }
1043
+ return r;
1044
+ });
1045
+ if (!rowChanged) return p;
1046
+ changed = true;
1047
+ return { ...p, requirements };
1048
+ });
1049
+ return changed ? { ...state, pendingProposals } : state;
1050
+ }
1032
1051
  case "stopped":
1033
1052
  return {
1034
1053
  ...state,
@@ -1121,6 +1140,8 @@ function useAssistantChat(userId, options) {
1121
1140
  clientRef.current = client;
1122
1141
  const onWorkflowMutationRef = useRef(options?.onWorkflowMutation);
1123
1142
  onWorkflowMutationRef.current = options?.onWorkflowMutation;
1143
+ const onConnectRequirementRef = useRef(options?.onConnectRequirement);
1144
+ onConnectRequirementRef.current = options?.onConnectRequirement;
1124
1145
  const confirmingRef = useRef(/* @__PURE__ */ new Set());
1125
1146
  const [confirmingIds, setConfirmingIds] = useState(EMPTY_IDS);
1126
1147
  const sendingRef = useRef(false);
@@ -1362,6 +1383,29 @@ function useAssistantChat(userId, options) {
1362
1383
  error: null
1363
1384
  });
1364
1385
  }, []);
1386
+ const connectRequirement = useCallback(
1387
+ async (proposal, requirement) => {
1388
+ const handler = onConnectRequirementRef.current;
1389
+ if (!handler) return;
1390
+ const seq = confirmSeqRef.current;
1391
+ let result;
1392
+ try {
1393
+ result = await handler(requirement);
1394
+ } catch {
1395
+ return;
1396
+ }
1397
+ if (confirmSeqRef.current !== seq) return;
1398
+ if (result?.connected) {
1399
+ dispatch({
1400
+ type: "requirement_connected",
1401
+ callId: proposal.callId,
1402
+ provider: requirement.provider,
1403
+ kind: requirement.kind
1404
+ });
1405
+ }
1406
+ },
1407
+ []
1408
+ );
1365
1409
  const reset = useCallback(() => {
1366
1410
  streamSeqRef.current += 1;
1367
1411
  confirmSeqRef.current += 1;
@@ -1454,6 +1498,8 @@ function useAssistantChat(userId, options) {
1454
1498
  stop,
1455
1499
  confirm,
1456
1500
  cancel,
1501
+ canConnectRequirement: Boolean(options?.onConnectRequirement),
1502
+ connectRequirement,
1457
1503
  reset,
1458
1504
  switchThread,
1459
1505
  restoring
@@ -1599,13 +1645,13 @@ function useAssistantThreads(userId) {
1599
1645
  // src/assistant/AssistantDock.tsx
1600
1646
  import { MessageSquare } from "lucide-react";
1601
1647
  import {
1602
- useEffect as useEffect6,
1603
- useRef as useRef7
1648
+ useEffect as useEffect7,
1649
+ useRef as useRef8
1604
1650
  } from "react";
1605
1651
 
1606
1652
  // src/assistant/AssistantPanel.tsx
1607
1653
  import { History, MessageSquarePlus, Minus, Plus, X } from "lucide-react";
1608
- import { useEffect as useEffect5, useMemo as useMemo3, useRef as useRef5, useState as useState6 } from "react";
1654
+ import { useEffect as useEffect6, useMemo as useMemo3, useRef as useRef6, useState as useState6 } from "react";
1609
1655
 
1610
1656
  // src/assistant/AssistantHistory.tsx
1611
1657
  import { Search, Trash2 } from "lucide-react";
@@ -1725,7 +1771,7 @@ function AssistantHistory({
1725
1771
  }
1726
1772
 
1727
1773
  // src/assistant/ProposalCard.tsx
1728
- import { useState as useState4 } from "react";
1774
+ import { useEffect as useEffect4, useRef as useRef3, useState as useState4 } from "react";
1729
1775
 
1730
1776
  // src/assistant/provider-label.ts
1731
1777
  var PROVIDER_LABELS = {
@@ -1743,13 +1789,14 @@ function providerLabel(provider) {
1743
1789
  }
1744
1790
 
1745
1791
  // src/assistant/ProposalCard.tsx
1746
- import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1792
+ import { Fragment, jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
1747
1793
  function ProposalCard({
1748
1794
  proposal,
1749
1795
  confirming,
1750
1796
  onConfirm,
1751
1797
  onCancel,
1752
1798
  navigate,
1799
+ onConnect,
1753
1800
  renderGraph
1754
1801
  }) {
1755
1802
  const view = describeProposal(proposal);
@@ -1805,7 +1852,8 @@ function ProposalCard({
1805
1852
  RequirementRow,
1806
1853
  {
1807
1854
  req: r,
1808
- navigate
1855
+ navigate,
1856
+ onConnect
1809
1857
  },
1810
1858
  `${r.provider}-${r.kind ?? "integration"}`
1811
1859
  )) }),
@@ -1855,14 +1903,41 @@ function openConnect(target, navigate) {
1855
1903
  }
1856
1904
  function RequirementRow({
1857
1905
  req,
1858
- navigate
1906
+ navigate,
1907
+ onConnect
1859
1908
  }) {
1909
+ const [connecting, setConnecting] = useState4(false);
1910
+ const mountedRef = useRef3(true);
1911
+ useEffect4(() => {
1912
+ mountedRef.current = true;
1913
+ return () => {
1914
+ mountedRef.current = false;
1915
+ };
1916
+ }, []);
1860
1917
  const label = providerLabel(req.provider);
1861
1918
  const isApp = req.kind === "github_app";
1862
1919
  const kindLabel = isApp ? `${label} App` : label;
1863
1920
  const statusText = req.connected ? isApp ? "installed" : "connected" : isApp ? "not installed" : "not connected";
1864
- const canConnect = !req.connected && req.connectUrl !== null;
1921
+ const canConnect = !req.connected && (Boolean(onConnect) || req.connectUrl !== null);
1865
1922
  const target = req.connectUrl ?? "/app/integrations";
1923
+ const handleConnect = () => {
1924
+ if (!onConnect) {
1925
+ openConnect(target, navigate);
1926
+ return;
1927
+ }
1928
+ setConnecting(true);
1929
+ let pending;
1930
+ try {
1931
+ pending = onConnect(req);
1932
+ } catch {
1933
+ if (mountedRef.current) setConnecting(false);
1934
+ return;
1935
+ }
1936
+ void Promise.resolve(pending).catch(() => {
1937
+ }).finally(() => {
1938
+ if (mountedRef.current) setConnecting(false);
1939
+ });
1940
+ };
1866
1941
  return /* @__PURE__ */ jsxs2("li", { className: "flex items-center justify-between gap-2 text-xs", children: [
1867
1942
  /* @__PURE__ */ jsxs2("span", { className: "flex min-w-0 items-center gap-2", children: [
1868
1943
  /* @__PURE__ */ jsx3(ProviderLogo, { provider: req.provider, size: 16 }),
@@ -1884,16 +1959,17 @@ function RequirementRow({
1884
1959
  )
1885
1960
  ] })
1886
1961
  ] }),
1887
- canConnect && /* @__PURE__ */ jsxs2(
1962
+ canConnect && /* @__PURE__ */ jsx3(
1888
1963
  "button",
1889
1964
  {
1890
1965
  type: "button",
1891
- onClick: () => openConnect(target, navigate),
1892
- className: "shrink-0 text-primary",
1893
- children: [
1966
+ onClick: handleConnect,
1967
+ disabled: connecting,
1968
+ className: "shrink-0 text-primary disabled:opacity-50",
1969
+ children: connecting ? isApp ? "Installing\u2026" : "Connecting\u2026" : /* @__PURE__ */ jsxs2(Fragment, { children: [
1894
1970
  isApp ? "Install" : "Connect",
1895
1971
  " \u2192"
1896
- ]
1972
+ ] })
1897
1973
  }
1898
1974
  )
1899
1975
  ] });
@@ -1901,7 +1977,7 @@ function RequirementRow({
1901
1977
 
1902
1978
  // src/assistant/transcript.tsx
1903
1979
  import { useCallback as useCallback3, useMemo as useMemo2 } from "react";
1904
- import { Fragment, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1980
+ import { Fragment as Fragment2, jsx as jsx4, jsxs as jsxs3 } from "react/jsx-runtime";
1905
1981
  function assistantIsThinking(state) {
1906
1982
  if (state.status !== "streaming") return false;
1907
1983
  const streaming = state.streamingId ? state.messages.find((m) => m.id === state.streamingId) : void 0;
@@ -1999,7 +2075,7 @@ function ProposalSlot({
1999
2075
  proposal,
2000
2076
  render
2001
2077
  }) {
2002
- return /* @__PURE__ */ jsx4(Fragment, { children: render(proposal) });
2078
+ return /* @__PURE__ */ jsx4(Fragment2, { children: render(proposal) });
2003
2079
  }
2004
2080
  function AssistantTranscript({
2005
2081
  view,
@@ -2016,7 +2092,7 @@ function AssistantTranscript({
2016
2092
  [renderMarkdown]
2017
2093
  );
2018
2094
  if (messages.length === 0 && !view.isStreaming) {
2019
- return /* @__PURE__ */ jsx4(Fragment, { children: emptyState });
2095
+ return /* @__PURE__ */ jsx4(Fragment2, { children: emptyState });
2020
2096
  }
2021
2097
  return /* @__PURE__ */ jsx4(
2022
2098
  ChatMessages,
@@ -2026,7 +2102,7 @@ function AssistantTranscript({
2026
2102
  agentLabel: "Assistant",
2027
2103
  renderMarkdown: markdown,
2028
2104
  toolRenderers,
2029
- renderEmpty: () => /* @__PURE__ */ jsx4(Fragment, { children: emptyState }),
2105
+ renderEmpty: () => /* @__PURE__ */ jsx4(Fragment2, { children: emptyState }),
2030
2106
  renderExtras: (message) => {
2031
2107
  const proposals = message.id === proposalHostId && view.pendingProposals.length > 0 ? /* @__PURE__ */ jsx4("div", { className: "mt-3 flex flex-col gap-3", children: view.pendingProposals.map((proposal) => /* @__PURE__ */ jsx4(
2032
2108
  ProposalSlot,
@@ -2041,7 +2117,7 @@ function AssistantTranscript({
2041
2117
  " this turn"
2042
2118
  ] }) : null;
2043
2119
  if (!proposals && !cost) return null;
2044
- return /* @__PURE__ */ jsxs3(Fragment, { children: [
2120
+ return /* @__PURE__ */ jsxs3(Fragment2, { children: [
2045
2121
  proposals,
2046
2122
  cost
2047
2123
  ] });
@@ -2051,7 +2127,7 @@ function AssistantTranscript({
2051
2127
  }
2052
2128
 
2053
2129
  // src/assistant/usePanelPrefs.ts
2054
- import { useCallback as useCallback4, useEffect as useEffect4, useRef as useRef3, useState as useState5 } from "react";
2130
+ import { useCallback as useCallback4, useEffect as useEffect5, useRef as useRef4, useState as useState5 } from "react";
2055
2131
  var MIN_PANEL_WIDTH = 360;
2056
2132
  var DEFAULT_PANEL_WIDTH = 448;
2057
2133
  var MAX_PANEL_WIDTH_FRACTION = 0.95;
@@ -2094,8 +2170,8 @@ function clampScale(value) {
2094
2170
  function usePanelWidth() {
2095
2171
  const [width, setWidthState] = useState5(DEFAULT_PANEL_WIDTH);
2096
2172
  const [maxWidth, setMaxWidth] = useState5(() => maxPanelWidth());
2097
- const desiredRef = useRef3(DEFAULT_PANEL_WIDTH);
2098
- useEffect4(() => {
2173
+ const desiredRef = useRef4(DEFAULT_PANEL_WIDTH);
2174
+ useEffect5(() => {
2099
2175
  setMaxWidth(maxPanelWidth());
2100
2176
  const stored = readNumber(WIDTH_KEY);
2101
2177
  if (stored != null) {
@@ -2103,7 +2179,7 @@ function usePanelWidth() {
2103
2179
  setWidthState(clampWidth(stored));
2104
2180
  }
2105
2181
  }, []);
2106
- useEffect4(() => {
2182
+ useEffect5(() => {
2107
2183
  const onResize = () => {
2108
2184
  setMaxWidth(maxPanelWidth());
2109
2185
  setWidthState(clampWidth(desiredRef.current));
@@ -2130,7 +2206,7 @@ function usePanelWidth() {
2130
2206
  }
2131
2207
  function useFontScale() {
2132
2208
  const [scale, setScaleState] = useState5(DEFAULT_FONT_SCALE);
2133
- useEffect4(() => {
2209
+ useEffect5(() => {
2134
2210
  const stored = readNumber(FONT_SCALE_KEY);
2135
2211
  if (stored != null) setScaleState(clampScale(stored));
2136
2212
  }, []);
@@ -2153,7 +2229,7 @@ function useIsDesktop() {
2153
2229
  const [isDesktop, setIsDesktop] = useState5(
2154
2230
  () => typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(min-width: 768px)").matches : true
2155
2231
  );
2156
- useEffect4(() => {
2232
+ useEffect5(() => {
2157
2233
  if (typeof window === "undefined" || typeof window.matchMedia !== "function") {
2158
2234
  return;
2159
2235
  }
@@ -2167,12 +2243,12 @@ function useIsDesktop() {
2167
2243
  }
2168
2244
 
2169
2245
  // src/assistant/use-stick-to-bottom.ts
2170
- import { useCallback as useCallback5, useLayoutEffect, useRef as useRef4 } from "react";
2246
+ import { useCallback as useCallback5, useLayoutEffect, useRef as useRef5 } from "react";
2171
2247
  var STICK_SLACK_PX = 48;
2172
2248
  function useStickToBottom(ref, { enabled, contentSignature, streamingId, threadId }) {
2173
- const stuckRef = useRef4(true);
2174
- const prevStreamingRef = useRef4(streamingId);
2175
- const prevThreadRef = useRef4(threadId);
2249
+ const stuckRef = useRef5(true);
2250
+ const prevStreamingRef = useRef5(streamingId);
2251
+ const prevThreadRef = useRef5(threadId);
2176
2252
  const onScroll = useCallback5(() => {
2177
2253
  if (!enabled) return;
2178
2254
  const el = ref.current;
@@ -2250,24 +2326,24 @@ function AssistantPanel({
2250
2326
  const threads = useAssistantThreads(userId);
2251
2327
  const font = useFontScale();
2252
2328
  const [view, setView] = useState6("chat");
2253
- const historyButtonRef = useRef5(null);
2254
- const logRef = useRef5(null);
2329
+ const historyButtonRef = useRef6(null);
2330
+ const logRef = useRef6(null);
2255
2331
  const pickerModels = useMemo3(
2256
2332
  () => toPickerModels(models, chat.selectedModel),
2257
2333
  [models, chat.selectedModel]
2258
2334
  );
2259
2335
  const pickerValue = chat.selectedModel ?? models.default ?? "";
2260
2336
  const { state } = chat;
2261
- const chatRef = useRef5(chat);
2337
+ const chatRef = useRef6(chat);
2262
2338
  chatRef.current = chat;
2263
- useEffect5(() => {
2339
+ useEffect6(() => {
2264
2340
  if (view !== "history") return;
2265
2341
  const search = logRef.current?.querySelector(
2266
2342
  'input[type="search"]'
2267
2343
  );
2268
2344
  (search ?? logRef.current)?.focus();
2269
2345
  }, [view]);
2270
- useEffect5(() => {
2346
+ useEffect6(() => {
2271
2347
  if (view !== "history") return;
2272
2348
  const onKeyDownCapture = (e) => {
2273
2349
  if (e.key !== "Escape") return;
@@ -2317,6 +2393,7 @@ function AssistantPanel({
2317
2393
  onConfirm: () => chat.confirm(proposal),
2318
2394
  onCancel: () => chat.cancel(proposal),
2319
2395
  navigate,
2396
+ onConnect: chat.canConnectRequirement ? (requirement) => chat.connectRequirement(proposal, requirement) : void 0,
2320
2397
  renderGraph
2321
2398
  }
2322
2399
  );
@@ -2617,7 +2694,7 @@ function useAssistantLauncher() {
2617
2694
  }
2618
2695
 
2619
2696
  // src/assistant/ResizeHandle.tsx
2620
- import { useRef as useRef6 } from "react";
2697
+ import { useRef as useRef7 } from "react";
2621
2698
  import { jsx as jsx7 } from "react/jsx-runtime";
2622
2699
  function ResizeHandle({
2623
2700
  width,
@@ -2626,7 +2703,7 @@ function ResizeHandle({
2626
2703
  onCommit,
2627
2704
  onNudge
2628
2705
  }) {
2629
- const dragRef = useRef6(null);
2706
+ const dragRef = useRef7(null);
2630
2707
  const onPointerDown = (e) => {
2631
2708
  if (e.button !== 0) return;
2632
2709
  e.preventDefault();
@@ -2695,7 +2772,7 @@ function ResizeHandle({
2695
2772
  }
2696
2773
 
2697
2774
  // src/assistant/AssistantDock.tsx
2698
- import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2775
+ import { Fragment as Fragment3, jsx as jsx8, jsxs as jsxs5 } from "react/jsx-runtime";
2699
2776
  function focusableWithin(container) {
2700
2777
  const selector = 'a[href], button:not([disabled]), textarea:not([disabled]), input:not([disabled]), select:not([disabled]), [tabindex]:not([tabindex="-1"])';
2701
2778
  return Array.from(container.querySelectorAll(selector)).filter(
@@ -2709,19 +2786,23 @@ function AssistantDock({
2709
2786
  formatMoney,
2710
2787
  renderGraph,
2711
2788
  onWorkflowMutation,
2789
+ onConnectRequirement,
2712
2790
  renderMarkdown,
2713
2791
  toolRenderers,
2714
2792
  renderTranscript
2715
2793
  }) {
2716
2794
  const { open, openAssistant, closeAssistant } = useAssistantLauncher();
2717
- const chat = useAssistantChat(userId, { onWorkflowMutation });
2795
+ const chat = useAssistantChat(userId, {
2796
+ onWorkflowMutation,
2797
+ onConnectRequirement
2798
+ });
2718
2799
  const isDesktop = useIsDesktop();
2719
2800
  const { width, maxWidth, setWidth, previewWidth, nudgeWidth } = usePanelWidth();
2720
- const launcherRef = useRef7(null);
2721
- const dialogRef = useRef7(null);
2722
- const returnFocusRef = useRef7(null);
2723
- const wasOpenRef = useRef7(false);
2724
- useEffect6(() => {
2801
+ const launcherRef = useRef8(null);
2802
+ const dialogRef = useRef8(null);
2803
+ const returnFocusRef = useRef8(null);
2804
+ const wasOpenRef = useRef8(false);
2805
+ useEffect7(() => {
2725
2806
  if (!open) return;
2726
2807
  const onKeyDown = (e) => {
2727
2808
  if (e.key === "Escape") closeAssistant();
@@ -2729,7 +2810,7 @@ function AssistantDock({
2729
2810
  document.addEventListener("keydown", onKeyDown);
2730
2811
  return () => document.removeEventListener("keydown", onKeyDown);
2731
2812
  }, [open, closeAssistant]);
2732
- useEffect6(() => {
2813
+ useEffect7(() => {
2733
2814
  if (open) {
2734
2815
  if (!wasOpenRef.current && !returnFocusRef.current) {
2735
2816
  returnFocusRef.current = document.activeElement;
@@ -2785,7 +2866,7 @@ function AssistantDock({
2785
2866
  first.focus();
2786
2867
  }
2787
2868
  };
2788
- return /* @__PURE__ */ jsxs5(Fragment2, { children: [
2869
+ return /* @__PURE__ */ jsxs5(Fragment3, { children: [
2789
2870
  /* @__PURE__ */ jsx8(
2790
2871
  "div",
2791
2872
  {