@circuitwall/jarela 0.8.0 → 0.8.1

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 (98) hide show
  1. package/.next/standalone/.next/BUILD_ID +1 -1
  2. package/.next/standalone/.next/app-path-routes-manifest.json +1 -1
  3. package/.next/standalone/.next/build-manifest.json +2 -2
  4. package/.next/standalone/.next/prerender-manifest.json +3 -3
  5. package/.next/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +1 -1
  6. package/.next/standalone/.next/server/app/_global-error.html +1 -1
  7. package/.next/standalone/.next/server/app/_global-error.rsc +1 -1
  8. package/.next/standalone/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  9. package/.next/standalone/.next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  10. package/.next/standalone/.next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  11. package/.next/standalone/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  12. package/.next/standalone/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  13. package/.next/standalone/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  14. package/.next/standalone/.next/server/app/_not-found/page.js +1 -537
  15. package/.next/standalone/.next/server/app/_not-found/page.js.map +1 -1
  16. package/.next/standalone/.next/server/app/_not-found/page.js.nft.json +1 -1
  17. package/.next/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  18. package/.next/standalone/.next/server/app/_not-found.html +23 -2
  19. package/.next/standalone/.next/server/app/_not-found.rsc +47 -18
  20. package/.next/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +47 -18
  21. package/.next/standalone/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  22. package/.next/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +36 -7
  23. package/.next/standalone/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  24. package/.next/standalone/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  25. package/.next/standalone/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  26. package/.next/standalone/.next/server/app/index.html +23 -2
  27. package/.next/standalone/.next/server/app/index.rsc +46 -17
  28. package/.next/standalone/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  29. package/.next/standalone/.next/server/app/index.segments/_full.segment.rsc +46 -17
  30. package/.next/standalone/.next/server/app/index.segments/_head.segment.rsc +1 -1
  31. package/.next/standalone/.next/server/app/index.segments/_index.segment.rsc +36 -7
  32. package/.next/standalone/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  33. package/.next/standalone/.next/server/app/page.js +79690 -79580
  34. package/.next/standalone/.next/server/app/page.js.map +1 -1
  35. package/.next/standalone/.next/server/app/page.js.nft.json +1 -1
  36. package/.next/standalone/.next/server/app/page_client-reference-manifest.js +1 -1
  37. package/.next/standalone/.next/server/app/setup/page.js +1 -1
  38. package/.next/standalone/.next/server/app/setup/page.js.nft.json +1 -1
  39. package/.next/standalone/.next/server/app/setup/page_client-reference-manifest.js +1 -1
  40. package/.next/standalone/.next/server/app/setup.html +1 -1
  41. package/.next/standalone/.next/server/app/setup.rsc +48 -19
  42. package/.next/standalone/.next/server/app/setup.segments/_full.segment.rsc +48 -19
  43. package/.next/standalone/.next/server/app/setup.segments/_head.segment.rsc +1 -1
  44. package/.next/standalone/.next/server/app/setup.segments/_index.segment.rsc +36 -7
  45. package/.next/standalone/.next/server/app/setup.segments/_tree.segment.rsc +2 -2
  46. package/.next/standalone/.next/server/app/setup.segments/setup/__PAGE__.segment.rsc +1 -1
  47. package/.next/standalone/.next/server/app/setup.segments/setup.segment.rsc +1 -1
  48. package/.next/standalone/.next/server/app-paths-manifest.json +1 -1
  49. package/.next/standalone/.next/server/chunks/4045.js +611 -0
  50. package/.next/standalone/.next/server/chunks/4045.js.map +1 -0
  51. package/.next/standalone/.next/server/chunks/5432.js +5 -2
  52. package/.next/standalone/.next/server/chunks/5432.js.map +1 -1
  53. package/.next/standalone/.next/server/chunks/{5745.js → 6765.js} +9 -551
  54. package/.next/standalone/.next/server/chunks/6765.js.map +1 -0
  55. package/.next/standalone/.next/server/chunks/7885.js +5 -2
  56. package/.next/standalone/.next/server/chunks/7885.js.map +1 -1
  57. package/.next/standalone/.next/server/middleware-build-manifest.js +2 -2
  58. package/.next/standalone/.next/server/pages/404.html +23 -2
  59. package/.next/standalone/.next/server/pages/500.html +1 -1
  60. package/.next/standalone/.next/server/server-reference-manifest.json +1 -1
  61. package/.next/standalone/.next/static/chunks/{3741-81560b0aef166f49.js → 3741-b70e2d1a48a087d6.js} +16 -9
  62. package/.next/standalone/.next/static/chunks/3741-b70e2d1a48a087d6.js.map +1 -0
  63. package/.next/standalone/.next/static/chunks/app/{layout-31009df0f341ccf5.js → layout-84c6f211a7a1ca36.js} +38 -5
  64. package/.next/standalone/.next/static/chunks/app/layout-84c6f211a7a1ca36.js.map +1 -0
  65. package/.next/standalone/.next/static/chunks/app/{page-108f526cb6e48b7b.js → page-31e4d0ad258be21a.js} +258 -122
  66. package/.next/standalone/.next/static/chunks/app/page-31e4d0ad258be21a.js.map +1 -0
  67. package/.next/standalone/.next/static/css/af02b3acc7d8f08d.css +5 -0
  68. package/.next/standalone/.next/static/css/af02b3acc7d8f08d.css.map +1 -0
  69. package/.next/standalone/package.json +1 -1
  70. package/.next/standalone/public/manifest.json +2 -2
  71. package/CHANGELOG.md +24 -0
  72. package/api/types.ts +3 -1
  73. package/app/layout.tsx +30 -1
  74. package/components/agents/AgentEditor.tsx +5 -5
  75. package/components/layout/AppShell.tsx +36 -18
  76. package/components/layout/MenuPanel.tsx +7 -7
  77. package/components/models/ModelEditor.tsx +3 -3
  78. package/components/profile/ProfileEditor.tsx +9 -9
  79. package/components/profile/ProfilePanel.tsx +3 -3
  80. package/components/setup/OnboardingWizard.tsx +4 -4
  81. package/components/ui/HeaderActivity.tsx +24 -0
  82. package/contexts/AppContext.tsx +12 -4
  83. package/contexts/ThemeContext.tsx +30 -1
  84. package/hooks/useSSE.ts +42 -5
  85. package/lib/agents/base.ts +3 -1
  86. package/lib/agents/run-thread.ts +6 -3
  87. package/lib/ui/loading.ts +59 -0
  88. package/package.json +1 -1
  89. package/public/manifest.json +2 -2
  90. package/.next/standalone/.next/server/chunks/5745.js.map +0 -1
  91. package/.next/standalone/.next/static/chunks/3741-81560b0aef166f49.js.map +0 -1
  92. package/.next/standalone/.next/static/chunks/app/layout-31009df0f341ccf5.js.map +0 -1
  93. package/.next/standalone/.next/static/chunks/app/page-108f526cb6e48b7b.js.map +0 -1
  94. package/.next/standalone/.next/static/css/a23baa1c79db0435.css +0 -5
  95. package/.next/standalone/.next/static/css/a23baa1c79db0435.css.map +0 -1
  96. package/components/ui/TopProgressBar.tsx +0 -32
  97. /package/.next/standalone/.next/static/{0ImXz-nn9QbojXpTvB3i0 → yk5tOLkAUA4hfQKDjGbzK}/_buildManifest.js +0 -0
  98. /package/.next/standalone/.next/static/{0ImXz-nn9QbojXpTvB3i0 → yk5tOLkAUA4hfQKDjGbzK}/_ssgManifest.js +0 -0
@@ -25,9 +25,26 @@ function readStored() {
25
25
  return "system";
26
26
  }
27
27
  }
28
+ const LIGHT_CHROME = "#ffffff";
29
+ const DARK_CHROME = "#09090b";
30
+ function resolveChrome(theme) {
31
+ if (theme === "light") return LIGHT_CHROME;
32
+ if (theme === "dark") return DARK_CHROME;
33
+ if (false) {}
34
+ return window.matchMedia("(prefers-color-scheme: dark)").matches ? DARK_CHROME : LIGHT_CHROME;
35
+ }
36
+ // Keep the single <meta name="theme-color"> tag (installed by the pre-paint
37
+ // script in app/layout.tsx) aligned with the active surface so the PWA's
38
+ // desktop title bar and mobile address bar match the theme.
39
+ function syncChrome(theme) {
40
+ if (typeof document === "undefined") return;
41
+ const meta = document.querySelector('meta[name="theme-color"]');
42
+ if (meta) meta.setAttribute("content", resolveChrome(theme));
43
+ }
28
44
  function apply(theme) {
29
45
  if (typeof document === "undefined") return;
30
46
  document.documentElement.setAttribute("data-theme", theme);
47
+ syncChrome(theme);
31
48
  }
32
49
  const ThemeContext = /*#__PURE__*/ (0,react__WEBPACK_IMPORTED_MODULE_1__.createContext)(null);
33
50
  function ThemeProvider({ children }) {
@@ -36,7 +53,16 @@ function ThemeProvider({ children }) {
36
53
  // React state to whatever the script (or localStorage) decided.
37
54
  const [theme, setThemeState] = (0,react__WEBPACK_IMPORTED_MODULE_1__.useState)("system");
38
55
  (0,react__WEBPACK_IMPORTED_MODULE_1__.useEffect)(()=>{
39
- setThemeState(readStored());
56
+ const stored = readStored();
57
+ setThemeState(stored);
58
+ // When in "system" mode, mirror OS-level changes into the PWA chrome.
59
+ if (false) {}
60
+ const mq = window.matchMedia("(prefers-color-scheme: dark)");
61
+ const onChange = ()=>{
62
+ if (readStored() === "system") syncChrome("system");
63
+ };
64
+ mq.addEventListener?.("change", onChange);
65
+ return ()=>mq.removeEventListener?.("change", onChange);
40
66
  }, []);
41
67
  const setTheme = (0,react__WEBPACK_IMPORTED_MODULE_1__.useCallback)((t)=>{
42
68
  setThemeState(t);
@@ -63,7 +89,7 @@ function useTheme() {
63
89
 
64
90
  /***/ }),
65
91
 
66
- /***/ 4633:
92
+ /***/ 1742:
67
93
  /***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
68
94
 
69
95
  "use strict";
@@ -675,9 +701,112 @@ function useUrlSync() {
675
701
  ]);
676
702
  }
677
703
 
704
+ ;// ./lib/ui/loading.ts
705
+ /* __next_internal_client_entry_do_not_use__ startLoading,useLoadingCount,useTrackLoading,pushActivity,useActivityLabel auto */ // Tiny global loading-state store. Any component can register itself as
706
+ // "currently busy"; the top-level progress bar reads the aggregate count and
707
+ // shows itself whenever count > 0. Module-level state is fine here — all
708
+ // usage is client-side and there's exactly one progress bar per page.
709
+
710
+ let activeCount = 0;
711
+ const loading_listeners = new Set();
712
+ function loading_notify() {
713
+ for (const l of loading_listeners)l(activeCount);
714
+ }
715
+ // Returns a cleanup function — call it when work finishes (or on effect unmount).
716
+ function startLoading() {
717
+ activeCount += 1;
718
+ loading_notify();
719
+ let cleared = false;
720
+ return ()=>{
721
+ if (cleared) return;
722
+ cleared = true;
723
+ activeCount = Math.max(0, activeCount - 1);
724
+ loading_notify();
725
+ };
726
+ }
727
+ // Subscribe to the aggregate count. Re-renders the caller when it changes.
728
+ function useLoadingCount() {
729
+ const [n, setN] = useState(activeCount);
730
+ useEffect(()=>{
731
+ const fn = (v)=>setN(v);
732
+ loading_listeners.add(fn);
733
+ setN(activeCount);
734
+ return ()=>{
735
+ loading_listeners.delete(fn);
736
+ };
737
+ }, []);
738
+ return n;
739
+ }
740
+ // Convenience: tracks `active` automatically. When `active` flips true, register;
741
+ // when it flips false (or component unmounts), unregister.
742
+ function useTrackLoading(active) {
743
+ (0,react.useEffect)(()=>{
744
+ if (!active) return;
745
+ return startLoading();
746
+ }, [
747
+ active
748
+ ]);
749
+ }
750
+ // ---------------------------------------------------------------------------
751
+ // Activity label channel. Independent of the loading count: callers that
752
+ // want to surface a human-readable "what's happening right now" string
753
+ // (e.g. "thinking…", "using web_search") push onto a small stack. The
754
+ // header reads the top of the stack and renders it inline.
755
+ // ---------------------------------------------------------------------------
756
+ let activitySeq = 0;
757
+ const activityStack = [];
758
+ const activityListeners = new Set();
759
+ function currentActivity() {
760
+ return activityStack.length > 0 ? activityStack[activityStack.length - 1].label : null;
761
+ }
762
+ function notifyActivity() {
763
+ const top = currentActivity();
764
+ for (const l of activityListeners)l(top);
765
+ }
766
+ // Push a label and return a setter+clearer for the same slot. The setter
767
+ // keeps the same stack id so updating a label (e.g. tool name changing
768
+ // mid-run) doesn't reorder layered activities. `clear` removes the slot.
769
+ function pushActivity(label) {
770
+ const id = ++activitySeq;
771
+ activityStack.push({
772
+ id,
773
+ label
774
+ });
775
+ notifyActivity();
776
+ return {
777
+ set (next) {
778
+ const slot = activityStack.find((s)=>s.id === id);
779
+ if (slot && slot.label !== next) {
780
+ slot.label = next;
781
+ notifyActivity();
782
+ }
783
+ },
784
+ clear () {
785
+ const idx = activityStack.findIndex((s)=>s.id === id);
786
+ if (idx >= 0) {
787
+ activityStack.splice(idx, 1);
788
+ notifyActivity();
789
+ }
790
+ }
791
+ };
792
+ }
793
+ function useActivityLabel() {
794
+ const [label, setLabel] = (0,react.useState)(currentActivity());
795
+ (0,react.useEffect)(()=>{
796
+ const fn = (v)=>setLabel(v);
797
+ activityListeners.add(fn);
798
+ setLabel(currentActivity());
799
+ return ()=>{
800
+ activityListeners.delete(fn);
801
+ };
802
+ }, []);
803
+ return label;
804
+ }
805
+
678
806
  ;// ./hooks/useSSE.ts
679
807
  /* __next_internal_client_entry_do_not_use__ useSSE auto */
680
808
 
809
+
681
810
  // Single-transport agent run hook (ADR-0008): one POST to submit + one
682
811
  // `EventSource` (under the hood) to subscribe. The hook keeps a stable
683
812
  // surface for `ChatView` — `start`, `attach`, `stop`, `streaming`,
@@ -691,13 +820,36 @@ function useSSE(onDone) {
691
820
  const [error, setError] = (0,react.useState)(null);
692
821
  const abortRef = (0,react.useRef)(null);
693
822
  const threadIdRef = (0,react.useRef)(null);
823
+ // Live "what is the agent doing" label, surfaced in the app header. The
824
+ // slot stays open for the duration of one run; we mutate its label as
825
+ // tool calls come and go so the header text updates in place without
826
+ // pushing/popping (which would flicker stacked activities).
827
+ const activityRef = (0,react.useRef)(null);
828
+ const activeToolsRef = (0,react.useRef)(new Map());
829
+ const openActivity = (0,react.useCallback)((initial)=>{
830
+ activityRef.current?.clear();
831
+ activeToolsRef.current.clear();
832
+ activityRef.current = pushActivity(initial);
833
+ }, []);
834
+ const closeActivity = (0,react.useCallback)(()=>{
835
+ activityRef.current?.clear();
836
+ activityRef.current = null;
837
+ activeToolsRef.current.clear();
838
+ }, []);
839
+ // Always release the activity label if the hook unmounts mid-run, so a
840
+ // dangling "thinking…" can't outlive its session.
841
+ (0,react.useEffect)(()=>closeActivity, [
842
+ closeActivity
843
+ ]);
694
844
  const consume = (0,react.useCallback)(async (iterable)=>{
695
845
  for await (const raw of iterable){
696
846
  const event = JSON.parse(raw);
697
847
  if (event.type === "text_delta") {
698
848
  setStreamingContent((p)=>p + event.delta);
849
+ activityRef.current?.set("Responding…");
699
850
  } else if (event.type === "thinking_delta") {
700
851
  setThinkingContent((p)=>p + event.delta);
852
+ if (activeToolsRef.current.size === 0) activityRef.current?.set("Thinking…");
701
853
  } else if (event.type === "tool_call") {
702
854
  setToolEvents((prev)=>[
703
855
  ...prev,
@@ -708,6 +860,8 @@ function useSSE(onDone) {
708
860
  payload: event.arguments
709
861
  }
710
862
  ]);
863
+ activeToolsRef.current.set(event.id, event.name);
864
+ activityRef.current?.set(`Using ${event.name}…`);
711
865
  } else if (event.type === "tool_result") {
712
866
  setToolEvents((prev)=>[
713
867
  ...prev,
@@ -718,8 +872,12 @@ function useSSE(onDone) {
718
872
  payload: event.result
719
873
  }
720
874
  ]);
875
+ activeToolsRef.current.delete(event.id);
876
+ const remaining = activeToolsRef.current.values().next().value;
877
+ activityRef.current?.set(remaining ? `Using ${remaining}…` : "Thinking…");
721
878
  } else if (event.type === "done") {
722
879
  setStreaming(false);
880
+ closeActivity();
723
881
  // Don't clear streamingContent here — it would cause a visual gap
724
882
  // between "stream done" and "refetched messages arrived" where the
725
883
  // assistant bubble disappears for ~100ms. The consumer (ChatView)
@@ -734,12 +892,14 @@ function useSSE(onDone) {
734
892
  setStreaming(false);
735
893
  setStreamingContent("");
736
894
  setThinkingContent("");
895
+ closeActivity();
737
896
  setError(event.message);
738
897
  break;
739
898
  }
740
899
  }
741
900
  }, [
742
- onDone
901
+ onDone,
902
+ closeActivity
743
903
  ]);
744
904
  const start = (0,react.useCallback)(async (threadId, message, options, attachments)=>{
745
905
  abortRef.current?.abort();
@@ -751,6 +911,7 @@ function useSSE(onDone) {
751
911
  setThinkingContent("");
752
912
  setToolEvents([]);
753
913
  setError(null);
914
+ openActivity("Sending…");
754
915
  try {
755
916
  // Command: register the run server-side. 202 = we own this turn; 409
756
917
  // = another tab/device owns it (caller re-queues, we still subscribe
@@ -770,12 +931,15 @@ function useSSE(onDone) {
770
931
  setStreaming(false);
771
932
  setStreamingContent("");
772
933
  setThinkingContent("");
934
+ closeActivity();
773
935
  return {
774
936
  accepted: false
775
937
  };
776
938
  }
777
939
  }, [
778
- consume
940
+ consume,
941
+ openActivity,
942
+ closeActivity
779
943
  ]);
780
944
  // Stop the active run. Three-part: (1) tell the server to abort the
781
945
  // agent stream so the LangGraph loop unwinds; (2) tear down local
@@ -795,10 +959,12 @@ function useSSE(onDone) {
795
959
  setStreaming(false);
796
960
  // Keep streamingContent and thinkingContent visible until the next
797
961
  // start()/attach() — same pattern as the `done` branch in consume().
962
+ closeActivity();
798
963
  abortRef.current?.abort();
799
964
  onDone?.();
800
965
  }, [
801
- onDone
966
+ onDone,
967
+ closeActivity
802
968
  ]);
803
969
  // Attach to an in-flight run for the given thread (server-side run kept
804
970
  // going because the user switched away, or because this is a fresh
@@ -817,6 +983,7 @@ function useSSE(onDone) {
817
983
  setThinkingContent("");
818
984
  setToolEvents([]);
819
985
  setError(null);
986
+ openActivity("Reconnecting…");
820
987
  try {
821
988
  await consume((0,client/* subscribeRun */._C)(threadId, ctrl.signal));
822
989
  } catch (err) {
@@ -825,13 +992,16 @@ function useSSE(onDone) {
825
992
  // "no run to attach to" (server returns 404, EventSource fails to
826
993
  // open) — completely normal when navigating into an idle session.
827
994
  setStreaming(false);
995
+ closeActivity();
828
996
  if (err.name !== "AbortError") {
829
997
  onDone?.();
830
998
  }
831
999
  }
832
1000
  }, [
833
1001
  consume,
834
- onDone
1002
+ onDone,
1003
+ openActivity,
1004
+ closeActivity
835
1005
  ]);
836
1006
  // Called by the consumer after a refetch lands, so the streaming bubble
837
1007
  // gets swapped for the persisted assistant message in a single render.
@@ -851,53 +1021,6 @@ function useSSE(onDone) {
851
1021
  };
852
1022
  }
853
1023
 
854
- ;// ./lib/ui/loading.ts
855
- /* __next_internal_client_entry_do_not_use__ startLoading,useLoadingCount,useTrackLoading auto */ // Tiny global loading-state store. Any component can register itself as
856
- // "currently busy"; the top-level progress bar reads the aggregate count and
857
- // shows itself whenever count > 0. Module-level state is fine here — all
858
- // usage is client-side and there's exactly one progress bar per page.
859
-
860
- let activeCount = 0;
861
- const loading_listeners = new Set();
862
- function loading_notify() {
863
- for (const l of loading_listeners)l(activeCount);
864
- }
865
- // Returns a cleanup function — call it when work finishes (or on effect unmount).
866
- function startLoading() {
867
- activeCount += 1;
868
- loading_notify();
869
- let cleared = false;
870
- return ()=>{
871
- if (cleared) return;
872
- cleared = true;
873
- activeCount = Math.max(0, activeCount - 1);
874
- loading_notify();
875
- };
876
- }
877
- // Subscribe to the aggregate count. Re-renders the caller when it changes.
878
- function useLoadingCount() {
879
- const [n, setN] = (0,react.useState)(activeCount);
880
- (0,react.useEffect)(()=>{
881
- const fn = (v)=>setN(v);
882
- loading_listeners.add(fn);
883
- setN(activeCount);
884
- return ()=>{
885
- loading_listeners.delete(fn);
886
- };
887
- }, []);
888
- return n;
889
- }
890
- // Convenience: tracks `active` automatically. When `active` flips true, register;
891
- // when it flips false (or component unmounts), unregister.
892
- function useTrackLoading(active) {
893
- (0,react.useEffect)(()=>{
894
- if (!active) return;
895
- return startLoading();
896
- }, [
897
- active
898
- ]);
899
- }
900
-
901
1024
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/shield-alert.mjs
902
1025
  var shield_alert = __webpack_require__(9203);
903
1026
  // EXTERNAL MODULE: ./node_modules/lucide-react/dist/esm/icons/chevron-up.mjs
@@ -5556,11 +5679,11 @@ function fmtCtx(n) {
5556
5679
  }
5557
5680
  function ModelEditor({ model, onSave, onClose }) {
5558
5681
  const { state } = (0,AppContext/* useAppContext */.U)();
5559
- const isAdvanced = state.experienceMode === "advanced";
5682
+ const isFullMode = state.experienceMode === "full";
5560
5683
  // Per-editor opt-in so a normal-mode user can reveal the engine-room
5561
5684
  // fields for one model without flipping the global workspace mode.
5562
5685
  const [showExpert, setShowExpert] = (0,react.useState)(false);
5563
- const expertVisible = isAdvanced || showExpert;
5686
+ const expertVisible = isFullMode || showExpert;
5564
5687
  const isEdit = !!model;
5565
5688
  const [name, setName] = (0,react.useState)(model?.name ?? "");
5566
5689
  const [provider, setProvider] = (0,react.useState)(model?.provider ?? "anthropic");
@@ -5772,7 +5895,7 @@ function ModelEditor({ model, onSave, onClose }) {
5772
5895
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
5773
5896
  className: "p-4 space-y-3.5",
5774
5897
  children: [
5775
- !isAdvanced && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
5898
+ !isFullMode && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
5776
5899
  type: "button",
5777
5900
  onClick: ()=>setShowExpert((v)=>!v),
5778
5901
  "aria-expanded": showExpert,
@@ -8096,7 +8219,7 @@ function Section({ step, title, children }) {
8096
8219
  }
8097
8220
  function AgentEditor({ agent, models, onSave, onClose }) {
8098
8221
  const { state, dispatch } = (0,AppContext/* useAppContext */.U)();
8099
- const isAdvanced = state.experienceMode === "advanced";
8222
+ const isFullMode = state.experienceMode === "full";
8100
8223
  const isEdit = !!agent;
8101
8224
  const { tools } = useTools();
8102
8225
  const fileRef = (0,react.useRef)(null);
@@ -8336,7 +8459,7 @@ function AgentEditor({ agent, models, onSave, onClose }) {
8336
8459
  return /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
8337
8460
  className: "fixed inset-0 bg-black/60 flex items-start justify-center z-50 p-2 sm:p-4 overflow-y-auto",
8338
8461
  children: /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
8339
- className: `bg-surface-2 border border-border rounded-2xl w-full shadow-xl my-2 sm:my-4 ${isAdvanced ? "max-w-2xl" : "max-w-xl"}`,
8462
+ className: `bg-surface-2 border border-border rounded-2xl w-full shadow-xl my-2 sm:my-4 ${isFullMode ? "max-w-2xl" : "max-w-xl"}`,
8340
8463
  children: [
8341
8464
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
8342
8465
  className: "flex items-center justify-between px-4 py-3 border-b border-border",
@@ -8584,7 +8707,7 @@ function AgentEditor({ agent, models, onSave, onClose }) {
8584
8707
  children: groupedTools.map(({ group, categories })=>group ? /*#__PURE__*/ (0,jsx_runtime.jsx)(ToolGroupBlock, {
8585
8708
  group: group,
8586
8709
  categories: categories,
8587
- advancedMode: isAdvanced,
8710
+ advancedMode: isFullMode,
8588
8711
  selected: selectedTools,
8589
8712
  onToggleTool: toggleTool,
8590
8713
  onToggleCategory: toggleCategory,
@@ -8593,7 +8716,7 @@ function AgentEditor({ agent, models, onSave, onClose }) {
8593
8716
  }, group) : categories.map(([category, catTools])=>/*#__PURE__*/ (0,jsx_runtime.jsx)(ToolCategoryBlock, {
8594
8717
  category: category,
8595
8718
  tools: catTools,
8596
- advancedMode: isAdvanced,
8719
+ advancedMode: isFullMode,
8597
8720
  selected: selectedTools,
8598
8721
  onToggleTool: toggleTool,
8599
8722
  onToggleCategory: toggleCategory,
@@ -8610,7 +8733,7 @@ function AgentEditor({ agent, models, onSave, onClose }) {
8610
8733
  step: 4,
8611
8734
  title: "Advanced settings",
8612
8735
  children: [
8613
- isAdvanced && /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
8736
+ isFullMode && /*#__PURE__*/ (0,jsx_runtime.jsxs)(jsx_runtime.Fragment, {
8614
8737
  children: [
8615
8738
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("label", {
8616
8739
  className: "block",
@@ -9538,7 +9661,7 @@ function ProfileEditor() {
9538
9661
  }),
9539
9662
  /*#__PURE__*/ (0,jsx_runtime.jsx)("p", {
9540
9663
  className: "text-[11px] text-fg-faint leading-snug",
9541
- children: "Choose how much configuration detail is shown in the app. Normal hides technical panels and advanced model controls."
9664
+ children: "Choose how much configuration detail is shown in the app. Essential hides technical panels and advanced model controls."
9542
9665
  }),
9543
9666
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
9544
9667
  className: "grid grid-cols-1 sm:grid-cols-2 gap-2",
@@ -9547,14 +9670,14 @@ function ProfileEditor() {
9547
9670
  type: "button",
9548
9671
  onClick: ()=>dispatch({
9549
9672
  type: "SET_EXPERIENCE_MODE",
9550
- mode: "normal"
9673
+ mode: "essential"
9551
9674
  }),
9552
- "aria-pressed": mode === "normal",
9553
- className: `text-left px-3 py-2.5 rounded-xl border transition-colors ${mode === "normal" ? "border-accent/60 bg-accent/15 text-fg shadow-sm" : "border-border bg-surface-3 text-fg-muted hover:text-fg hover:border-border-strong"}`,
9675
+ "aria-pressed": mode === "essential",
9676
+ className: `text-left px-3 py-2.5 rounded-xl border transition-colors ${mode === "essential" ? "border-accent/60 bg-accent/15 text-fg shadow-sm" : "border-border bg-surface-3 text-fg-muted hover:text-fg hover:border-border-strong"}`,
9554
9677
  children: [
9555
9678
  /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9556
9679
  className: "text-xs font-medium",
9557
- children: "Normal"
9680
+ children: "Essential"
9558
9681
  }),
9559
9682
  /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9560
9683
  className: "text-[10px] text-fg-faint leading-tight mt-0.5",
@@ -9566,14 +9689,14 @@ function ProfileEditor() {
9566
9689
  type: "button",
9567
9690
  onClick: ()=>dispatch({
9568
9691
  type: "SET_EXPERIENCE_MODE",
9569
- mode: "advanced"
9692
+ mode: "full"
9570
9693
  }),
9571
- "aria-pressed": mode === "advanced",
9572
- className: `text-left px-3 py-2.5 rounded-xl border transition-colors ${mode === "advanced" ? "border-accent/60 bg-accent/15 text-fg shadow-sm" : "border-border bg-surface-3 text-fg-muted hover:text-fg hover:border-border-strong"}`,
9694
+ "aria-pressed": mode === "full",
9695
+ className: `text-left px-3 py-2.5 rounded-xl border transition-colors ${mode === "full" ? "border-accent/60 bg-accent/15 text-fg shadow-sm" : "border-border bg-surface-3 text-fg-muted hover:text-fg hover:border-border-strong"}`,
9573
9696
  children: [
9574
9697
  /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9575
9698
  className: "text-xs font-medium",
9576
- children: "Advanced"
9699
+ children: "Full"
9577
9700
  }),
9578
9701
  /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
9579
9702
  className: "text-[10px] text-fg-faint leading-tight mt-0.5",
@@ -10104,11 +10227,11 @@ function TailscaleServe() {
10104
10227
 
10105
10228
  function ProfilePanel() {
10106
10229
  const { state } = (0,AppContext/* useAppContext */.U)();
10107
- const isNormal = state.experienceMode === "normal";
10230
+ const isEssential = state.experienceMode === "essential";
10108
10231
  const containerRef = (0,react.useRef)(null);
10109
10232
  const [showWizard, setShowWizard] = (0,react.useState)(false);
10110
10233
  useDeepLinkScroll("profile", "profile", containerRef);
10111
- if (isNormal && showWizard) {
10234
+ if (isEssential && showWizard) {
10112
10235
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
10113
10236
  className: "h-full overflow-y-auto profile-scrollbar panel-scrollbar",
10114
10237
  children: [
@@ -10160,7 +10283,7 @@ function ProfilePanel() {
10160
10283
  className: "text-sm font-semibold text-fg",
10161
10284
  children: "User Profile"
10162
10285
  }),
10163
- isNormal && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
10286
+ isEssential && /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
10164
10287
  type: "button",
10165
10288
  onClick: ()=>{
10166
10289
  setShowWizard(true);
@@ -17219,33 +17342,37 @@ function HarnessPanel() {
17219
17342
  });
17220
17343
  }
17221
17344
 
17222
- ;// ./components/ui/TopProgressBar.tsx
17223
- /* __next_internal_client_entry_do_not_use__ TopProgressBar auto */
17224
-
17345
+ ;// ./components/ui/HeaderActivity.tsx
17346
+ /* __next_internal_client_entry_do_not_use__ HeaderActivity auto */
17225
17347
 
17226
- // Thin indeterminate progress bar pinned to the top of the viewport.
17227
- // Visible whenever any tracked async work is in flight. Fades in fast and
17228
- // fades out after a short delay so quick operations don't strobe.
17229
- function TopProgressBar() {
17230
- const count = useLoadingCount();
17231
- const [visible, setVisible] = (0,react.useState)(false);
17232
- (0,react.useEffect)(()=>{
17233
- if (count > 0) {
17234
- setVisible(true);
17235
- return;
17236
- }
17237
- // Linger briefly after work completes for a smoother fade-out.
17238
- const t = setTimeout(()=>setVisible(false), 200);
17239
- return ()=>clearTimeout(t);
17240
- }, [
17241
- count
17242
- ]);
17243
- return /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
17244
- className: `pointer-events-none fixed top-0 left-0 right-0 h-[2px] z-50 transition-opacity duration-150 ${visible ? "opacity-100" : "opacity-0"}`,
17245
- "aria-hidden": !visible,
17246
- children: /*#__PURE__*/ (0,jsx_runtime.jsx)("div", {
17247
- className: "jarela-progress h-full w-full"
17248
- })
17348
+ // Inline "what is happening right now" text rendered next to the agent
17349
+ // dropdown. Replaces the old TopProgressBar: a single short label that
17350
+ // updates live as the run progresses (Sending… / Thinking… / Using <tool>…).
17351
+ // Returns null when nothing is in flight so the header stays calm.
17352
+ function HeaderActivity() {
17353
+ const label = useActivityLabel();
17354
+ if (!label) return null;
17355
+ return /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
17356
+ role: "status",
17357
+ "aria-live": "polite",
17358
+ className: "ml-1 inline-flex items-center gap-1.5 text-xs text-fg-faint truncate max-w-[14rem]",
17359
+ children: [
17360
+ /*#__PURE__*/ (0,jsx_runtime.jsxs)("span", {
17361
+ className: "relative inline-flex h-1.5 w-1.5 shrink-0",
17362
+ children: [
17363
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
17364
+ className: "absolute inset-0 rounded-full bg-accent/70 animate-ping"
17365
+ }),
17366
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
17367
+ className: "relative inline-flex h-1.5 w-1.5 rounded-full bg-accent"
17368
+ })
17369
+ ]
17370
+ }),
17371
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
17372
+ className: "truncate",
17373
+ children: label
17374
+ })
17375
+ ]
17249
17376
  });
17250
17377
  }
17251
17378
 
@@ -18236,11 +18363,11 @@ function AgentSessionList({ activeAgentId, onSelect }) {
18236
18363
  }
18237
18364
  function MenuPanel({ activeTab, agentId, showTools, showThinking, onClose, onAgentChange, onSetTab, onShowToolsChange, onShowThinkingChange }) {
18238
18365
  const { state, dispatch } = (0,AppContext/* useAppContext */.U)();
18239
- const isAdvanced = state.experienceMode === "advanced";
18366
+ const isFullMode = state.experienceMode === "full";
18240
18367
  const toggleMode = ()=>{
18241
18368
  dispatch({
18242
18369
  type: "SET_EXPERIENCE_MODE",
18243
- mode: isAdvanced ? "normal" : "advanced"
18370
+ mode: isFullMode ? "essential" : "full"
18244
18371
  });
18245
18372
  };
18246
18373
  // Advanced section starts collapsed once the user has dismissed it
@@ -18318,10 +18445,10 @@ function MenuPanel({ activeTab, agentId, showTools, showThinking, onClose, onAge
18318
18445
  /*#__PURE__*/ (0,jsx_runtime.jsx)("button", {
18319
18446
  type: "button",
18320
18447
  onClick: toggleMode,
18321
- title: `Switch to ${isAdvanced ? "normal" : "advanced"} mode`,
18322
- "aria-label": `Switch to ${isAdvanced ? "normal" : "advanced"} mode`,
18323
- className: `control-tap text-[10px] uppercase tracking-wide px-2 py-0.5 rounded-full border transition-colors ${isAdvanced ? "border-accent/40 bg-accent/10 text-fg-subtle hover:bg-accent/20" : "border-border bg-surface-3 text-fg-faint hover:text-fg-muted hover:border-border-strong"}`,
18324
- children: isAdvanced ? "advanced" : "normal"
18448
+ title: `Switch to ${isFullMode ? "essential" : "full"} mode`,
18449
+ "aria-label": `Switch to ${isFullMode ? "essential" : "full"} mode`,
18450
+ className: `control-tap text-[10px] uppercase tracking-wide px-2 py-0.5 rounded-full border transition-colors ${isFullMode ? "border-accent/40 bg-accent/10 text-fg-subtle hover:bg-accent/20" : "border-border bg-surface-3 text-fg-faint hover:text-fg-muted hover:border-border-strong"}`,
18451
+ children: isFullMode ? "full" : "essential"
18325
18452
  })
18326
18453
  ]
18327
18454
  })
@@ -18330,7 +18457,7 @@ function MenuPanel({ activeTab, agentId, showTools, showThinking, onClose, onAge
18330
18457
  className: "grid grid-cols-4 sm:grid-cols-6 gap-1.5 px-2 py-2 border-b border-border shrink-0",
18331
18458
  children: COMMON_TABS.map(renderTabButton)
18332
18459
  }),
18333
- isAdvanced && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
18460
+ isFullMode && /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
18334
18461
  className: "border-b border-border shrink-0",
18335
18462
  children: [
18336
18463
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
@@ -20237,7 +20364,7 @@ const AppShell_ADVANCED_TABS = new Set([
20237
20364
  ]);
20238
20365
  function AppShell() {
20239
20366
  const { state, dispatch } = (0,AppContext/* useAppContext */.U)();
20240
- const isAdvanced = state.experienceMode === "advanced";
20367
+ const isFullMode = state.experienceMode === "full";
20241
20368
  useUrlSync();
20242
20369
  const { threadId, loading: sessionLoading, error: sessionError } = useAgentSession(state.activeAgentId, state.activeThreadId);
20243
20370
  const [showMenu, setShowMenu] = (0,react.useState)(false);
@@ -20259,7 +20386,7 @@ function AppShell() {
20259
20386
  state.activeTab
20260
20387
  ]);
20261
20388
  (0,react.useEffect)(()=>{
20262
- if (!isAdvanced && AppShell_ADVANCED_TABS.has(state.activeTab)) {
20389
+ if (!isFullMode && AppShell_ADVANCED_TABS.has(state.activeTab)) {
20263
20390
  dispatch({
20264
20391
  type: "SET_TAB",
20265
20392
  tab: "profile"
@@ -20267,7 +20394,7 @@ function AppShell() {
20267
20394
  }
20268
20395
  }, [
20269
20396
  dispatch,
20270
- isAdvanced,
20397
+ isFullMode,
20271
20398
  state.activeTab
20272
20399
  ]);
20273
20400
  const unreadCount = useUnreadCount();
@@ -20405,7 +20532,6 @@ function AppShell() {
20405
20532
  return /*#__PURE__*/ (0,jsx_runtime.jsxs)("div", {
20406
20533
  className: "h-screen h-[100dvh] flex flex-col text-fg overflow-hidden px-safe",
20407
20534
  children: [
20408
- /*#__PURE__*/ (0,jsx_runtime.jsx)(TopProgressBar, {}),
20409
20535
  /*#__PURE__*/ (0,jsx_runtime.jsx)(NotificationStatus, {}),
20410
20536
  /*#__PURE__*/ (0,jsx_runtime.jsx)(Toaster, {}),
20411
20537
  /*#__PURE__*/ (0,jsx_runtime.jsx)(ServerStatus, {}),
@@ -20437,22 +20563,31 @@ function AppShell() {
20437
20563
  type: "button",
20438
20564
  onClick: ()=>setShowAgentPicker((v)=>!v),
20439
20565
  className: "control-tap inline-flex items-center gap-2 rounded-lg px-1.5 py-1 hover:bg-surface-3/60 transition-colors",
20440
- title: "Select active agent",
20566
+ title: activeAgent ? `Active agent: ${activeAgent.name} — click to switch` : "Select active agent",
20441
20567
  "aria-haspopup": "menu",
20442
20568
  "aria-expanded": showAgentPicker,
20443
20569
  children: [
20570
+ activeAgent?.icon ? // eslint-disable-next-line @next/next/no-img-element
20571
+ /*#__PURE__*/ (0,jsx_runtime.jsx)("img", {
20572
+ src: activeAgent.icon,
20573
+ alt: "",
20574
+ className: "h-6 w-6 rounded-md object-cover shrink-0"
20575
+ }) : activeAgent ? /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
20576
+ "aria-hidden": true,
20577
+ className: "h-6 w-6 rounded-md bg-surface-3 text-[11px] font-semibold text-fg-subtle inline-flex items-center justify-center shrink-0",
20578
+ children: activeAgent.name.charAt(0).toUpperCase()
20579
+ }) : // No active agent yet — fall back to the app mark. Blue-on-
20580
+ // transparent loses contrast against the dark glass, so we
20581
+ // flatten + invert it in dark mode (alpha is preserved).
20582
+ // eslint-disable-next-line @next/next/no-img-element
20444
20583
  /*#__PURE__*/ (0,jsx_runtime.jsx)("img", {
20445
20584
  src: "/logo-mark-transparent.png",
20446
20585
  alt: "",
20447
20586
  className: "h-6 w-auto dark:brightness-0 dark:invert"
20448
20587
  }),
20449
20588
  /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
20450
- className: "text-fg font-semibold tracking-tight",
20451
- children: (0,app_config/* getAppName */.fj)()
20452
- }),
20453
- /*#__PURE__*/ (0,jsx_runtime.jsx)("span", {
20454
- className: "text-xs text-fg-faint max-w-[11rem] truncate hidden sm:inline",
20455
- children: activeAgent?.name ?? "select agent"
20589
+ className: "text-fg font-semibold tracking-tight truncate max-w-[12rem] sm:max-w-[16rem]",
20590
+ children: activeAgent?.name ?? (0,app_config/* getAppName */.fj)()
20456
20591
  }),
20457
20592
  /*#__PURE__*/ (0,jsx_runtime.jsx)(chevron_down/* default */.A, {
20458
20593
  size: 14,
@@ -20510,6 +20645,7 @@ function AppShell() {
20510
20645
  })
20511
20646
  ]
20512
20647
  }),
20648
+ /*#__PURE__*/ (0,jsx_runtime.jsx)(HeaderActivity, {}),
20513
20649
  /*#__PURE__*/ (0,jsx_runtime.jsxs)("button", {
20514
20650
  onClick: ()=>{
20515
20651
  setShowMenu((v)=>!v);
@@ -20552,7 +20688,7 @@ function AppShell() {
20552
20688
  mode: state.activeTab === "agents" ? "visible" : "hidden",
20553
20689
  children: /*#__PURE__*/ (0,jsx_runtime.jsx)(AgentsPanel, {})
20554
20690
  }),
20555
- isAdvanced && mountedTabs.has("memory") && /*#__PURE__*/ (0,jsx_runtime.jsx)(react.Activity, {
20691
+ isFullMode && mountedTabs.has("memory") && /*#__PURE__*/ (0,jsx_runtime.jsx)(react.Activity, {
20556
20692
  mode: state.activeTab === "memory" ? "visible" : "hidden",
20557
20693
  children: /*#__PURE__*/ (0,jsx_runtime.jsx)(MemoryPanel, {})
20558
20694
  }),
@@ -20584,7 +20720,7 @@ function AppShell() {
20584
20720
  mode: state.activeTab === "tasks" ? "visible" : "hidden",
20585
20721
  children: /*#__PURE__*/ (0,jsx_runtime.jsx)(ScheduledTasksPanel, {})
20586
20722
  }),
20587
- isAdvanced && mountedTabs.has("bridges") && /*#__PURE__*/ (0,jsx_runtime.jsx)(react.Activity, {
20723
+ isFullMode && mountedTabs.has("bridges") && /*#__PURE__*/ (0,jsx_runtime.jsx)(react.Activity, {
20588
20724
  mode: state.activeTab === "bridges" ? "visible" : "hidden",
20589
20725
  children: /*#__PURE__*/ (0,jsx_runtime.jsx)(BridgesPanel, {})
20590
20726
  }),
@@ -20592,7 +20728,7 @@ function AppShell() {
20592
20728
  mode: state.activeTab === "profile" ? "visible" : "hidden",
20593
20729
  children: /*#__PURE__*/ (0,jsx_runtime.jsx)(ProfilePanel, {})
20594
20730
  }),
20595
- isAdvanced && mountedTabs.has("harness") && /*#__PURE__*/ (0,jsx_runtime.jsx)(react.Activity, {
20731
+ isFullMode && mountedTabs.has("harness") && /*#__PURE__*/ (0,jsx_runtime.jsx)(react.Activity, {
20596
20732
  mode: state.activeTab === "harness" ? "visible" : "hidden",
20597
20733
  children: /*#__PURE__*/ (0,jsx_runtime.jsx)(HarnessPanel, {})
20598
20734
  }),
@@ -20635,7 +20771,7 @@ function AppShell() {
20635
20771
  /***/ 9469:
20636
20772
  /***/ ((__unused_webpack_module, __unused_webpack_exports, __webpack_require__) => {
20637
20773
 
20638
- Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 4633));
20774
+ Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_require__, 1742));
20639
20775
 
20640
20776
 
20641
20777
  /***/ })
@@ -20648,4 +20784,4 @@ Promise.resolve(/* import() eager */).then(__webpack_require__.bind(__webpack_re
20648
20784
  /******/ _N_E = __webpack_exports__;
20649
20785
  /******/ }
20650
20786
  ]);
20651
- //# sourceMappingURL=page-108f526cb6e48b7b.js.map
20787
+ //# sourceMappingURL=page-31e4d0ad258be21a.js.map