clearotron 0.3.0-beta.2 → 0.3.0-beta.4

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 (40) hide show
  1. package/INSTALL.md +32 -6
  2. package/bin/connect.mjs +68 -25
  3. package/bin/disconnect.mjs +16 -11
  4. package/bin/onboard.mjs +65 -6
  5. package/bin/start.mjs +7 -1
  6. package/build-info.json +2 -2
  7. package/driver/CHANGELOG.md +38 -0
  8. package/driver/driver.config.mjs +5 -0
  9. package/driver/engine/anthropic-agent.mjs +34 -17
  10. package/driver/gateway.mjs +76 -15
  11. package/driver/package.json +1 -1
  12. package/driver/portal-service.mjs +1 -1
  13. package/driver/profile-service.mjs +31 -3
  14. package/driver/publish/index.mjs +12 -9
  15. package/driver/publish/knockout.mjs +4 -2
  16. package/driver/publish/office-record-links.mjs +56 -21
  17. package/driver/recipe-service.mjs +14 -5
  18. package/driver/record-origins.mjs +14 -0
  19. package/driver/suite-census.json +34 -28
  20. package/mcp-server/CHANGELOG.md +8 -0
  21. package/mcp-server/lib/driver.mjs +2 -0
  22. package/mcp-server/lib/knockout.mjs +2 -2
  23. package/mcp-server/lib/options.mjs +9 -2
  24. package/mcp-server/package.json +1 -1
  25. package/package.json +1 -1
  26. package/portal-ui/dist/assets/{index-CsCuPshD.css → index-Cv-E_agg.css} +199 -86
  27. package/portal-ui/dist/assets/{index-CcFjgM78.js → index-DWYCsOCJ.js} +514 -380
  28. package/portal-ui/dist/index.html +2 -2
  29. package/portal-ui/package.json +1 -1
  30. package/providers/clarivate/src/core.js +5 -0
  31. package/providers/oauth-mcp-bridge/CHANGELOG.md +8 -0
  32. package/providers/oauth-mcp-bridge/package.json +1 -1
  33. package/scripts/e2e-unread-terminals.mjs +1 -1
  34. package/scripts/e2e.mjs +114 -9
  35. package/scripts/revisit-render-check.mjs +22 -4
  36. package/scripts/travelling-predicates.mjs +1 -1
  37. package/shared/connect-clients.mjs +282 -321
  38. package/shared/names-in-force.mjs +1 -0
  39. package/shared/stdio-connect.mjs +63 -0
  40. package/shared/store-in-repo.mjs +50 -2
@@ -10764,7 +10764,33 @@ var api = {
10764
10764
  ...asString(r["sub"]) ? { sub: asString(r["sub"]) } : {},
10765
10765
  ...asString(r["verifiedOn"]) ? { verifiedOn: asString(r["verifiedOn"]) } : {},
10766
10766
  ...asString(r["by"]) ? { by: asString(r["by"]) } : {},
10767
- steps: asArray(r["steps"]).filter((x) => typeof x === "string" && x !== ""),
10767
+ steps: asArray(r["steps"]).flatMap((x) => {
10768
+ const s = asRecord(x);
10769
+ const text = asString(s["text"]);
10770
+ if (!text) return [];
10771
+ const hint = asString(s["hint"]);
10772
+ const c = s["copy"] == null ? null : asRecord(s["copy"]);
10773
+ let copy;
10774
+ if (c) {
10775
+ const kind = asString(c["kind"]);
10776
+ if (kind === "block" && asString(c["text"])) copy = {
10777
+ kind,
10778
+ text: asString(c["text"])
10779
+ };
10780
+ else if (kind === "secret" && asString(c["label"]) && asString(c["template"]) && asString(c["slot"]) && asString(c["template"]).includes(asString(c["slot"]))) copy = {
10781
+ kind,
10782
+ label: asString(c["label"]),
10783
+ template: asString(c["template"]),
10784
+ slot: asString(c["slot"])
10785
+ };
10786
+ else return [];
10787
+ }
10788
+ return [{
10789
+ text,
10790
+ ...hint ? { hint } : {},
10791
+ ...copy ? { copy } : {}
10792
+ }];
10793
+ }),
10768
10794
  launch: (() => {
10769
10795
  const u = asString(asRecord(r["launch"])["url"]);
10770
10796
  return u && /^https:\/\//.test(u) ? { url: u } : null;
@@ -11018,14 +11044,14 @@ var NAV = [
11018
11044
  label: "Admin settings",
11019
11045
  path: "/portal/admin",
11020
11046
  icon: "settings",
11021
- needs: "manage",
11047
+ needs: "everything",
11022
11048
  hidden: true,
11023
11049
  children: [{
11024
11050
  id: "admin.config",
11025
11051
  label: "Global config",
11026
11052
  path: "/portal/admin/config",
11027
11053
  icon: "server",
11028
- needs: "manage"
11054
+ needs: "everything"
11029
11055
  }]
11030
11056
  },
11031
11057
  {
@@ -11036,7 +11062,8 @@ var NAV = [
11036
11062
  hidden: true
11037
11063
  }
11038
11064
  ];
11039
- var visible = (e, who) => !e.needs || who.permissions[e.needs];
11065
+ var holds = (who, gate) => gate === "everything" ? who.allAccounts === true : who.permissions[gate];
11066
+ var visible = (e, who) => !e.needs || holds(who, e.needs);
11040
11067
  function navFor(who, entries = NAV) {
11041
11068
  return entries.filter((e) => visible(e, who) && !e.hidden).map((e) => e.children ? {
11042
11069
  ...e,
@@ -11148,6 +11175,7 @@ var PATHS = {
11148
11175
  bookmark: "M19 21l-7-5-7 5V5a2 2 0 0 1 2-2h10a2 2 0 0 1 2 2Z",
11149
11176
  sliders: "M4 21v-7M4 10V3M12 21v-9M12 8V3M20 21v-5M20 12V3M1 14h6M9 8h6M17 16h6",
11150
11177
  server: "M20 2H4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V4a2 2 0 0 0-2-2ZM20 14H4a2 2 0 0 0-2 2v4a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2v-4a2 2 0 0 0-2-2ZM6 6h.01M6 18h.01",
11178
+ laptop: "M20 16V7a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v9m16 0H4m16 0 1.28 2.55a1 1 0 0 1-.9 1.45H3.62a1 1 0 0 1-.9-1.45L4 16",
11151
11179
  menu: "M3 12h18M3 6h18M3 18h18",
11152
11180
  x: "M18 6 6 18M6 6l12 12",
11153
11181
  chevron: "m9 18 6-6-6-6",
@@ -11155,6 +11183,7 @@ var PATHS = {
11155
11183
  "chevron-right": "m9 18 6-6-6-6",
11156
11184
  "grip-vertical": "M9 5h.01M15 5h.01M9 12h.01M15 12h.01M9 19h.01M15 19h.01",
11157
11185
  "arrow-right": "M5 12h14M13 6l6 6-6 6",
11186
+ "arrow-left": "M19 12H5M11 18l-6-6 6-6",
11158
11187
  trash: "M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6M10 11v6M14 11v6",
11159
11188
  search: "M11 19a8 8 0 1 0 0-16 8 8 0 0 0 0 16ZM21 21l-4.3-4.3",
11160
11189
  eye: "M2 12s4-7 10-7 10 7 10 7-4 7-10 7-10-7-10-7ZM12 15a3 3 0 1 0 0-6 3 3 0 0 0 0 6Z",
@@ -11486,6 +11515,157 @@ function accessSentence(input) {
11486
11515
  return limits.length ? `${first} They ${limits.join(", and ")}.` : first;
11487
11516
  }
11488
11517
  //#endregion
11518
+ //#region src/shell/permissions.ts
11519
+ function canManage(who) {
11520
+ return who.permissions.manage;
11521
+ }
11522
+ function canRun(who) {
11523
+ return who.permissions.run;
11524
+ }
11525
+ function seesEverything(who) {
11526
+ return who.allAccounts === true;
11527
+ }
11528
+ //#endregion
11529
+ //#region src/shell/CompanyPicker.tsx
11530
+ function CompanyCard({ row, onPick }) {
11531
+ return (0, import_jsx_runtime.jsxs)("button", {
11532
+ type: "button",
11533
+ className: row.generic ? "entry-card pick-generic" : "entry-card",
11534
+ onClick: onPick,
11535
+ style: {
11536
+ flexDirection: "row",
11537
+ alignItems: "center",
11538
+ gap: 16,
11539
+ padding: "15px 17px"
11540
+ },
11541
+ children: [(0, import_jsx_runtime.jsxs)("span", {
11542
+ style: {
11543
+ minWidth: 0,
11544
+ flex: 1,
11545
+ textAlign: "left"
11546
+ },
11547
+ children: [(0, import_jsx_runtime.jsxs)("span", {
11548
+ className: "entry-title",
11549
+ style: {
11550
+ display: "block",
11551
+ marginBottom: 2
11552
+ },
11553
+ children: [row.name, row.generic ? (0, import_jsx_runtime.jsx)("span", {
11554
+ className: "pill",
11555
+ style: {
11556
+ marginLeft: 8,
11557
+ verticalAlign: "middle",
11558
+ background: "transparent",
11559
+ borderColor: "var(--accent-ink)",
11560
+ color: "var(--text-accent)"
11561
+ },
11562
+ children: "Default"
11563
+ }) : null]
11564
+ }), (0, import_jsx_runtime.jsx)("span", {
11565
+ className: "entry-body",
11566
+ style: {
11567
+ display: "block",
11568
+ overflow: "hidden",
11569
+ textOverflow: "ellipsis",
11570
+ whiteSpace: "nowrap"
11571
+ },
11572
+ children: row.line
11573
+ })]
11574
+ }), (0, import_jsx_runtime.jsx)("span", {
11575
+ "aria-hidden": "true",
11576
+ style: {
11577
+ flex: "none",
11578
+ color: "var(--text-faint)",
11579
+ display: "inline-flex"
11580
+ },
11581
+ children: (0, import_jsx_runtime.jsx)(Icon, {
11582
+ name: "arrow-right",
11583
+ size: 17
11584
+ })
11585
+ })]
11586
+ });
11587
+ }
11588
+ function CompanyPicker({ eyebrow, heading, line, keys, orgOf, organisations, companyName, factsFor, onPick, onAdd }) {
11589
+ const { headings, groups } = pickerGroups(keys, orgOf, organisations, companyName, factsFor);
11590
+ return (0, import_jsx_runtime.jsxs)("div", {
11591
+ className: "screen",
11592
+ children: [(0, import_jsx_runtime.jsx)("div", {
11593
+ className: "eyebrow",
11594
+ children: eyebrow
11595
+ }), (0, import_jsx_runtime.jsxs)("div", {
11596
+ className: "measure",
11597
+ children: [(0, import_jsx_runtime.jsxs)("div", {
11598
+ style: {
11599
+ display: "flex",
11600
+ alignItems: "flex-end",
11601
+ gap: 20,
11602
+ margin: "4px 0 18px"
11603
+ },
11604
+ children: [(0, import_jsx_runtime.jsxs)("div", {
11605
+ style: { flex: 1 },
11606
+ children: [(0, import_jsx_runtime.jsx)("h1", {
11607
+ style: {
11608
+ fontSize: 27,
11609
+ margin: "0 0 4px",
11610
+ color: "var(--text-strong)"
11611
+ },
11612
+ children: heading
11613
+ }), (0, import_jsx_runtime.jsx)("p", {
11614
+ style: {
11615
+ margin: 0,
11616
+ color: "var(--text-muted)",
11617
+ fontSize: 14.5
11618
+ },
11619
+ children: line
11620
+ })]
11621
+ }), onAdd ? (0, import_jsx_runtime.jsx)("button", {
11622
+ type: "button",
11623
+ className: "start-pill",
11624
+ onClick: onAdd,
11625
+ style: {
11626
+ flex: "none",
11627
+ borderColor: "var(--accent-ink)",
11628
+ color: "var(--text-accent)",
11629
+ fontWeight: 700
11630
+ },
11631
+ children: "+ New company"
11632
+ }) : null]
11633
+ }), groups.map((g, i) => (0, import_jsx_runtime.jsxs)("div", { children: [headings && g.org ? (0, import_jsx_runtime.jsx)("div", {
11634
+ className: "eyebrow",
11635
+ style: { margin: i === 0 ? "0 0 8px" : "16px 0 8px" },
11636
+ "data-anon": "mark",
11637
+ children: g.org.name
11638
+ }) : null, (0, import_jsx_runtime.jsx)("div", {
11639
+ style: {
11640
+ display: "flex",
11641
+ flexDirection: "column",
11642
+ gap: 10,
11643
+ marginTop: !headings && i > 0 ? 10 : 0
11644
+ },
11645
+ children: g.rows.map((r) => (0, import_jsx_runtime.jsx)(CompanyCard, {
11646
+ row: r,
11647
+ onPick: () => onPick(r.key)
11648
+ }, r.key))
11649
+ })] }, g.org?.key ?? ""))]
11650
+ })]
11651
+ });
11652
+ }
11653
+ function CompanyGate({ ctx, eyebrow, heading, line }) {
11654
+ return (0, import_jsx_runtime.jsx)(CompanyPicker, {
11655
+ eyebrow,
11656
+ heading,
11657
+ line,
11658
+ keys: ctx.ownerKeys,
11659
+ orgOf: ctx.orgOf,
11660
+ organisations: ctx.organisations,
11661
+ companyName: ctx.ownerName,
11662
+ factsFor: ctx.factsFor,
11663
+ onPick: (key) => ctx.setOwner(key),
11664
+ onAdd: canManage(ctx.me) ? () => ctx.go(NEW_COMPANY_PATH) : void 0
11665
+ });
11666
+ }
11667
+ var NEW_COMPANY_PATH = "/portal/brand/new";
11668
+ //#endregion
11489
11669
  //#region src/shell/AppShell.tsx
11490
11670
  var MOBILE = "(max-width: 899px)";
11491
11671
  function useIsMobile() {
@@ -11740,7 +11920,8 @@ function AppShell({ render }) {
11740
11920
  }), (0, import_jsx_runtime.jsx)(BrandOwnerSwitcher, {
11741
11921
  grouped,
11742
11922
  value: ownerInView,
11743
- onChange: setOwnerGuarded
11923
+ onChange: setOwnerGuarded,
11924
+ onAdd: canManage(me) ? () => go(NEW_COMPANY_PATH) : void 0
11744
11925
  })]
11745
11926
  }), (0, import_jsx_runtime.jsx)(NavList, {
11746
11927
  entries: groups.owner,
@@ -11908,14 +12089,15 @@ function AppShell({ render }) {
11908
12089
  ]
11909
12090
  });
11910
12091
  }
11911
- function BrandOwnerSwitcher({ grouped, value, onChange }) {
12092
+ var NEW_COMPANY_OPTION = ":new-company";
12093
+ function BrandOwnerSwitcher({ grouped, value, onChange, onAdd }) {
11912
12094
  const option = (r) => (0, import_jsx_runtime.jsx)("option", {
11913
12095
  value: r.key,
11914
12096
  children: switcherLabel(r)
11915
12097
  }, r.key);
11916
12098
  return (0, import_jsx_runtime.jsxs)("select", {
11917
12099
  value: value ?? "",
11918
- onChange: (e) => onChange(e.target.value || null),
12100
+ onChange: (e) => e.target.value === NEW_COMPANY_OPTION ? onAdd?.() : onChange(e.target.value || null),
11919
12101
  "aria-label": "Company",
11920
12102
  style: {
11921
12103
  width: "100%",
@@ -11928,13 +12110,21 @@ function BrandOwnerSwitcher({ grouped, value, onChange }) {
11928
12110
  fontWeight: 700,
11929
12111
  color: "var(--text-strong)"
11930
12112
  },
11931
- children: [(0, import_jsx_runtime.jsx)("option", {
11932
- value: "",
11933
- children: ALL_OWNERS
11934
- }), grouped.groups.map((g) => grouped.headings && g.org ? (0, import_jsx_runtime.jsx)("optgroup", {
11935
- label: g.org.name,
11936
- children: g.rows.map(option)
11937
- }, g.org.key) : g.rows.map(option))]
12113
+ children: [
12114
+ (0, import_jsx_runtime.jsx)("option", {
12115
+ value: "",
12116
+ children: ALL_OWNERS
12117
+ }),
12118
+ grouped.groups.map((g) => grouped.headings && g.org ? (0, import_jsx_runtime.jsx)("optgroup", {
12119
+ label: g.org.name,
12120
+ children: g.rows.map(option)
12121
+ }, g.org.key) : g.rows.map(option)),
12122
+ onAdd ? (0, import_jsx_runtime.jsx)("option", {
12123
+ value: NEW_COMPANY_OPTION,
12124
+ "data-action": "new-company",
12125
+ children: "+ New company"
12126
+ }) : null
12127
+ ]
11938
12128
  });
11939
12129
  }
11940
12130
  var initials = (email) => {
@@ -12251,14 +12441,6 @@ function moveBefore(order, id, over) {
12251
12441
  return next;
12252
12442
  }
12253
12443
  //#endregion
12254
- //#region src/shell/permissions.ts
12255
- function canManage(who) {
12256
- return who.permissions.manage;
12257
- }
12258
- function canRun(who) {
12259
- return who.permissions.run;
12260
- }
12261
- //#endregion
12262
12444
  //#region src/screens/Home.tsx
12263
12445
  var TERMINAL$1 = new Set([
12264
12446
  "delivered",
@@ -13016,11 +13198,15 @@ function Clearances({ ctx }) {
13016
13198
  const wanted = new URLSearchParams(window.location.search).get("owner");
13017
13199
  if (wanted && wanted !== ctx.owner) ctx.setOwner(wanted);
13018
13200
  }, [ctx]);
13019
- const account = ownerFilter ?? (ctx.me.allAccounts ? "*" : ctx.me.accounts.length === 1 ? ctx.me.accounts[0] : null);
13020
- const { result: famResult, reload: reloadFamilies } = useLoad(() => api.families(account), [account]);
13201
+ const seesAll = ctx.me.allAccounts;
13202
+ const account = ownerFilter ?? (seesAll ? "*" : ctx.me.accounts.length === 1 ? ctx.me.accounts[0] : null);
13203
+ const { result: famResult, reload: reloadFamilies } = useLoad(() => seesAll ? api.families(account) : Promise.resolve({
13204
+ kind: "ok",
13205
+ value: NO_FAMILIES
13206
+ }), [account, seesAll]);
13021
13207
  const families = famResult?.kind === "ok" ? famResult.value : NO_FAMILIES;
13022
13208
  const [picked, setPicked] = (0, import_react.useState)(new Set());
13023
- const canGroup = canManage(ctx.me);
13209
+ const canGroup = canManage(ctx.me) && seesAll;
13024
13210
  const [showRetired, setShowRetired] = (0, import_react.useState)(false);
13025
13211
  const { result: retiredResult, reload: reloadRetired } = useLoad(() => canGroup ? api.retiredRuns(account) : Promise.resolve({ kind: "notFound" }), [account, canGroup]);
13026
13212
  const retired = retiredResult?.kind === "ok" ? retiredResult.value : [];
@@ -15936,146 +16122,6 @@ function unsavedChanges({ current, empty, saved, submitted }) {
15936
16122
  return current !== saved;
15937
16123
  }
15938
16124
  //#endregion
15939
- //#region src/shell/CompanyPicker.tsx
15940
- function CompanyCard({ row, onPick }) {
15941
- return (0, import_jsx_runtime.jsxs)("button", {
15942
- type: "button",
15943
- className: row.generic ? "entry-card pick-generic" : "entry-card",
15944
- onClick: onPick,
15945
- style: {
15946
- flexDirection: "row",
15947
- alignItems: "center",
15948
- gap: 16,
15949
- padding: "15px 17px"
15950
- },
15951
- children: [(0, import_jsx_runtime.jsxs)("span", {
15952
- style: {
15953
- minWidth: 0,
15954
- flex: 1,
15955
- textAlign: "left"
15956
- },
15957
- children: [(0, import_jsx_runtime.jsxs)("span", {
15958
- className: "entry-title",
15959
- style: {
15960
- display: "block",
15961
- marginBottom: 2
15962
- },
15963
- children: [row.name, row.generic ? (0, import_jsx_runtime.jsx)("span", {
15964
- className: "pill",
15965
- style: {
15966
- marginLeft: 8,
15967
- verticalAlign: "middle",
15968
- background: "transparent",
15969
- borderColor: "var(--accent-ink)",
15970
- color: "var(--text-accent)"
15971
- },
15972
- children: "Default"
15973
- }) : null]
15974
- }), (0, import_jsx_runtime.jsx)("span", {
15975
- className: "entry-body",
15976
- style: {
15977
- display: "block",
15978
- overflow: "hidden",
15979
- textOverflow: "ellipsis",
15980
- whiteSpace: "nowrap"
15981
- },
15982
- children: row.line
15983
- })]
15984
- }), (0, import_jsx_runtime.jsx)("span", {
15985
- "aria-hidden": "true",
15986
- style: {
15987
- flex: "none",
15988
- color: "var(--text-faint)",
15989
- display: "inline-flex"
15990
- },
15991
- children: (0, import_jsx_runtime.jsx)(Icon, {
15992
- name: "arrow-right",
15993
- size: 17
15994
- })
15995
- })]
15996
- });
15997
- }
15998
- function CompanyPicker({ eyebrow, heading, line, keys, orgOf, organisations, companyName, factsFor, onPick, onAdd }) {
15999
- const { headings, groups } = pickerGroups(keys, orgOf, organisations, companyName, factsFor);
16000
- return (0, import_jsx_runtime.jsxs)("div", {
16001
- className: "screen",
16002
- children: [(0, import_jsx_runtime.jsx)("div", {
16003
- className: "eyebrow",
16004
- children: eyebrow
16005
- }), (0, import_jsx_runtime.jsxs)("div", {
16006
- className: "measure",
16007
- children: [(0, import_jsx_runtime.jsxs)("div", {
16008
- style: {
16009
- display: "flex",
16010
- alignItems: "flex-end",
16011
- gap: 20,
16012
- margin: "4px 0 18px"
16013
- },
16014
- children: [(0, import_jsx_runtime.jsxs)("div", {
16015
- style: { flex: 1 },
16016
- children: [(0, import_jsx_runtime.jsx)("h1", {
16017
- style: {
16018
- fontSize: 27,
16019
- margin: "0 0 4px",
16020
- color: "var(--text-strong)"
16021
- },
16022
- children: heading
16023
- }), (0, import_jsx_runtime.jsx)("p", {
16024
- style: {
16025
- margin: 0,
16026
- color: "var(--text-muted)",
16027
- fontSize: 14.5
16028
- },
16029
- children: line
16030
- })]
16031
- }), onAdd ? (0, import_jsx_runtime.jsx)("button", {
16032
- type: "button",
16033
- className: "start-pill",
16034
- onClick: onAdd,
16035
- style: {
16036
- flex: "none",
16037
- borderColor: "var(--accent-ink)",
16038
- color: "var(--text-accent)",
16039
- fontWeight: 700
16040
- },
16041
- children: "+ New company"
16042
- }) : null]
16043
- }), groups.map((g, i) => (0, import_jsx_runtime.jsxs)("div", { children: [headings && g.org ? (0, import_jsx_runtime.jsx)("div", {
16044
- className: "eyebrow",
16045
- style: { margin: i === 0 ? "0 0 8px" : "16px 0 8px" },
16046
- "data-anon": "mark",
16047
- children: g.org.name
16048
- }) : null, (0, import_jsx_runtime.jsx)("div", {
16049
- style: {
16050
- display: "flex",
16051
- flexDirection: "column",
16052
- gap: 10,
16053
- marginTop: !headings && i > 0 ? 10 : 0
16054
- },
16055
- children: g.rows.map((r) => (0, import_jsx_runtime.jsx)(CompanyCard, {
16056
- row: r,
16057
- onPick: () => onPick(r.key)
16058
- }, r.key))
16059
- })] }, g.org?.key ?? ""))]
16060
- })]
16061
- });
16062
- }
16063
- function CompanyGate({ ctx, eyebrow, heading, line }) {
16064
- return (0, import_jsx_runtime.jsx)(CompanyPicker, {
16065
- eyebrow,
16066
- heading,
16067
- line,
16068
- keys: ctx.ownerKeys,
16069
- orgOf: ctx.orgOf,
16070
- organisations: ctx.organisations,
16071
- companyName: ctx.ownerName,
16072
- factsFor: ctx.factsFor,
16073
- onPick: (key) => ctx.setOwner(key),
16074
- onAdd: canManage(ctx.me) ? () => ctx.go(NEW_COMPANY_PATH) : void 0
16075
- });
16076
- }
16077
- var NEW_COMPANY_PATH = "/portal/brand/new";
16078
- //#endregion
16079
16125
  //#region src/contract/companyCreated.ts
16080
16126
  var pending = null;
16081
16127
  function handOff(created) {
@@ -17392,7 +17438,7 @@ function NewClearance({ ctx }) {
17392
17438
  demoMode: ctx.me.engineMode === "demo",
17393
17439
  setupRoute: ctx.me.setupRoute,
17394
17440
  programDisputed: ctx.me.engineProgramDisputed,
17395
- onSettings: canManage(ctx.me) ? () => ctx.go("/portal/admin/config") : null,
17441
+ onSettings: seesEverything(ctx.me) ? () => ctx.go("/portal/admin/config") : null,
17396
17442
  saveOpen,
17397
17443
  saveName,
17398
17444
  saveText,
@@ -20023,19 +20069,19 @@ var WHAT_YOU_CAN_DO = [
20023
20069
  "Ask what-if: why a finding was rated as it was, what changes if the goods narrow"
20024
20070
  ];
20025
20071
  var COPIED_MS = 2600;
20072
+ var PLACES = ["disk", "public-http"];
20026
20073
  var WHERE = {
20027
- disk: "On this computer",
20028
- "public-http": "Somewhere else"
20029
- };
20030
- var EITHER = "either";
20031
- var placesOf = (offers) => {
20032
- const named = [...new Set(offers.map((o) => o.route ?? "public-http"))].filter((r) => r !== EITHER);
20033
- return named.length ? named : offers.length ? ["disk"] : [];
20034
- };
20035
- var servesPlace = (o, place) => {
20036
- const r = o.route ?? "public-http";
20037
- return r === place || r === EITHER;
20074
+ disk: {
20075
+ label: "Clearotron is installed on this machine (laptop/desktop)",
20076
+ icon: "laptop"
20077
+ },
20078
+ "public-http": {
20079
+ label: "Clearotron is running elsewhere (e.g. Cloud/Server)",
20080
+ icon: "server"
20081
+ }
20038
20082
  };
20083
+ var HELP_URL = "https://github.com/CordilleraSarl/clearotron/blob/main/mcp-server/CONNECT.md";
20084
+ var HELP_LINK_TEXT = "GitHub MCP Connector Documentation";
20039
20085
  async function copy(text) {
20040
20086
  try {
20041
20087
  await navigator.clipboard.writeText(text);
@@ -20045,77 +20091,121 @@ async function copy(text) {
20045
20091
  }
20046
20092
  }
20047
20093
  var mask = (key) => key.length > 3 ? `${key.slice(0, 3)}••••` : "••••";
20048
- var pasteLine = (offer) => offer.pasteAs ?? `Paste it into ${offer.name}`;
20049
- function Destination({ offer, selected, copied, onPick }) {
20050
- return (0, import_jsx_runtime.jsxs)("button", {
20051
- type: "button",
20052
- className: "ai-dest",
20053
- "data-id": offer.id,
20054
- "data-selected": selected ? "" : void 0,
20055
- "data-copied": copied ? "" : void 0,
20056
- "aria-pressed": selected,
20057
- onClick: onPick,
20058
- children: [(0, import_jsx_runtime.jsxs)("span", {
20059
- className: "ai-dest-name",
20060
- children: [offer.name, offer.sub ? (0, import_jsx_runtime.jsx)("span", {
20061
- className: "ai-dest-sub",
20062
- children: offer.sub
20063
- }) : null]
20064
- }), (0, import_jsx_runtime.jsxs)("span", {
20065
- className: "ai-dest-say",
20066
- children: [(0, import_jsx_runtime.jsx)("span", {
20067
- className: "ai-dest-idle",
20068
- children: pasteLine(offer)
20069
- }), (0, import_jsx_runtime.jsx)("span", {
20070
- className: "ai-dest-done",
20071
- children: "✓ Copied"
20072
- })]
20073
- })]
20074
- });
20075
- }
20076
- function Panel({ offer, landed }) {
20094
+ var fill = (c, value) => c.template.split(c.slot).join(value);
20095
+ function Marked({ text }) {
20096
+ const parts = text.split(/(\*\*[^*]+\*\*|`[^`]+`)/g).filter((p) => p !== "");
20097
+ return (0, import_jsx_runtime.jsx)(import_jsx_runtime.Fragment, { children: parts.map((p, n) => p.length > 4 && p.startsWith("**") && p.endsWith("**") ? (0, import_jsx_runtime.jsx)("b", { children: p.slice(2, -2) }, n) : p.length > 2 && p.startsWith("`") && p.endsWith("`") ? (0, import_jsx_runtime.jsx)("code", {
20098
+ className: "ai-code",
20099
+ children: p.slice(1, -1)
20100
+ }, n) : (0, import_jsx_runtime.jsx)("span", { children: p }, n)) });
20101
+ }
20102
+ var AT_REST = {
20103
+ copiedAt: null,
20104
+ landedAt: null,
20105
+ landed: null,
20106
+ revealedAt: null,
20107
+ revealed: null
20108
+ };
20109
+ function StepsPanel({ offer, measuring = false, state = AT_REST, onBlock, onSecret }) {
20077
20110
  return (0, import_jsx_runtime.jsxs)("div", {
20078
- className: "ai-panel",
20079
- "data-for": offer.id,
20111
+ className: "steps-panel",
20112
+ "data-for": measuring ? void 0 : offer.id,
20080
20113
  children: [
20114
+ (0, import_jsx_runtime.jsx)("div", {
20115
+ className: "eyebrow",
20116
+ children: "Steps for"
20117
+ }),
20081
20118
  (0, import_jsx_runtime.jsx)("h3", {
20082
- className: "ai-panel-head",
20083
- children: pasteLine(offer)
20119
+ className: "steps-name",
20120
+ children: offer.name
20084
20121
  }),
20085
- landed ? (0, import_jsx_runtime.jsxs)("p", {
20086
- className: "ai-panel-landed",
20087
- children: ["On your clipboard now: ", (0, import_jsx_runtime.jsx)("code", {
20088
- className: "mono",
20089
- children: landed
20090
- })]
20091
- }) : null,
20092
- offer.steps.length ? (0, import_jsx_runtime.jsx)("ol", {
20093
- className: "ai-panel-steps",
20094
- children: offer.steps.map((line) => (0, import_jsx_runtime.jsx)("li", { children: line }, line))
20095
- }) : null,
20096
- offer.verifiedOn ? (0, import_jsx_runtime.jsxs)("p", {
20097
- className: "ai-panel-stamp",
20098
- children: [
20099
- "✓ Checked ",
20100
- offer.verifiedOn,
20101
- " — these are the taps this app actually has today."
20102
- ]
20103
- }) : (0, import_jsx_runtime.jsx)("p", {
20104
- className: "ai-panel-stamp ai-panel-stamp-none",
20105
- children: "These steps name no button we have not opened ourselves. Your app may word them differently."
20122
+ (0, import_jsx_runtime.jsx)("ol", {
20123
+ className: "steps",
20124
+ children: offer.steps.map((s, i) => {
20125
+ const c = s.copy;
20126
+ const flashed = !measuring && state.copiedAt === i;
20127
+ const landed = measuring && c?.kind === "secret" ? fill(c, mask("")) : state.landedAt === i ? state.landed : null;
20128
+ return (0, import_jsx_runtime.jsx)("li", { children: (0, import_jsx_runtime.jsxs)("div", { children: [
20129
+ (0, import_jsx_runtime.jsx)("div", {
20130
+ className: "step-text",
20131
+ children: (0, import_jsx_runtime.jsx)(Marked, { text: s.text })
20132
+ }),
20133
+ c?.kind === "block" ? (0, import_jsx_runtime.jsxs)("div", {
20134
+ className: "codeblock",
20135
+ children: [(0, import_jsx_runtime.jsx)("pre", { children: c.text }), (0, import_jsx_runtime.jsx)("button", {
20136
+ type: "button",
20137
+ className: `btn-ghost${flashed ? " is-copied" : ""}`,
20138
+ "data-step": i,
20139
+ tabIndex: measuring ? -1 : void 0,
20140
+ onClick: () => onBlock?.(i, c.text),
20141
+ children: flashed ? "✓ Copied" : "Copy"
20142
+ })]
20143
+ }) : null,
20144
+ c?.kind === "secret" ? (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
20145
+ (0, import_jsx_runtime.jsx)("div", {
20146
+ className: "secret-btn",
20147
+ children: (0, import_jsx_runtime.jsx)("button", {
20148
+ type: "button",
20149
+ className: `btn-primary${flashed ? " is-copied" : ""}`,
20150
+ "data-step": i,
20151
+ tabIndex: measuring ? -1 : void 0,
20152
+ onClick: () => onSecret?.(i, c),
20153
+ children: flashed ? (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [(0, import_jsx_runtime.jsx)(Icon, {
20154
+ name: "check",
20155
+ size: 15
20156
+ }), "Copied"] }) : landed ? "Copy again" : c.label
20157
+ })
20158
+ }),
20159
+ landed ? (0, import_jsx_runtime.jsxs)("div", {
20160
+ className: "landed",
20161
+ children: [(0, import_jsx_runtime.jsx)("div", {
20162
+ className: "landed-label",
20163
+ children: "On your clipboard now"
20164
+ }), landed.split("\n").map((line, n) => (0, import_jsx_runtime.jsx)("div", {
20165
+ className: "mono",
20166
+ children: line
20167
+ }, n))]
20168
+ }) : null,
20169
+ !measuring && state.revealedAt === i && state.revealed ? (0, import_jsx_runtime.jsxs)("div", {
20170
+ className: "landed",
20171
+ children: [(0, import_jsx_runtime.jsx)("p", {
20172
+ className: "ai-said",
20173
+ children: "Your browser would not let us copy it. Copy this by hand — it is yours, and it will not be shown again."
20174
+ }), (0, import_jsx_runtime.jsx)("pre", {
20175
+ className: "ai-pre",
20176
+ children: state.revealed
20177
+ })]
20178
+ }) : null
20179
+ ] }) : null,
20180
+ s.hint ? (0, import_jsx_runtime.jsx)("div", {
20181
+ className: "step-hint",
20182
+ children: (0, import_jsx_runtime.jsx)(Marked, { text: s.hint })
20183
+ }) : null
20184
+ ] }) }, i);
20185
+ })
20106
20186
  })
20107
20187
  ]
20108
20188
  });
20109
20189
  }
20190
+ function NotOnline() {
20191
+ return (0, import_jsx_runtime.jsxs)("div", {
20192
+ className: "notice ai-none",
20193
+ children: [(0, import_jsx_runtime.jsx)("strong", { children: "Not available on this installation yet" }), (0, import_jsx_runtime.jsx)("p", { children: "Your AI app reaches Clearotron over the internet, and this installation isn’t on the internet yet. Whoever installed it can put it online — it takes about a minute and needs no account." })]
20194
+ });
20195
+ }
20110
20196
  function UseYourAI({ ctx }) {
20111
20197
  const [access, setAccess] = (0, import_react.useState)(null);
20112
- const [route, setRoute] = (0, import_react.useState)(null);
20198
+ const [place, setPlace] = (0, import_react.useState)(null);
20113
20199
  const [picked, setPicked] = (0, import_react.useState)(null);
20200
+ const [copiedAt, setCopiedAt] = (0, import_react.useState)(null);
20201
+ const [landedAt, setLandedAt] = (0, import_react.useState)(null);
20114
20202
  const [landed, setLanded] = (0, import_react.useState)(null);
20115
- const [copiedId, setCopiedId] = (0, import_react.useState)(null);
20116
20203
  const [failed, setFailed] = (0, import_react.useState)(null);
20204
+ const [revealedAt, setRevealedAt] = (0, import_react.useState)(null);
20117
20205
  const [revealed, setRevealed] = (0, import_react.useState)(null);
20206
+ const [slotHeight, setSlotHeight] = (0, import_react.useState)(0);
20118
20207
  const timer = (0, import_react.useRef)(null);
20208
+ const probe = (0, import_react.useRef)(null);
20119
20209
  (0, import_react.useEffect)(() => {
20120
20210
  api.mcpAccess().then((r) => {
20121
20211
  if (r.kind === "ok") setAccess(r.value);
@@ -20125,43 +20215,66 @@ function UseYourAI({ ctx }) {
20125
20215
  if (timer.current) window.clearTimeout(timer.current);
20126
20216
  }, []);
20127
20217
  const served = (access?.offers ?? []).filter((o) => o.served);
20128
- const routes = placesOf(served);
20129
- const active = route ?? (routes.includes("disk") ? "disk" : routes[0] ?? null);
20130
- const here = served.filter((o) => active !== null && servesPlace(o, active));
20218
+ const routes = PLACES.filter((p) => served.some((o) => o.route === p));
20219
+ const asks = routes.includes("disk");
20220
+ const active = asks ? place : routes[0] ?? null;
20221
+ const here = served.filter((o) => active !== null && o.route === active);
20131
20222
  const chosen = here.find((o) => o.id === picked) ?? null;
20132
- const press = async (offer) => {
20133
- setPicked(offer.id);
20223
+ (0, import_react.useLayoutEffect)(() => {
20224
+ const el = probe.current;
20225
+ if (!el) return;
20226
+ const measure = () => setSlotHeight(Math.max(0, ...[...el.children].map((c) => c.offsetHeight)));
20227
+ measure();
20228
+ const seen = new ResizeObserver(measure);
20229
+ seen.observe(el);
20230
+ return () => seen.disconnect();
20231
+ }, [active, here.length]);
20232
+ const settle = () => {
20233
+ setCopiedAt(null);
20234
+ setLandedAt(null);
20235
+ setLanded(null);
20236
+ setRevealedAt(null);
20237
+ setRevealed(null);
20238
+ setFailed(null);
20239
+ };
20240
+ const flash = (i) => {
20241
+ setCopiedAt(i);
20242
+ if (timer.current) window.clearTimeout(timer.current);
20243
+ timer.current = window.setTimeout(() => setCopiedAt(null), COPIED_MS);
20244
+ };
20245
+ const copyBlock = async (i, text) => {
20246
+ setFailed(null);
20247
+ if (!await copy(text)) {
20248
+ setFailed("Your browser would not let us copy it. Select the text above and copy it by hand.");
20249
+ return;
20250
+ }
20251
+ flash(i);
20252
+ };
20253
+ const press = async (i, c) => {
20134
20254
  setFailed(null);
20255
+ setRevealedAt(null);
20135
20256
  setRevealed(null);
20136
- setLanded(null);
20137
- if (offer.command) {
20138
- if (!await copy(offer.command)) {
20139
- setFailed("Your browser would not let us copy it. The steps below still apply.");
20140
- return;
20141
- }
20142
- setLanded(offer.command);
20143
- } else {
20144
- const r = await api.connectKey();
20145
- if (r.kind !== "ok") {
20146
- setFailed("We could not set this up just now. Try again, or ask us.");
20147
- return;
20148
- }
20149
- if (!await copy(`${r.value.address}\n${r.value.key}`)) {
20150
- setRevealed({
20151
- address: r.value.address,
20152
- key: r.value.key
20153
- });
20154
- return;
20155
- }
20156
- setLanded(`${r.value.address} ${mask(r.value.key)}`);
20257
+ const r = await api.connectKey();
20258
+ if (r.kind !== "ok") {
20259
+ setFailed("We could not set this up just now. Try again, or ask us.");
20260
+ return;
20157
20261
  }
20158
- setCopiedId(offer.id);
20159
- if (timer.current) window.clearTimeout(timer.current);
20160
- timer.current = window.setTimeout(() => setCopiedId(null), COPIED_MS);
20262
+ if (!await copy(fill(c, r.value.key))) {
20263
+ setRevealedAt(i);
20264
+ setRevealed(fill(c, r.value.key));
20265
+ return;
20266
+ }
20267
+ setLandedAt(i);
20268
+ setLanded(fill(c, mask(r.value.key)));
20269
+ flash(i);
20161
20270
  };
20162
20271
  return (0, import_jsx_runtime.jsxs)("div", {
20163
20272
  className: "screen ai-screen",
20164
20273
  children: [
20274
+ (0, import_jsx_runtime.jsx)("div", {
20275
+ className: "eyebrow",
20276
+ children: "Use your own AI"
20277
+ }),
20165
20278
  (0, import_jsx_runtime.jsx)("h1", {
20166
20279
  className: "ai-title",
20167
20280
  children: "Use your own AI"
@@ -20171,136 +20284,156 @@ function UseYourAI({ ctx }) {
20171
20284
  children: "Run and interrogate clearances from the assistant you already use — by voice, by email, or just by asking."
20172
20285
  }),
20173
20286
  (0, import_jsx_runtime.jsxs)("section", {
20174
- className: "ai-can",
20287
+ className: "ctx-card ai-can",
20175
20288
  children: [
20176
20289
  (0, import_jsx_runtime.jsx)("h2", { children: "What you can do" }),
20177
- (0, import_jsx_runtime.jsx)("ul", { children: WHAT_YOU_CAN_DO.map((line) => (0, import_jsx_runtime.jsx)("li", { children: line }, line)) }),
20290
+ (0, import_jsx_runtime.jsx)("ul", {
20291
+ className: "ai-can-list",
20292
+ children: WHAT_YOU_CAN_DO.map((line) => (0, import_jsx_runtime.jsxs)("li", { children: [(0, import_jsx_runtime.jsx)(Icon, {
20293
+ name: "check",
20294
+ size: 15
20295
+ }), line] }, line))
20296
+ }),
20178
20297
  (0, import_jsx_runtime.jsxs)("p", {
20179
20298
  className: "ai-can-foot",
20180
20299
  children: [
20181
- "Every report also has an ",
20300
+ "Use the ",
20182
20301
  (0, import_jsx_runtime.jsx)("strong", { children: "Ask AI" }),
20183
- " button that jumps straight to that run.",
20184
- " ",
20185
- (0, import_jsx_runtime.jsx)("strong", { children: "What you set up here reaches your own clearances and nothing else." })
20302
+ " button on a report."
20186
20303
  ]
20187
20304
  })
20188
20305
  ]
20189
20306
  }),
20190
- (0, import_jsx_runtime.jsx)("h2", {
20191
- className: "ai-connect-head",
20192
- children: "Connect it"
20193
- }),
20194
- !served.length ? (0, import_jsx_runtime.jsxs)("p", {
20195
- className: "ai-none",
20196
- children: [(0, import_jsx_runtime.jsx)("strong", { children: "Not available on this installation yet." }), " Your assistants reach this service over the internet, and this installation is not on the internet. Whoever installed it can put it online — it takes about a minute and needs no account."]
20197
- }) : (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
20198
- routes.length > 1 ? (0, import_jsx_runtime.jsxs)("div", {
20199
- className: "ai-where",
20200
- children: [
20201
- (0, import_jsx_runtime.jsx)("h3", {
20202
- className: "ai-where-q",
20203
- children: "Where does your assistant run?"
20204
- }),
20205
- (0, import_jsx_runtime.jsx)("div", {
20206
- className: "ai-seg",
20207
- role: "group",
20208
- "aria-label": "Where does your assistant run?",
20209
- children: routes.map((r) => (0, import_jsx_runtime.jsx)("button", {
20210
- type: "button",
20211
- className: "ai-seg-btn",
20212
- "data-on": r === active ? "" : void 0,
20213
- "aria-pressed": r === active,
20214
- onClick: () => {
20215
- setRoute(r);
20216
- setPicked(null);
20217
- setLanded(null);
20218
- setRevealed(null);
20219
- setFailed(null);
20220
- },
20221
- children: WHERE[r] ?? WHERE["public-http"]
20222
- }, r))
20223
- }),
20224
- (0, import_jsx_runtime.jsx)("p", {
20225
- className: "ai-where-sub",
20226
- children: "Pick your assistant. We copy the one line it needs — nothing to sign up for, nothing opened up."
20227
- })
20228
- ]
20229
- }) : (0, import_jsx_runtime.jsx)("p", {
20230
- className: "ai-where-sub",
20231
- children: "Pick where you will paste it. One press copies everything your assistant needs."
20232
- }),
20233
- (0, import_jsx_runtime.jsx)("div", {
20234
- className: "ai-dests",
20235
- children: here.map((o) => (0, import_jsx_runtime.jsx)(Destination, {
20236
- offer: o,
20237
- selected: o.id === picked,
20238
- copied: o.id === copiedId,
20239
- onPick: () => void press(o)
20240
- }, o.id))
20241
- }),
20242
- (0, import_jsx_runtime.jsxs)("div", {
20243
- className: "ai-slot",
20244
- "aria-live": "polite",
20245
- children: [failed ? (0, import_jsx_runtime.jsx)("p", {
20246
- className: "ai-said",
20247
- children: failed
20248
- }) : null, revealed ? (0, import_jsx_runtime.jsxs)("div", {
20249
- className: "ai-panel",
20250
- children: [(0, import_jsx_runtime.jsxs)("p", {
20251
- className: "ai-said",
20252
- children: [
20253
- "Your browser would not let us copy it. Paste these two lines into",
20254
- " ",
20255
- chosen?.name ?? "your assistant",
20256
- " — they are yours, and they will not be shown again."
20257
- ]
20258
- }), (0, import_jsx_runtime.jsxs)("pre", {
20259
- className: "ai-pre",
20307
+ (0, import_jsx_runtime.jsxs)("section", {
20308
+ className: "ai-connect",
20309
+ children: [(0, import_jsx_runtime.jsx)("h2", {
20310
+ className: "ai-connect-head",
20311
+ children: "Connect it"
20312
+ }), !served.length ? (0, import_jsx_runtime.jsx)(NotOnline, {}) : (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [asks ? (0, import_jsx_runtime.jsx)("div", {
20313
+ className: "where-grid",
20314
+ role: "group",
20315
+ "aria-label": "Where Clearotron is running",
20316
+ children: PLACES.map((p) => (0, import_jsx_runtime.jsxs)("button", {
20317
+ type: "button",
20318
+ className: "where-card",
20319
+ "data-place": p,
20320
+ "aria-pressed": p === active,
20321
+ onClick: () => {
20322
+ if (p !== active) {
20323
+ setPlace(p);
20324
+ setPicked(null);
20325
+ settle();
20326
+ }
20327
+ },
20328
+ children: [
20329
+ (0, import_jsx_runtime.jsx)("span", {
20330
+ className: p === active ? "radio radio-on" : "radio",
20331
+ "aria-hidden": "true"
20332
+ }),
20333
+ (0, import_jsx_runtime.jsx)(Icon, {
20334
+ name: WHERE[p].icon,
20335
+ size: 19
20336
+ }),
20337
+ WHERE[p].label
20338
+ ]
20339
+ }, p))
20340
+ }) : null, active === null ? null : !here.length ? (0, import_jsx_runtime.jsx)(NotOnline, {}) : (0, import_jsx_runtime.jsxs)("div", {
20341
+ className: "ai-connect-grid",
20342
+ children: [(0, import_jsx_runtime.jsxs)("div", { children: [(0, import_jsx_runtime.jsx)("h3", {
20343
+ className: "section-title",
20344
+ children: "Select AI app"
20345
+ }), (0, import_jsx_runtime.jsx)("div", {
20346
+ className: "ai-apps",
20347
+ children: here.map((o) => (0, import_jsx_runtime.jsxs)("button", {
20348
+ type: "button",
20349
+ className: `pick-row ai-app${o.id === picked ? " pick-row-on" : ""}`,
20350
+ "data-id": o.id,
20351
+ "aria-pressed": o.id === picked,
20352
+ onClick: () => {
20353
+ if (o.id !== picked) {
20354
+ setPicked(o.id);
20355
+ settle();
20356
+ }
20357
+ },
20260
20358
  children: [
20261
- revealed.address,
20262
- "\n",
20263
- revealed.key
20359
+ (0, import_jsx_runtime.jsx)("span", {
20360
+ className: o.id === picked ? "radio radio-on" : "radio",
20361
+ "aria-hidden": "true"
20362
+ }),
20363
+ (0, import_jsx_runtime.jsxs)("span", {
20364
+ className: "ai-app-label",
20365
+ children: [(0, import_jsx_runtime.jsx)("span", {
20366
+ className: "ai-app-name",
20367
+ children: o.name
20368
+ }), o.sub ? (0, import_jsx_runtime.jsx)("span", {
20369
+ className: "ai-app-sub",
20370
+ children: o.sub
20371
+ }) : null]
20372
+ }),
20373
+ (0, import_jsx_runtime.jsx)("span", {
20374
+ className: "ai-app-go",
20375
+ children: (0, import_jsx_runtime.jsx)(Icon, {
20376
+ name: "chevron",
20377
+ size: 16
20378
+ })
20379
+ })
20264
20380
  ]
20265
- })]
20266
- }) : chosen ? (0, import_jsx_runtime.jsx)(Panel, {
20267
- offer: chosen,
20268
- landed
20269
- }) : (0, import_jsx_runtime.jsx)("p", {
20270
- className: "ai-slot-empty",
20271
- children: "Pick your assistant and we will copy what it needs, then show you exactly where it goes."
20381
+ }, o.id))
20382
+ })] }), (0, import_jsx_runtime.jsxs)("div", {
20383
+ className: "ai-slot",
20384
+ "aria-live": "polite",
20385
+ style: slotHeight ? { minHeight: slotHeight } : void 0,
20386
+ children: [
20387
+ chosen ? (0, import_jsx_runtime.jsx)(StepsPanel, {
20388
+ offer: chosen,
20389
+ state: {
20390
+ copiedAt,
20391
+ landedAt,
20392
+ landed,
20393
+ revealedAt,
20394
+ revealed
20395
+ },
20396
+ onBlock: (i, text) => void copyBlock(i, text),
20397
+ onSecret: (i, c) => void press(i, c)
20398
+ }) : (0, import_jsx_runtime.jsx)("div", {
20399
+ className: "steps-panel steps-panel-empty",
20400
+ children: (0, import_jsx_runtime.jsxs)("span", {
20401
+ className: "steps-empty",
20402
+ children: [(0, import_jsx_runtime.jsx)(Icon, {
20403
+ name: "arrow-left",
20404
+ size: 16
20405
+ }), "Select AI to see instructions"]
20406
+ })
20407
+ }),
20408
+ failed ? (0, import_jsx_runtime.jsx)("p", {
20409
+ className: "ai-said ai-failed",
20410
+ children: failed
20411
+ }) : null,
20412
+ (0, import_jsx_runtime.jsx)("div", {
20413
+ className: "ai-probe",
20414
+ ref: probe,
20415
+ "aria-hidden": "true",
20416
+ children: here.map((o) => (0, import_jsx_runtime.jsx)(StepsPanel, {
20417
+ offer: o,
20418
+ measuring: true
20419
+ }, o.id))
20420
+ })
20421
+ ]
20272
20422
  })]
20273
- })
20274
- ] }),
20275
- (0, import_jsx_runtime.jsxs)("details", {
20276
- className: "ai-help",
20277
- children: [(0, import_jsx_runtime.jsx)("summary", { children: "Not connecting, or want to set it up yourself?" }), (0, import_jsx_runtime.jsxs)("div", {
20278
- className: "ai-help-body",
20279
- children: [
20280
- (0, import_jsx_runtime.jsxs)("p", { children: [
20281
- "Press the button for your assistant and it will tell you the next thing to do — usually three taps inside that app’s own settings. If your assistant is not listed, pick",
20282
- (0, import_jsx_runtime.jsx)("strong", { children: " Another agent" }),
20283
- ": it will give you both of the things any assistant can take."
20284
- ] }),
20285
- (0, import_jsx_runtime.jsxs)("p", { children: [
20286
- "Once it is connected, you do not have to learn anything new. Ask it in your own words —",
20287
- (0, import_jsx_runtime.jsx)("em", { children: " “start a knockout for our new drinks name across the US”" }),
20288
- ", or",
20289
- (0, import_jsx_runtime.jsx)("em", { children: " “why did you rate that one high?”" }),
20290
- " — and it will do the same work you would do on these screens."
20291
- ] }),
20292
- (0, import_jsx_runtime.jsx)("p", { children: "If a press does not finish, the most common reason is that your assistant runs somewhere this service cannot be reached from. The team who set this up can tell you in a sentence." }),
20293
- (0, import_jsx_runtime.jsxs)("p", {
20294
- className: "ai-help-doc",
20295
- children: [(0, import_jsx_runtime.jsx)("a", {
20296
- href: "/portal/connect-help",
20297
- target: "_blank",
20298
- rel: "noreferrer",
20299
- children: "The full technical instructions"
20300
- }), " — written for an engineer, or for an assistant reading on your behalf."]
20301
- })
20302
- ]
20303
- })]
20423
+ })] })]
20424
+ }),
20425
+ (0, import_jsx_runtime.jsxs)("div", {
20426
+ className: "notice quiet ai-help",
20427
+ children: [
20428
+ (0, import_jsx_runtime.jsx)("strong", { children: "If it doesn’t connect" }),
20429
+ (0, import_jsx_runtime.jsx)("p", { children: "Point your AI at the full technical setup instructions to diagnose." }),
20430
+ (0, import_jsx_runtime.jsx)("p", { children: (0, import_jsx_runtime.jsxs)("a", {
20431
+ href: HELP_URL,
20432
+ target: "_blank",
20433
+ rel: "noreferrer",
20434
+ children: [HELP_LINK_TEXT, " ↗"]
20435
+ }) })
20436
+ ]
20304
20437
  })
20305
20438
  ]
20306
20439
  });
@@ -22124,7 +22257,8 @@ function useSourceRepo() {
22124
22257
  function PeopleAccess({ ctx }) {
22125
22258
  const { result } = useLoad(() => api.adminAccess(), []);
22126
22259
  const repo = useSourceRepo();
22127
- const { result: observed } = useLoad(() => api.adminObserved(), []);
22260
+ const seesAll = ctx.me.allAccounts;
22261
+ const { result: observed } = useLoad(() => seesAll ? api.adminObserved() : Promise.resolve({ kind: "notFound" }), [seesAll]);
22128
22262
  if (result && result.kind !== "ok") return (0, import_jsx_runtime.jsx)("div", {
22129
22263
  className: "screen",
22130
22264
  children: (0, import_jsx_runtime.jsxs)("div", {