@phenx-inc/ctlsurf 0.13.5 → 0.14.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/out/headless/index.mjs +13663 -385
  2. package/out/headless/index.mjs.map +4 -4
  3. package/out/main/index.js +11677 -290
  4. package/out/main/node-CUnQxFha.js +868 -0
  5. package/out/preload/index.js +19 -0
  6. package/out/renderer/assets/{cssMode-CAEObGNt.js → cssMode-7adWSORr.js} +3 -3
  7. package/out/renderer/assets/{freemarker2-D63hnnDq.js → freemarker2-BkLLWnzk.js} +1 -1
  8. package/out/renderer/assets/{handlebars-UYo_IYpi.js → handlebars-Cinfm9fZ.js} +1 -1
  9. package/out/renderer/assets/{html-2dvYDi3g.js → html-vl9fkHKL.js} +1 -1
  10. package/out/renderer/assets/{htmlMode-B6fxDDPF.js → htmlMode-BtGqkTNI.js} +3 -3
  11. package/out/renderer/assets/{index-CMb4AqkZ.js → index-BhrV6ld-.js} +381 -29
  12. package/out/renderer/assets/{index-BEekQe3-.css → index-BpCORklm.css} +217 -0
  13. package/out/renderer/assets/{javascript-8RyFDDdk.js → javascript-B7CCdfuW.js} +2 -2
  14. package/out/renderer/assets/{jsonMode-CqspkWCb.js → jsonMode-ut9LWBMJ.js} +3 -3
  15. package/out/renderer/assets/{liquid-DaEnAsYY.js → liquid-DVDJ0lKt.js} +1 -1
  16. package/out/renderer/assets/{lspLanguageFeatures-Czkp5sZb.js → lspLanguageFeatures-BbMj8Wsc.js} +1 -1
  17. package/out/renderer/assets/{mdx-Q-qSZsFg.js → mdx-CcQzYB0J.js} +1 -1
  18. package/out/renderer/assets/{python-Sw0S0BJV.js → python-Byy7wKMv.js} +1 -1
  19. package/out/renderer/assets/{razor-C7zQmabz.js → razor-D1xi_wMM.js} +1 -1
  20. package/out/renderer/assets/{tsMode-BWdOxk6v.js → tsMode-DJPzbn5i.js} +1 -1
  21. package/out/renderer/assets/{typescript-BrdIiKZf.js → typescript-BuVaU7i3.js} +1 -1
  22. package/out/renderer/assets/{xml-DbKLNPOq.js → xml-rzc91O3d.js} +1 -1
  23. package/out/renderer/assets/{yaml-ehupJBsZ.js → yaml-fAOzQMge.js} +1 -1
  24. package/out/renderer/index.html +2 -2
  25. package/package.json +2 -1
  26. package/src/main/index.ts +55 -8
  27. package/src/main/observer/anthropic.ts +48 -0
  28. package/src/main/observer/budget.ts +79 -0
  29. package/src/main/observer/ledger.ts +61 -0
  30. package/src/main/observer/observer.ts +566 -0
  31. package/src/main/observer/spans.ts +170 -0
  32. package/src/main/observer/store.ts +200 -0
  33. package/src/main/observer/tier0.ts +234 -0
  34. package/src/main/observer/tier1.ts +306 -0
  35. package/src/main/observer/tier2.ts +125 -0
  36. package/src/main/observer/types.ts +224 -0
  37. package/src/main/orchestrator.ts +74 -0
  38. package/src/main/transcripts.ts +18 -0
  39. package/src/preload/index.ts +40 -2
  40. package/src/renderer/App.tsx +22 -0
  41. package/src/renderer/components/ObserverPanel.tsx +289 -0
  42. package/src/renderer/components/SettingsDialog.tsx +104 -0
  43. package/src/renderer/components/TerminalPanel.tsx +28 -5
  44. package/src/renderer/styles.css +217 -0
@@ -1,4 +1,4 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-CAEObGNt.js","./lspLanguageFeatures-Czkp5sZb.js","./htmlMode-B6fxDDPF.js","./jsonMode-CqspkWCb.js","./javascript-8RyFDDdk.js","./typescript-BrdIiKZf.js"])))=>i.map(i=>d[i]);
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./cssMode-7adWSORr.js","./lspLanguageFeatures-BbMj8Wsc.js","./htmlMode-BtGqkTNI.js","./jsonMode-ut9LWBMJ.js","./javascript-B7CCdfuW.js","./typescript-BuVaU7i3.js"])))=>i.map(i=>d[i]);
2
2
  function getDefaultExportFromCjs(x) {
3
3
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
4
4
  }
@@ -19189,17 +19189,33 @@ function showTerminalToast(message) {
19189
19189
  }
19190
19190
  function copyTextValue(text2) {
19191
19191
  if (!text2) return;
19192
- void window.worker.copyText(text2);
19193
- showTerminalToast("Copied to clipboard");
19192
+ void window.worker.copyText(text2).then((res) => {
19193
+ if (res?.ok) showTerminalToast("Copied to clipboard");
19194
+ else {
19195
+ showTerminalToast("Copy failed — clipboard not updated");
19196
+ console.warn("[copy] clipboard write not verified", res);
19197
+ }
19198
+ }).catch((err) => {
19199
+ showTerminalToast("Copy failed");
19200
+ console.warn("[copy] clipboard write threw", err);
19201
+ });
19194
19202
  }
19195
19203
  function convertTextToTable(text2) {
19196
19204
  const result = convertToEmailTable(text2);
19197
- if (result) {
19198
- window.worker.copyEmailTable(result.html, result.text);
19199
- showTerminalToast(`Copied ${result.rows}×${result.cols} table to clipboard`);
19200
- } else {
19205
+ if (!result) {
19201
19206
  showTerminalToast("No table found in selection");
19207
+ return;
19202
19208
  }
19209
+ void window.worker.copyEmailTable(result.html, result.text).then((res) => {
19210
+ if (res?.ok) showTerminalToast(`Copied ${result.rows}×${result.cols} table to clipboard`);
19211
+ else {
19212
+ showTerminalToast("Copy failed — clipboard not updated");
19213
+ console.warn("[copy] table clipboard write not verified", res);
19214
+ }
19215
+ }).catch((err) => {
19216
+ showTerminalToast("Copy failed");
19217
+ console.warn("[copy] table clipboard write threw", err);
19218
+ });
19203
19219
  }
19204
19220
  function speakTextValue(text2) {
19205
19221
  if (!text2.trim()) return;
@@ -208151,7 +208167,7 @@ const lessDefaults = new LanguageServiceDefaultsImpl$3(
208151
208167
  modeConfigurationDefault$2
208152
208168
  );
208153
208169
  function getMode$3() {
208154
- return __vitePreload(() => import("./cssMode-CAEObGNt.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
208170
+ return __vitePreload(() => import("./cssMode-7adWSORr.js"), true ? __vite__mapDeps([0,1]) : void 0, import.meta.url);
208155
208171
  }
208156
208172
  languages.onLanguage("less", () => {
208157
208173
  getMode$3().then((mode2) => mode2.setupMode(lessDefaults));
@@ -208256,7 +208272,7 @@ const razorLanguageService = registerHTMLLanguageService(
208256
208272
  );
208257
208273
  const razorDefaults = razorLanguageService.defaults;
208258
208274
  function getMode$2() {
208259
- return __vitePreload(() => import("./htmlMode-B6fxDDPF.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
208275
+ return __vitePreload(() => import("./htmlMode-BtGqkTNI.js"), true ? __vite__mapDeps([2,1]) : void 0, import.meta.url);
208260
208276
  }
208261
208277
  function registerHTMLLanguageService(languageId, options = optionsDefault, modeConfiguration = getConfigurationDefault(languageId)) {
208262
208278
  const defaults = new LanguageServiceDefaultsImpl$2(languageId, options, modeConfiguration);
@@ -208340,7 +208356,7 @@ const jsonDefaults = new LanguageServiceDefaultsImpl$1(
208340
208356
  );
208341
208357
  const getWorker$1 = () => getMode$1().then((mode2) => mode2.getWorker());
208342
208358
  function getMode$1() {
208343
- return __vitePreload(() => import("./jsonMode-CqspkWCb.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
208359
+ return __vitePreload(() => import("./jsonMode-ut9LWBMJ.js"), true ? __vite__mapDeps([3,1]) : void 0, import.meta.url);
208344
208360
  }
208345
208361
  languages.register({
208346
208362
  id: "json",
@@ -208586,7 +208602,7 @@ const getJavaScriptWorker = () => {
208586
208602
  return getMode().then((mode) => mode.getJavaScriptWorker());
208587
208603
  };
208588
208604
  function getMode() {
208589
- return __vitePreload(() => import("./tsMode-BWdOxk6v.js"), true ? [] : void 0, import.meta.url);
208605
+ return __vitePreload(() => import("./tsMode-DJPzbn5i.js"), true ? [] : void 0, import.meta.url);
208590
208606
  }
208591
208607
  languages.onLanguage("typescript", () => {
208592
208608
  return getMode().then((mode) => mode.setupTypeScript(typescriptDefaults));
@@ -208781,49 +208797,49 @@ registerLanguage({
208781
208797
  extensions: [".ftl", ".ftlh", ".ftlx"],
208782
208798
  aliases: ["FreeMarker2", "Apache FreeMarker2"],
208783
208799
  loader: () => {
208784
- return __vitePreload(() => import("./freemarker2-D63hnnDq.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
208800
+ return __vitePreload(() => import("./freemarker2-BkLLWnzk.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
208785
208801
  }
208786
208802
  });
208787
208803
  registerLanguage({
208788
208804
  id: "freemarker2.tag-angle.interpolation-dollar",
208789
208805
  aliases: ["FreeMarker2 (Angle/Dollar)", "Apache FreeMarker2 (Angle/Dollar)"],
208790
208806
  loader: () => {
208791
- return __vitePreload(() => import("./freemarker2-D63hnnDq.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
208807
+ return __vitePreload(() => import("./freemarker2-BkLLWnzk.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationDollar);
208792
208808
  }
208793
208809
  });
208794
208810
  registerLanguage({
208795
208811
  id: "freemarker2.tag-bracket.interpolation-dollar",
208796
208812
  aliases: ["FreeMarker2 (Bracket/Dollar)", "Apache FreeMarker2 (Bracket/Dollar)"],
208797
208813
  loader: () => {
208798
- return __vitePreload(() => import("./freemarker2-D63hnnDq.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
208814
+ return __vitePreload(() => import("./freemarker2-BkLLWnzk.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationDollar);
208799
208815
  }
208800
208816
  });
208801
208817
  registerLanguage({
208802
208818
  id: "freemarker2.tag-angle.interpolation-bracket",
208803
208819
  aliases: ["FreeMarker2 (Angle/Bracket)", "Apache FreeMarker2 (Angle/Bracket)"],
208804
208820
  loader: () => {
208805
- return __vitePreload(() => import("./freemarker2-D63hnnDq.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
208821
+ return __vitePreload(() => import("./freemarker2-BkLLWnzk.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAngleInterpolationBracket);
208806
208822
  }
208807
208823
  });
208808
208824
  registerLanguage({
208809
208825
  id: "freemarker2.tag-bracket.interpolation-bracket",
208810
208826
  aliases: ["FreeMarker2 (Bracket/Bracket)", "Apache FreeMarker2 (Bracket/Bracket)"],
208811
208827
  loader: () => {
208812
- return __vitePreload(() => import("./freemarker2-D63hnnDq.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
208828
+ return __vitePreload(() => import("./freemarker2-BkLLWnzk.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagBracketInterpolationBracket);
208813
208829
  }
208814
208830
  });
208815
208831
  registerLanguage({
208816
208832
  id: "freemarker2.tag-auto.interpolation-dollar",
208817
208833
  aliases: ["FreeMarker2 (Auto/Dollar)", "Apache FreeMarker2 (Auto/Dollar)"],
208818
208834
  loader: () => {
208819
- return __vitePreload(() => import("./freemarker2-D63hnnDq.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
208835
+ return __vitePreload(() => import("./freemarker2-BkLLWnzk.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationDollar);
208820
208836
  }
208821
208837
  });
208822
208838
  registerLanguage({
208823
208839
  id: "freemarker2.tag-auto.interpolation-bracket",
208824
208840
  aliases: ["FreeMarker2 (Auto/Bracket)", "Apache FreeMarker2 (Auto/Bracket)"],
208825
208841
  loader: () => {
208826
- return __vitePreload(() => import("./freemarker2-D63hnnDq.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
208842
+ return __vitePreload(() => import("./freemarker2-BkLLWnzk.js"), true ? [] : void 0, import.meta.url).then((m) => m.TagAutoInterpolationBracket);
208827
208843
  }
208828
208844
  });
208829
208845
  registerLanguage({
@@ -208844,7 +208860,7 @@ registerLanguage({
208844
208860
  extensions: [".handlebars", ".hbs"],
208845
208861
  aliases: ["Handlebars", "handlebars", "hbs"],
208846
208862
  mimetypes: ["text/x-handlebars-template"],
208847
- loader: () => __vitePreload(() => import("./handlebars-UYo_IYpi.js"), true ? [] : void 0, import.meta.url)
208863
+ loader: () => __vitePreload(() => import("./handlebars-Cinfm9fZ.js"), true ? [] : void 0, import.meta.url)
208848
208864
  });
208849
208865
  registerLanguage({
208850
208866
  id: "hcl",
@@ -208857,7 +208873,7 @@ registerLanguage({
208857
208873
  extensions: [".html", ".htm", ".shtml", ".xhtml", ".mdoc", ".jsp", ".asp", ".aspx", ".jshtm"],
208858
208874
  aliases: ["HTML", "htm", "html", "xhtml"],
208859
208875
  mimetypes: ["text/html", "text/x-jshtm", "text/template", "text/ng-template"],
208860
- loader: () => __vitePreload(() => import("./html-2dvYDi3g.js"), true ? [] : void 0, import.meta.url)
208876
+ loader: () => __vitePreload(() => import("./html-vl9fkHKL.js"), true ? [] : void 0, import.meta.url)
208861
208877
  });
208862
208878
  registerLanguage({
208863
208879
  id: "ini",
@@ -208880,7 +208896,7 @@ registerLanguage({
208880
208896
  filenames: ["jakefile"],
208881
208897
  aliases: ["JavaScript", "javascript", "js"],
208882
208898
  mimetypes: ["text/javascript"],
208883
- loader: () => __vitePreload(() => import("./javascript-8RyFDDdk.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
208899
+ loader: () => __vitePreload(() => import("./javascript-B7CCdfuW.js"), true ? __vite__mapDeps([4,5]) : void 0, import.meta.url)
208884
208900
  });
208885
208901
  registerLanguage({
208886
208902
  id: "julia",
@@ -208919,7 +208935,7 @@ registerLanguage({
208919
208935
  extensions: [".liquid", ".html.liquid"],
208920
208936
  aliases: ["Liquid", "liquid"],
208921
208937
  mimetypes: ["application/liquid"],
208922
- loader: () => __vitePreload(() => import("./liquid-DaEnAsYY.js"), true ? [] : void 0, import.meta.url)
208938
+ loader: () => __vitePreload(() => import("./liquid-DVDJ0lKt.js"), true ? [] : void 0, import.meta.url)
208923
208939
  });
208924
208940
  registerLanguage({
208925
208941
  id: "m3",
@@ -208937,7 +208953,7 @@ registerLanguage({
208937
208953
  id: "mdx",
208938
208954
  extensions: [".mdx"],
208939
208955
  aliases: ["MDX", "mdx"],
208940
- loader: () => __vitePreload(() => import("./mdx-Q-qSZsFg.js"), true ? [] : void 0, import.meta.url)
208956
+ loader: () => __vitePreload(() => import("./mdx-CcQzYB0J.js"), true ? [] : void 0, import.meta.url)
208941
208957
  });
208942
208958
  registerLanguage({
208943
208959
  id: "mips",
@@ -209036,7 +209052,7 @@ registerLanguage({
209036
209052
  extensions: [".py", ".rpy", ".pyw", ".cpy", ".gyp", ".gypi"],
209037
209053
  aliases: ["Python", "py"],
209038
209054
  firstLine: "^#!/.*\\bpython[0-9.-]*\\b",
209039
- loader: () => __vitePreload(() => import("./python-Sw0S0BJV.js"), true ? [] : void 0, import.meta.url)
209055
+ loader: () => __vitePreload(() => import("./python-Byy7wKMv.js"), true ? [] : void 0, import.meta.url)
209040
209056
  });
209041
209057
  registerLanguage({
209042
209058
  id: "qsharp",
@@ -209055,7 +209071,7 @@ registerLanguage({
209055
209071
  extensions: [".cshtml"],
209056
209072
  aliases: ["Razor", "razor"],
209057
209073
  mimetypes: ["text/x-cshtml"],
209058
- loader: () => __vitePreload(() => import("./razor-C7zQmabz.js"), true ? [] : void 0, import.meta.url)
209074
+ loader: () => __vitePreload(() => import("./razor-D1xi_wMM.js"), true ? [] : void 0, import.meta.url)
209059
209075
  });
209060
209076
  registerLanguage({
209061
209077
  id: "redis",
@@ -209188,7 +209204,7 @@ registerLanguage({
209188
209204
  aliases: ["TypeScript", "ts", "typescript"],
209189
209205
  mimetypes: ["text/typescript"],
209190
209206
  loader: () => {
209191
- return __vitePreload(() => import("./typescript-BrdIiKZf.js"), true ? [] : void 0, import.meta.url);
209207
+ return __vitePreload(() => import("./typescript-BuVaU7i3.js"), true ? [] : void 0, import.meta.url);
209192
209208
  }
209193
209209
  });
209194
209210
  registerLanguage({
@@ -209233,14 +209249,14 @@ registerLanguage({
209233
209249
  firstLine: "(\\<\\?xml.*)|(\\<svg)|(\\<\\!doctype\\s+svg)",
209234
209250
  aliases: ["XML", "xml"],
209235
209251
  mimetypes: ["text/xml", "application/xml", "application/xaml+xml", "application/xml-dtd"],
209236
- loader: () => __vitePreload(() => import("./xml-DbKLNPOq.js"), true ? [] : void 0, import.meta.url)
209252
+ loader: () => __vitePreload(() => import("./xml-rzc91O3d.js"), true ? [] : void 0, import.meta.url)
209237
209253
  });
209238
209254
  registerLanguage({
209239
209255
  id: "yaml",
209240
209256
  extensions: [".yaml", ".yml"],
209241
209257
  aliases: ["YAML", "yaml", "YML", "yml"],
209242
209258
  mimetypes: ["application/x-yaml", "text/x-yaml"],
209243
- loader: () => __vitePreload(() => import("./yaml-ehupJBsZ.js"), true ? [] : void 0, import.meta.url)
209259
+ loader: () => __vitePreload(() => import("./yaml-fAOzQMge.js"), true ? [] : void 0, import.meta.url)
209244
209260
  });
209245
209261
  var __defProp = Object.defineProperty;
209246
209262
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
@@ -213533,20 +213549,54 @@ function SettingsDialog({ open, onClose }) {
213533
213549
  const [idleTimeoutMin, setIdleTimeoutMin] = reactExports.useState(15);
213534
213550
  const [saved, setSaved] = reactExports.useState(false);
213535
213551
  const [version, setVersion] = reactExports.useState("");
213552
+ const [obsEnabled, setObsEnabled] = reactExports.useState(false);
213553
+ const [obsApiKey, setObsApiKey] = reactExports.useState("");
213554
+ const [obsHasKey, setObsHasKey] = reactExports.useState(false);
213555
+ const [obsKeySource, setObsKeySource] = reactExports.useState(null);
213556
+ const [obsCapUsd, setObsCapUsd] = reactExports.useState(1);
213557
+ const [obsSaved, setObsSaved] = reactExports.useState(false);
213536
213558
  const loadProfiles = async () => {
213537
213559
  const data = await window.worker.listProfiles();
213538
213560
  setProfileList(data);
213539
213561
  setActiveProfileId(data.activeProfile);
213540
213562
  };
213563
+ const loadObserver = async () => {
213564
+ try {
213565
+ const o = await window.worker.getObserverSettings();
213566
+ setObsEnabled(o.enabled);
213567
+ setObsHasKey(o.hasApiKey);
213568
+ setObsKeySource(o.keySource);
213569
+ setObsCapUsd(o.dailyCapUsd);
213570
+ setObsApiKey("");
213571
+ } catch {
213572
+ }
213573
+ };
213541
213574
  reactExports.useEffect(() => {
213542
213575
  if (open) {
213543
213576
  loadProfiles();
213577
+ loadObserver();
213544
213578
  setEditingId(null);
213545
213579
  setSaved(false);
213580
+ setObsSaved(false);
213546
213581
  window.worker.getVersion().then(setVersion).catch(() => {
213547
213582
  });
213548
213583
  }
213549
213584
  }, [open]);
213585
+ const handleObserverSave = async () => {
213586
+ const data = {
213587
+ enabled: obsEnabled,
213588
+ dailyCapUsd: Math.max(0.05, obsCapUsd) || 1
213589
+ };
213590
+ if (obsApiKey.trim()) {
213591
+ data.anthropicApiKey = obsApiKey.trim();
213592
+ }
213593
+ const o = await window.worker.setObserverSettings(data);
213594
+ setObsHasKey(o.hasApiKey);
213595
+ setObsKeySource(o.keySource);
213596
+ setObsApiKey("");
213597
+ setObsSaved(true);
213598
+ setTimeout(() => setObsSaved(false), 900);
213599
+ };
213550
213600
  const startEditing = (profile) => {
213551
213601
  setEditingId(profile.id);
213552
213602
  setName(profile.name);
@@ -213716,6 +213766,51 @@ function SettingsDialog({ open, onClose }) {
213716
213766
  ] })
213717
213767
  ] })
213718
213768
  ),
213769
+ !editingId && // ─── Observer (global) ─────────────────
213770
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "settings-section", children: [
213771
+ /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { children: "Observer" }),
213772
+ /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "settings-hint", children: "Reviews agent sessions for assumptions, unverified claims, and dependency/license risk, tracks time per work item, and posts a session digest to the project's Agent Datastore page." }),
213773
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "settings-checkbox", children: [
213774
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
213775
+ "input",
213776
+ {
213777
+ type: "checkbox",
213778
+ checked: obsEnabled,
213779
+ onChange: (e) => setObsEnabled(e.target.checked)
213780
+ }
213781
+ ),
213782
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Enable Observer" }),
213783
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "settings-hint", children: "Applies to newly started agent tabs. Advisory only — never blocks or slows the agent." })
213784
+ ] }),
213785
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { children: [
213786
+ "Anthropic API Key",
213787
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
213788
+ "input",
213789
+ {
213790
+ type: "password",
213791
+ value: obsApiKey,
213792
+ onChange: (e) => setObsApiKey(e.target.value),
213793
+ placeholder: obsKeySource === "settings" ? "***configured*** (leave blank to keep)" : obsKeySource === "env" ? "using ANTHROPIC_API_KEY from environment" : "sk-ant-…"
213794
+ }
213795
+ ),
213796
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "settings-hint", children: "Your own Anthropic key — separate from the ctlsurf profile key. Without one, the Observer still records the session ledger, Tier-0 tags, and spans, but skips model review and digests." })
213797
+ ] }),
213798
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { children: [
213799
+ "Daily budget cap (USD)",
213800
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
213801
+ "input",
213802
+ {
213803
+ type: "number",
213804
+ min: 0.05,
213805
+ step: 0.25,
213806
+ value: obsCapUsd,
213807
+ onChange: (e) => setObsCapUsd(parseFloat(e.target.value) || 1)
213808
+ }
213809
+ ),
213810
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "settings-hint", children: "Model review pauses for the day once spend reaches the cap; Tier-0 tagging and spans continue." })
213811
+ ] }),
213812
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "settings-actions", children: /* @__PURE__ */ jsxRuntimeExports.jsx("button", { className: "btn-primary", onClick: handleObserverSave, children: obsSaved ? "Saved!" : "Save Observer Settings" }) })
213813
+ ] }),
213719
213814
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "settings-section settings-about", children: [
213720
213815
  /* @__PURE__ */ jsxRuntimeExports.jsx("h4", { children: "About" }),
213721
213816
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "about-name", children: [
@@ -214070,6 +214165,232 @@ function TicketPane({ onSendToTerminal }) {
214070
214165
  ] })
214071
214166
  ] });
214072
214167
  }
214168
+ const SENSITIVITY_LEVELS = [
214169
+ { value: "severe", label: "Severe", hint: "Only high/critical findings — near silence" },
214170
+ { value: "balanced", label: "Balanced", hint: "Warn and above — clear signals only" },
214171
+ { value: "all", label: "All signals", hint: "Everything, including low-confidence observations" }
214172
+ ];
214173
+ const SEVERITY_COLORS = {
214174
+ info: "#7aa2f7",
214175
+ warn: "#e0af68",
214176
+ high: "#ff9e64",
214177
+ critical: "#f7768e"
214178
+ };
214179
+ const DIGEST_COLOR = "#bb9af7";
214180
+ function EyeIcon({ size: size2 = 16 }) {
214181
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
214182
+ "svg",
214183
+ {
214184
+ viewBox: "0 0 24 24",
214185
+ width: size2,
214186
+ height: size2,
214187
+ fill: "none",
214188
+ stroke: "currentColor",
214189
+ strokeWidth: "2",
214190
+ strokeLinecap: "round",
214191
+ strokeLinejoin: "round",
214192
+ "aria-hidden": "true",
214193
+ children: [
214194
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
214195
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "3" })
214196
+ ]
214197
+ }
214198
+ );
214199
+ }
214200
+ function formatTime(iso) {
214201
+ const d = new Date(iso);
214202
+ if (Number.isNaN(d.getTime())) return "";
214203
+ return d.toLocaleTimeString("en-US", { hour: "numeric", minute: "2-digit" });
214204
+ }
214205
+ function Chip({ color, label }) {
214206
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "obs-chip", style: { color, borderColor: `${color}55`, background: `${color}14` }, children: [
214207
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-chip-dot", style: { background: color } }),
214208
+ label
214209
+ ] });
214210
+ }
214211
+ function FindingCard({ item }) {
214212
+ const [expanded2, setExpanded] = reactExports.useState(false);
214213
+ const color = SEVERITY_COLORS[item.severity || "info"] || SEVERITY_COLORS.info;
214214
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
214215
+ "button",
214216
+ {
214217
+ type: "button",
214218
+ className: "obs-card",
214219
+ style: { borderLeftColor: color },
214220
+ onClick: () => setExpanded((v2) => !v2),
214221
+ "aria-expanded": expanded2,
214222
+ children: [
214223
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "obs-card-top", children: [
214224
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Chip, { color, label: item.severity || "info" }),
214225
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-card-cat", children: (item.category || "").replace(/_/g, " ") }),
214226
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-card-time", children: formatTime(item.ts) })
214227
+ ] }),
214228
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "obs-card-title", children: item.title }),
214229
+ expanded2 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "obs-card-body", children: [
214230
+ item.detail && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: item.detail }),
214231
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "obs-card-facts", children: [
214232
+ typeof item.confidence === "number" && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "obs-fact", children: [
214233
+ Math.round(item.confidence * 100),
214234
+ "% confidence"
214235
+ ] }),
214236
+ typeof item.tier === "number" && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "obs-fact", children: [
214237
+ "tier ",
214238
+ item.tier
214239
+ ] }),
214240
+ item.receipts && item.receipts.length > 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-fact", children: item.receipts.join(" · ") })
214241
+ ] })
214242
+ ] }),
214243
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `obs-card-caret ${expanded2 ? "open" : ""}`, "aria-hidden": "true", children: "▸" })
214244
+ ]
214245
+ }
214246
+ );
214247
+ }
214248
+ function DigestCard({ item }) {
214249
+ const [expanded2, setExpanded] = reactExports.useState(true);
214250
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs(
214251
+ "button",
214252
+ {
214253
+ type: "button",
214254
+ className: "obs-card",
214255
+ style: { borderLeftColor: DIGEST_COLOR },
214256
+ onClick: () => setExpanded((v2) => !v2),
214257
+ "aria-expanded": expanded2,
214258
+ children: [
214259
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "obs-card-top", children: [
214260
+ /* @__PURE__ */ jsxRuntimeExports.jsx(Chip, { color: DIGEST_COLOR, label: "digest" }),
214261
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-card-time", children: formatTime(item.ts) })
214262
+ ] }),
214263
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "obs-card-title", children: item.title }),
214264
+ expanded2 && item.detail && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "obs-card-body", children: /* @__PURE__ */ jsxRuntimeExports.jsx("p", { children: item.detail }) }),
214265
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `obs-card-caret ${expanded2 ? "open" : ""}`, "aria-hidden": "true", children: "▸" })
214266
+ ]
214267
+ }
214268
+ );
214269
+ }
214270
+ function ObserverPane() {
214271
+ const [snapshot, setSnapshot] = reactExports.useState(null);
214272
+ const [toggling, setToggling] = reactExports.useState(false);
214273
+ const [reviewing, setReviewing] = reactExports.useState(false);
214274
+ const refresh = reactExports.useCallback(async () => {
214275
+ try {
214276
+ const s = await window.worker.getObserverFeed();
214277
+ setSnapshot(s);
214278
+ setReviewing(s.reviewing);
214279
+ } catch {
214280
+ }
214281
+ }, []);
214282
+ reactExports.useEffect(() => {
214283
+ void refresh();
214284
+ const unsub = window.worker.onObserverUpdate((item) => {
214285
+ setSnapshot((prev) => prev ? { ...prev, items: [...prev.items.filter((i2) => i2.id !== item.id), item].slice(-200) } : prev);
214286
+ });
214287
+ const unsubActivity = window.worker.onObserverActivity(setReviewing);
214288
+ const unsubCwd = window.worker.onCwdChanged(() => void refresh());
214289
+ return () => {
214290
+ unsub();
214291
+ unsubActivity();
214292
+ unsubCwd();
214293
+ };
214294
+ }, [refresh]);
214295
+ const handleToggle = reactExports.useCallback(async (enabled2) => {
214296
+ if (toggling) return;
214297
+ setToggling(true);
214298
+ try {
214299
+ const s = await window.worker.toggleObserver(enabled2);
214300
+ setSnapshot(s);
214301
+ } finally {
214302
+ setToggling(false);
214303
+ }
214304
+ }, [toggling]);
214305
+ const handleSensitivity = reactExports.useCallback(async (level) => {
214306
+ const current = snapshot;
214307
+ if (!current || current.sensitivity === level) return;
214308
+ setSnapshot({ ...current, sensitivity: level });
214309
+ try {
214310
+ await window.worker.setObserverSettings({ enabled: current.enabled, sensitivity: level });
214311
+ } catch {
214312
+ void refresh();
214313
+ }
214314
+ }, [snapshot, refresh]);
214315
+ const enabled = snapshot?.enabled ?? false;
214316
+ const items = [...snapshot?.items || []].reverse();
214317
+ const findings = items.filter((i2) => i2.kind === "finding");
214318
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ticket-pane observer-pane", role: "region", "aria-label": "Observer", children: [
214319
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ticket-drawer-header", children: [
214320
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ticket-drawer-heading", children: [
214321
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: `ticket-drawer-badge obs-badge ${reviewing && enabled ? "reviewing" : ""}`, children: /* @__PURE__ */ jsxRuntimeExports.jsx(EyeIcon, { size: 16 }) }),
214322
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ticket-drawer-headtext", children: [
214323
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-drawer-title", children: "Observer" }),
214324
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-drawer-subtitle", children: !snapshot ? "loading…" : !enabled ? "off" : !snapshot.hasApiKey ? /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-drawer-warn", children: "no Anthropic API key — Tier 0 only (add in Settings)" }) : snapshot.observing.length === 0 ? "on — waiting for an agent tab" : /* @__PURE__ */ jsxRuntimeExports.jsxs(jsxRuntimeExports.Fragment, { children: [
214325
+ "watching ",
214326
+ /* @__PURE__ */ jsxRuntimeExports.jsx("strong", { children: snapshot.observing.map((o) => o.agentName).join(", ") })
214327
+ ] }) })
214328
+ ] })
214329
+ ] }),
214330
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("label", { className: "observer-switch", title: enabled ? "Turn Observer off" : "Turn Observer on", children: [
214331
+ /* @__PURE__ */ jsxRuntimeExports.jsx(
214332
+ "input",
214333
+ {
214334
+ type: "checkbox",
214335
+ checked: enabled,
214336
+ disabled: toggling || !snapshot,
214337
+ onChange: (e) => void handleToggle(e.target.checked)
214338
+ }
214339
+ ),
214340
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "observer-switch-track", children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "observer-switch-thumb" }) })
214341
+ ] })
214342
+ ] }),
214343
+ enabled && snapshot && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "obs-toolbar", children: [
214344
+ /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "obs-sensitivity", role: "radiogroup", "aria-label": "Detection threshold", children: SENSITIVITY_LEVELS.map((l2) => /* @__PURE__ */ jsxRuntimeExports.jsx(
214345
+ "button",
214346
+ {
214347
+ type: "button",
214348
+ className: `obs-sens-btn ${snapshot.sensitivity === l2.value ? "active" : ""}`,
214349
+ title: l2.hint,
214350
+ "aria-pressed": snapshot.sensitivity === l2.value,
214351
+ onClick: () => void handleSensitivity(l2.value),
214352
+ children: l2.label
214353
+ },
214354
+ l2.value
214355
+ )) }),
214356
+ reviewing && /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "obs-reviewing", "aria-live": "polite", children: [
214357
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-reviewing-dot" }),
214358
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-reviewing-dot" }),
214359
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-reviewing-dot" }),
214360
+ "reviewing"
214361
+ ] })
214362
+ ] }),
214363
+ /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ticket-list-body obs-feed", children: [
214364
+ !enabled && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ticket-empty", children: [
214365
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-empty-icon", children: /* @__PURE__ */ jsxRuntimeExports.jsx(EyeIcon, { size: 26 }) }),
214366
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-empty-title", children: "Observer is off" }),
214367
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-empty-hint", children: "Flip the switch to review this session for assumptions, unverified claims, and dependency/license risk each time the agent hands control back to you." })
214368
+ ] }),
214369
+ enabled && items.length === 0 && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ticket-empty", children: [
214370
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-empty-icon", children: /* @__PURE__ */ jsxRuntimeExports.jsx(EyeIcon, { size: 26 }) }),
214371
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-empty-title", children: "Nothing yet" }),
214372
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "ticket-empty-hint", children: "Reviews run when the agent finishes a turn. Results land here." })
214373
+ ] }),
214374
+ enabled && items.map((item) => {
214375
+ if (item.kind === "finding") return /* @__PURE__ */ jsxRuntimeExports.jsx(FindingCard, { item }, item.id);
214376
+ if (item.kind === "digest") return /* @__PURE__ */ jsxRuntimeExports.jsx(DigestCard, { item }, item.id);
214377
+ return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: `obs-line ${item.kind}`, children: [
214378
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-line-dot", "aria-hidden": "true" }),
214379
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-line-text", children: item.title }),
214380
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "obs-line-time", children: formatTime(item.ts) })
214381
+ ] }, item.id);
214382
+ })
214383
+ ] }),
214384
+ snapshot && enabled && /* @__PURE__ */ jsxRuntimeExports.jsx("div", { className: "ticket-drawer-footer", children: /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "ticket-drawer-hint", children: [
214385
+ findings.length,
214386
+ " finding",
214387
+ findings.length === 1 ? "" : "s",
214388
+ " · $",
214389
+ snapshot.spentTodayUsd.toFixed(2),
214390
+ " spent today"
214391
+ ] }) })
214392
+ ] });
214393
+ }
214073
214394
  const DEFAULT_LAYOUT = {
214074
214395
  type: "split",
214075
214396
  direction: "horizontal",
@@ -214422,7 +214743,8 @@ function App() {
214422
214743
  ] })
214423
214744
  },
214424
214745
  { id: "ctlsurf", label: "ctlsurf", content: /* @__PURE__ */ jsxRuntimeExports.jsx(CtlsurfPanel, { navigate: ctlsurfNav }) },
214425
- { id: "tickets", label: "Tickets", content: /* @__PURE__ */ jsxRuntimeExports.jsx(TicketPane, { onSendToTerminal: handleSendToTerminal }) }
214746
+ { id: "tickets", label: "Tickets", content: /* @__PURE__ */ jsxRuntimeExports.jsx(TicketPane, { onSendToTerminal: handleSendToTerminal }) },
214747
+ { id: "observer", label: "Observer", content: /* @__PURE__ */ jsxRuntimeExports.jsx(ObserverPane, {}) }
214426
214748
  ];
214427
214749
  return /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "app", children: [
214428
214750
  /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "titlebar", children: [
@@ -214479,6 +214801,36 @@ function App() {
214479
214801
  ]
214480
214802
  }
214481
214803
  ),
214804
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
214805
+ "button",
214806
+ {
214807
+ className: `titlebar-btn titlebar-icon-btn ${visiblePaneIds.includes("observer") ? "active" : ""}`,
214808
+ onClick: () => togglePane("observer"),
214809
+ title: "Toggle Observer pane — live session review",
214810
+ "aria-label": "Observer",
214811
+ children: [
214812
+ /* @__PURE__ */ jsxRuntimeExports.jsxs(
214813
+ "svg",
214814
+ {
214815
+ viewBox: "0 0 24 24",
214816
+ width: "13",
214817
+ height: "13",
214818
+ fill: "none",
214819
+ stroke: "currentColor",
214820
+ strokeWidth: "2",
214821
+ strokeLinecap: "round",
214822
+ strokeLinejoin: "round",
214823
+ "aria-hidden": "true",
214824
+ children: [
214825
+ /* @__PURE__ */ jsxRuntimeExports.jsx("path", { d: "M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z" }),
214826
+ /* @__PURE__ */ jsxRuntimeExports.jsx("circle", { cx: "12", cy: "12", r: "3" })
214827
+ ]
214828
+ }
214829
+ ),
214830
+ /* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: "Observer" })
214831
+ ]
214832
+ }
214833
+ ),
214482
214834
  /* @__PURE__ */ jsxRuntimeExports.jsx(
214483
214835
  "button",
214484
214836
  {