@burdenoff/microfe-atheletebridge 2026.801.2 → 2026.801.3

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 (63) hide show
  1. package/dist/atheletebridge/AthleteBridgeRoot.d.ts.map +1 -1
  2. package/dist/atheletebridge/AthleteBridgeRoot.js +53 -45
  3. package/dist/atheletebridge/AthleteBridgeRoot.js.map +1 -1
  4. package/dist/atheletebridge/AthleteBridgeRoutes.d.ts.map +1 -1
  5. package/dist/atheletebridge/AthleteBridgeRoutes.js +15 -7
  6. package/dist/atheletebridge/AthleteBridgeRoutes.js.map +1 -1
  7. package/dist/atheletebridge/components/StatusBadge.d.ts.map +1 -1
  8. package/dist/atheletebridge/components/StatusBadge.js +3 -1
  9. package/dist/atheletebridge/components/StatusBadge.js.map +1 -1
  10. package/dist/atheletebridge/components/ai/AgentRunFeed.d.ts +19 -0
  11. package/dist/atheletebridge/components/ai/AgentRunFeed.d.ts.map +1 -0
  12. package/dist/atheletebridge/components/ai/AgentRunFeed.js +124 -0
  13. package/dist/atheletebridge/components/ai/AgentRunFeed.js.map +1 -0
  14. package/dist/atheletebridge/components/ai/AiErrorNotice.d.ts +21 -0
  15. package/dist/atheletebridge/components/ai/AiErrorNotice.d.ts.map +1 -0
  16. package/dist/atheletebridge/components/ai/AiErrorNotice.js +114 -0
  17. package/dist/atheletebridge/components/ai/AiErrorNotice.js.map +1 -0
  18. package/dist/atheletebridge/components/ai/AiModelPicker.d.ts +19 -0
  19. package/dist/atheletebridge/components/ai/AiModelPicker.d.ts.map +1 -0
  20. package/dist/atheletebridge/components/ai/AiModelPicker.js +203 -0
  21. package/dist/atheletebridge/components/ai/AiModelPicker.js.map +1 -0
  22. package/dist/atheletebridge/components/ai/DecisionCard.d.ts +11 -0
  23. package/dist/atheletebridge/components/ai/DecisionCard.d.ts.map +1 -0
  24. package/dist/atheletebridge/components/ai/DecisionCard.js +343 -0
  25. package/dist/atheletebridge/components/ai/DecisionCard.js.map +1 -0
  26. package/dist/atheletebridge/components/ai/RunDecisionPanel.d.ts +21 -0
  27. package/dist/atheletebridge/components/ai/RunDecisionPanel.d.ts.map +1 -0
  28. package/dist/atheletebridge/components/ai/RunDecisionPanel.js +371 -0
  29. package/dist/atheletebridge/components/ai/RunDecisionPanel.js.map +1 -0
  30. package/dist/atheletebridge/components/ai/assessment.d.ts +14 -0
  31. package/dist/atheletebridge/components/ai/assessment.d.ts.map +1 -0
  32. package/dist/atheletebridge/components/ai/assessment.js +30 -0
  33. package/dist/atheletebridge/components/ai/assessment.js.map +1 -0
  34. package/dist/atheletebridge/components/ai/index.d.ts +11 -0
  35. package/dist/atheletebridge/components/ai/index.d.ts.map +1 -0
  36. package/dist/atheletebridge/components/index.d.ts +1 -0
  37. package/dist/atheletebridge/components/index.d.ts.map +1 -1
  38. package/dist/atheletebridge/hooks/index.d.ts +2 -2
  39. package/dist/atheletebridge/hooks/index.d.ts.map +1 -1
  40. package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts +92 -1
  41. package/dist/atheletebridge/hooks/useAthleteBridgeApi.d.ts.map +1 -1
  42. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js +274 -129
  43. package/dist/atheletebridge/hooks/useAthleteBridgeApi.js.map +1 -1
  44. package/dist/atheletebridge/index.d.ts +1 -1
  45. package/dist/atheletebridge/index.d.ts.map +1 -1
  46. package/dist/atheletebridge/pages/ai/AiOperationsPage.d.ts +23 -0
  47. package/dist/atheletebridge/pages/ai/AiOperationsPage.d.ts.map +1 -0
  48. package/dist/atheletebridge/pages/ai/AiOperationsPage.js +117 -0
  49. package/dist/atheletebridge/pages/ai/AiOperationsPage.js.map +1 -0
  50. package/dist/atheletebridge/types/index.d.ts +124 -1
  51. package/dist/atheletebridge/types/index.d.ts.map +1 -1
  52. package/dist/atheletebridge/utils/aiDecision.d.ts +73 -0
  53. package/dist/atheletebridge/utils/aiDecision.d.ts.map +1 -0
  54. package/dist/atheletebridge/utils/aiDecision.js +187 -0
  55. package/dist/atheletebridge/utils/aiDecision.js.map +1 -0
  56. package/dist/atheletebridge/utils/index.d.ts +2 -0
  57. package/dist/atheletebridge/utils/index.d.ts.map +1 -1
  58. package/dist/atheletebridge/utils/pageContext.d.ts.map +1 -1
  59. package/dist/atheletebridge/utils/pageContext.js +5 -0
  60. package/dist/atheletebridge/utils/pageContext.js.map +1 -1
  61. package/dist/generated/wspace-types.d.ts +68885 -33499
  62. package/dist/generated/wspace-types.d.ts.map +1 -1
  63. package/package.json +1 -1
@@ -0,0 +1,114 @@
1
+ import { cn as e } from "../../utils/cn.js";
2
+ import { formatDate as t } from "../../utils/formatters.js";
3
+ import { AI_PROVIDER_UNAVAILABLE as n, AthApiError as r, useAgentRun as i } from "../../hooks/useAthleteBridgeApi.js";
4
+ import { useState as a } from "react";
5
+ import { AlertTriangle as o, ChevronDown as s, ChevronRight as c, Loader2 as l } from "lucide-react";
6
+ import { Fragment as u, jsx as d, jsxs as f } from "react/jsx-runtime";
7
+ //#region src/atheletebridge/components/ai/AiErrorNotice.tsx
8
+ function p({ agentRunId: e }) {
9
+ let [n, r] = a(!1), o = i(n ? e : void 0);
10
+ return /* @__PURE__ */ f("div", {
11
+ className: "mt-3 border-t border-status-error-border/40 pt-3",
12
+ children: [/* @__PURE__ */ f("button", {
13
+ type: "button",
14
+ onClick: () => r((e) => !e),
15
+ "aria-expanded": n,
16
+ className: "inline-flex items-center gap-1.5 text-xs font-medium text-status-error-text underline-offset-2 hover:underline",
17
+ children: [d(n ? s : c, { className: "h-3.5 w-3.5" }), n ? "Hide the recorded failure" : "Show the recorded failure"]
18
+ }), n && /* @__PURE__ */ d("div", {
19
+ className: "mt-2 text-xs text-text-secondary",
20
+ children: o.isLoading ? /* @__PURE__ */ f("span", {
21
+ className: "inline-flex items-center gap-1.5",
22
+ children: [/* @__PURE__ */ d(l, { className: "h-3.5 w-3.5 animate-spin" }), " Loading ledger row…"]
23
+ }) : o.isError || !o.data ? /* @__PURE__ */ f("span", { children: [
24
+ "The ledger row could not be read back. Quote run id",
25
+ " ",
26
+ /* @__PURE__ */ d("code", {
27
+ className: "rounded bg-bg-sunken px-1 py-0.5 font-mono",
28
+ children: e
29
+ }),
30
+ " when reporting this."
31
+ ] }) : /* @__PURE__ */ f("dl", {
32
+ className: "grid grid-cols-1 gap-1 sm:grid-cols-2",
33
+ children: [
34
+ /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("dt", {
35
+ className: "inline font-medium text-text-primary",
36
+ children: "Provider: "
37
+ }), /* @__PURE__ */ f("dd", {
38
+ className: "inline",
39
+ children: [
40
+ o.data.provider,
41
+ " · ",
42
+ o.data.model
43
+ ]
44
+ })] }),
45
+ /* @__PURE__ */ f("div", { children: [/* @__PURE__ */ d("dt", {
46
+ className: "inline font-medium text-text-primary",
47
+ children: "Recorded: "
48
+ }), /* @__PURE__ */ d("dd", {
49
+ className: "inline",
50
+ children: t(o.data.createdAt)
51
+ })] }),
52
+ o.data.error && /* @__PURE__ */ f("div", {
53
+ className: "sm:col-span-2",
54
+ children: [/* @__PURE__ */ d("dt", {
55
+ className: "font-medium text-text-primary",
56
+ children: "Upstream error"
57
+ }), /* @__PURE__ */ d("dd", {
58
+ className: "mt-0.5 whitespace-pre-wrap break-words font-mono text-[0.7rem] leading-relaxed",
59
+ children: o.data.error
60
+ })]
61
+ })
62
+ ]
63
+ })
64
+ })]
65
+ });
66
+ }
67
+ function m({ error: t, className: i }) {
68
+ if (!t) return null;
69
+ let a = t instanceof r ? t : null, s = t instanceof Error ? t.message : "The request failed for an unknown reason.", c = a?.code === n;
70
+ return /* @__PURE__ */ d("div", {
71
+ role: "alert",
72
+ className: e("rounded-xl border border-status-error-border bg-status-error-bg-subtle p-4", i),
73
+ children: /* @__PURE__ */ f("div", {
74
+ className: "flex items-start gap-3",
75
+ children: [/* @__PURE__ */ d(o, { className: "mt-0.5 h-5 w-5 shrink-0 text-status-error-text" }), /* @__PURE__ */ f("div", {
76
+ className: "min-w-0 flex-1",
77
+ children: [
78
+ /* @__PURE__ */ d("p", {
79
+ className: "text-sm font-semibold text-status-error-text",
80
+ children: c ? "AI provider unavailable" : "The AI action failed"
81
+ }),
82
+ /* @__PURE__ */ d("p", {
83
+ className: "mt-1 break-words text-sm text-text-secondary",
84
+ children: s
85
+ }),
86
+ a?.code && /* @__PURE__ */ f("p", {
87
+ className: "mt-2 text-xs text-text-muted",
88
+ children: [
89
+ "Error code",
90
+ " ",
91
+ /* @__PURE__ */ d("code", {
92
+ className: "rounded bg-bg-sunken px-1 py-0.5 font-mono",
93
+ children: a.code
94
+ }),
95
+ a.agentRunId && /* @__PURE__ */ f(u, { children: [" · ledger row ", /* @__PURE__ */ d("code", {
96
+ className: "rounded bg-bg-sunken px-1 py-0.5 font-mono",
97
+ children: a.agentRunId
98
+ })] })
99
+ ]
100
+ }),
101
+ c && /* @__PURE__ */ d("p", {
102
+ className: "mt-2 text-xs text-text-secondary",
103
+ children: "Nothing was changed. The attempt is recorded in the decision ledger below, with every provider it tried."
104
+ }),
105
+ a?.agentRunId && /* @__PURE__ */ d(p, { agentRunId: a.agentRunId })
106
+ ]
107
+ })]
108
+ })
109
+ });
110
+ }
111
+ //#endregion
112
+ export { m as AiErrorNotice };
113
+
114
+ //# sourceMappingURL=AiErrorNotice.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiErrorNotice.js","names":[],"sources":["../../../../src/atheletebridge/components/ai/AiErrorNotice.tsx"],"sourcesContent":["/**\n * AI error notice\n * @module atheletebridge/components/ai\n *\n * Renders a failed AI action honestly (BOFF-3574).\n *\n * The svc answers an unconfigured/unreachable provider with\n * `AI_PROVIDER_UNAVAILABLE` and an `extensions.agentRunId` pointing at the\n * FAILED ledger row that holds every attempt's raw upstream message. Collapsing\n * that into a generic \"something went wrong\" toast is what made an outage\n * indistinguishable from a crashed service, so the code, the message and the\n * ledger row are all shown — and the row itself can be opened inline.\n */\n\nimport { useState } from 'react';\nimport { AlertTriangle, ChevronDown, ChevronRight, Loader2 } from 'lucide-react';\nimport { AI_PROVIDER_UNAVAILABLE, AthApiError, useAgentRun } from '../../hooks/useAthleteBridgeApi';\nimport { cn } from '../../utils/cn';\nimport { formatDate } from '../../utils/formatters';\n\ninterface AiErrorNoticeProps {\n /** Anything thrown by a mutation; non-errors render nothing. */\n error: unknown;\n className?: string;\n}\n\n/** The FAILED ledger row an AI_PROVIDER_UNAVAILABLE error points at. */\nfunction FailedRunDetails({ agentRunId }: { agentRunId: string }) {\n const [open, setOpen] = useState(false);\n // Only fetched once the user asks for it — the id alone is enough to find the\n // row, and a failed action should not fan out into extra reads by default.\n const run = useAgentRun(open ? agentRunId : undefined);\n\n return (\n <div className=\"mt-3 border-t border-status-error-border/40 pt-3\">\n <button\n type=\"button\"\n onClick={() => setOpen((value) => !value)}\n aria-expanded={open}\n className=\"inline-flex items-center gap-1.5 text-xs font-medium text-status-error-text underline-offset-2 hover:underline\"\n >\n {open ? <ChevronDown className=\"h-3.5 w-3.5\" /> : <ChevronRight className=\"h-3.5 w-3.5\" />}\n {open ? 'Hide the recorded failure' : 'Show the recorded failure'}\n </button>\n {open && (\n <div className=\"mt-2 text-xs text-text-secondary\">\n {run.isLoading ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> Loading ledger row…\n </span>\n ) : run.isError || !run.data ? (\n <span>\n The ledger row could not be read back. Quote run id{' '}\n <code className=\"rounded bg-bg-sunken px-1 py-0.5 font-mono\">{agentRunId}</code> when\n reporting this.\n </span>\n ) : (\n <dl className=\"grid grid-cols-1 gap-1 sm:grid-cols-2\">\n <div>\n <dt className=\"inline font-medium text-text-primary\">Provider: </dt>\n <dd className=\"inline\">\n {run.data.provider} · {run.data.model}\n </dd>\n </div>\n <div>\n <dt className=\"inline font-medium text-text-primary\">Recorded: </dt>\n <dd className=\"inline\">{formatDate(run.data.createdAt)}</dd>\n </div>\n {run.data.error && (\n <div className=\"sm:col-span-2\">\n <dt className=\"font-medium text-text-primary\">Upstream error</dt>\n <dd className=\"mt-0.5 whitespace-pre-wrap break-words font-mono text-[0.7rem] leading-relaxed\">\n {run.data.error}\n </dd>\n </div>\n )}\n </dl>\n )}\n </div>\n )}\n </div>\n );\n}\n\nexport function AiErrorNotice({ error, className }: AiErrorNoticeProps) {\n if (!error) {\n return null;\n }\n\n const apiError = error instanceof AthApiError ? error : null;\n const message =\n error instanceof Error ? error.message : 'The request failed for an unknown reason.';\n const isProviderOutage = apiError?.code === AI_PROVIDER_UNAVAILABLE;\n\n return (\n <div\n role=\"alert\"\n className={cn(\n 'rounded-xl border border-status-error-border bg-status-error-bg-subtle p-4',\n className\n )}\n >\n <div className=\"flex items-start gap-3\">\n <AlertTriangle className=\"mt-0.5 h-5 w-5 shrink-0 text-status-error-text\" />\n <div className=\"min-w-0 flex-1\">\n <p className=\"text-sm font-semibold text-status-error-text\">\n {isProviderOutage ? 'AI provider unavailable' : 'The AI action failed'}\n </p>\n <p className=\"mt-1 break-words text-sm text-text-secondary\">{message}</p>\n {apiError?.code && (\n <p className=\"mt-2 text-xs text-text-muted\">\n Error code{' '}\n <code className=\"rounded bg-bg-sunken px-1 py-0.5 font-mono\">{apiError.code}</code>\n {apiError.agentRunId && (\n <>\n {' · ledger row '}\n <code className=\"rounded bg-bg-sunken px-1 py-0.5 font-mono\">\n {apiError.agentRunId}\n </code>\n </>\n )}\n </p>\n )}\n {isProviderOutage && (\n <p className=\"mt-2 text-xs text-text-secondary\">\n Nothing was changed. The attempt is recorded in the decision ledger below, with every\n provider it tried.\n </p>\n )}\n {apiError?.agentRunId && <FailedRunDetails agentRunId={apiError.agentRunId} />}\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":";;;;;;;AA2BA,SAAS,EAAiB,EAAE,iBAAsC;CAChE,IAAM,CAAC,GAAM,KAAW,EAAS,EAAK,GAGhC,IAAM,EAAY,IAAO,IAAa,KAAA,CAAS;CAErD,OACE,kBAAC,OAAD;EAAK,WAAU;YAAf,CACE,kBAAC,UAAD;GACE,MAAK;GACL,eAAe,GAAS,MAAU,CAAC,CAAK;GACxC,iBAAe;GACf,WAAU;aAJZ,CAMU,EAAP,IAAQ,IAA0C,GAA3C,EAAa,WAAU,cAAe,CAA2C,GACxF,IAAO,8BAA8B,2BAChC;MACP,KACC,kBAAC,OAAD;GAAK,WAAU;aACZ,EAAI,YACH,kBAAC,QAAD;IAAM,WAAU;cAAhB,CACE,kBAAC,GAAD,EAAS,WAAU,2BAA4B,CAAA,GAAC,sBAC5C;QACJ,EAAI,WAAW,CAAC,EAAI,OACtB,kBAAC,QAAD,EAAA,UAAA;IAAM;IACgD;IACpD,kBAAC,QAAD;KAAM,WAAU;eAA8C;IAAiB,CAAA;IAAC;GAE5E,EAAA,CAAA,IAEN,kBAAC,MAAD;IAAI,WAAU;cAAd;KACE,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAAuC;KAAc,CAAA,GACnE,kBAAC,MAAD;MAAI,WAAU;gBAAd;OACG,EAAI,KAAK;OAAS;OAAI,EAAI,KAAK;MAC9B;OACD,EAAA,CAAA;KACL,kBAAC,OAAD,EAAA,UAAA,CACE,kBAAC,MAAD;MAAI,WAAU;gBAAuC;KAAc,CAAA,GACnE,kBAAC,MAAD;MAAI,WAAU;gBAAU,EAAW,EAAI,KAAK,SAAS;KAAM,CAAA,CACxD,EAAA,CAAA;KACJ,EAAI,KAAK,SACR,kBAAC,OAAD;MAAK,WAAU;gBAAf,CACE,kBAAC,MAAD;OAAI,WAAU;iBAAgC;MAAkB,CAAA,GAChE,kBAAC,MAAD;OAAI,WAAU;iBACX,EAAI,KAAK;MACR,CAAA,CACD;;IAEL;;EAEH,CAAA,CAEJ;;AAET;AAEA,SAAgB,EAAc,EAAE,UAAO,gBAAiC;CACtE,IAAI,CAAC,GACH,OAAO;CAGT,IAAM,IAAW,aAAiB,IAAc,IAAQ,MAClD,IACJ,aAAiB,QAAQ,EAAM,UAAU,6CACrC,IAAmB,GAAU,SAAS;CAE5C,OACE,kBAAC,OAAD;EACE,MAAK;EACL,WAAW,EACT,8EACA,CACF;YAEA,kBAAC,OAAD;GAAK,WAAU;aAAf,CACE,kBAAC,GAAD,EAAe,WAAU,iDAAkD,CAAA,GAC3E,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,KAAD;MAAG,WAAU;gBACV,IAAmB,4BAA4B;KAC/C,CAAA;KACH,kBAAC,KAAD;MAAG,WAAU;gBAAgD;KAAW,CAAA;KACvE,GAAU,QACT,kBAAC,KAAD;MAAG,WAAU;gBAAb;OAA4C;OAC/B;OACX,kBAAC,QAAD;QAAM,WAAU;kBAA8C,EAAS;OAAW,CAAA;OACjF,EAAS,cACR,kBAAA,GAAA,EAAA,UAAA,CACG,kBACD,kBAAC,QAAD;QAAM,WAAU;kBACb,EAAS;OACN,CAAA,CACN,EAAA,CAAA;MAEH;;KAEJ,KACC,kBAAC,KAAD;MAAG,WAAU;gBAAmC;KAG7C,CAAA;KAEJ,GAAU,cAAc,kBAAC,GAAD,EAAkB,YAAY,EAAS,WAAa,CAAA;IAC1E;KACF;;CACF,CAAA;AAET"}
@@ -0,0 +1,19 @@
1
+ /**
2
+ * AI model picker + autopilot control
3
+ * @module atheletebridge/components/ai
4
+ *
5
+ * The workspace's saved (provider, model) pair — read from
6
+ * `athWorkspaceAiConfig`, chosen from `athAiModelCatalog`, saved with
7
+ * `athSetWorkspaceAiModel` — plus the per-workspace autopilot opt-in
8
+ * (`athSetWorkspaceAutoPilot`).
9
+ *
10
+ * The autopilot copy is deliberately unglamorous. The loop only ever records a
11
+ * PROPOSED adjustment that a coach still has to accept, and it is additionally
12
+ * gated by the `ATHELETEBRIDGE_AGENT_LOOP_ENABLED` deployment kill switch,
13
+ * which is OFF in production. A toggle that implies "the AI now coaches for
14
+ * you" would be a lie in both directions, so it says exactly what it does.
15
+ */
16
+ export declare function AiModelPicker({ className }: {
17
+ className?: string;
18
+ }): import("react").JSX.Element;
19
+ //# sourceMappingURL=AiModelPicker.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiModelPicker.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/components/ai/AiModelPicker.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAqBH,wBAAgB,aAAa,CAAC,EAAE,SAAS,EAAE,EAAE;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,+BA0MlE"}
@@ -0,0 +1,203 @@
1
+ import { formatDate as e } from "../../utils/formatters.js";
2
+ import { useAiModelCatalog as t, useSetWorkspaceAiModel as n, useSetWorkspaceAutoPilot as r, useWorkspaceAiConfig as i } from "../../hooks/useAthleteBridgeApi.js";
3
+ import { timeAgo as a } from "../../utils/timeAgo.js";
4
+ import { FormField as o, fieldInputClass as s } from "../form.js";
5
+ import { AiErrorNotice as c } from "./AiErrorNotice.js";
6
+ import { useMemo as l, useState as u } from "react";
7
+ import { Bot as d, Check as f, Cpu as p, Loader2 as m, Save as h } from "lucide-react";
8
+ import { Fragment as g, jsx as _, jsxs as v } from "react/jsx-runtime";
9
+ import { Badge as y, GlassCard as b, Switch as x } from "@burdenoff/fe-libs/ui";
10
+ //#region src/atheletebridge/components/ai/AiModelPicker.tsx
11
+ var S = (e) => `${e.provider}::${e.model}`;
12
+ function C({ className: C }) {
13
+ let w = t(), T = i(), E = n(), D = r(), [O, k] = u(null), A = l(() => w.data ?? [], [w.data]), j = l(() => A.find((e) => e.isDefault) ?? null, [A]), M = T.data ? S(T.data) : j ? S(j) : "", N = l(() => {
14
+ let e = T.data;
15
+ return !e || A.some((t) => S(t) === S(e)) ? A : [{
16
+ provider: e.provider,
17
+ model: e.model,
18
+ label: "Saved by this workspace",
19
+ isDefault: !1,
20
+ capabilities: []
21
+ }, ...A];
22
+ }, [A, T.data]), P = O ?? M, F = N.find((e) => S(e) === P) ?? null, I = !!O && O !== M, L = T.data?.autoPilotEnabled ?? !1, R = T.data?.autoPilotLastRunAt ?? null;
23
+ return /* @__PURE__ */ _(b, {
24
+ treatment: "insight",
25
+ className: C,
26
+ children: /* @__PURE__ */ v("div", {
27
+ className: "p-6",
28
+ children: [
29
+ /* @__PURE__ */ v("div", {
30
+ className: "flex items-start gap-3",
31
+ children: [/* @__PURE__ */ _("div", {
32
+ className: "flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary",
33
+ children: /* @__PURE__ */ _(p, {
34
+ className: "h-5 w-5",
35
+ "aria-hidden": "true"
36
+ })
37
+ }), /* @__PURE__ */ v("div", {
38
+ className: "min-w-0 flex-1",
39
+ children: [/* @__PURE__ */ _("h2", {
40
+ className: "text-lg font-semibold text-text-primary",
41
+ children: "Model"
42
+ }), /* @__PURE__ */ _("p", {
43
+ className: "mt-1 text-sm text-text-secondary",
44
+ children: "The provider and model every AthleteBridge decision runs on. A named provider is a first preference, not a lock — the service still falls back through the rest of the chain if it cannot answer."
45
+ })]
46
+ })]
47
+ }),
48
+ /* @__PURE__ */ v("div", {
49
+ className: "mt-5 grid grid-cols-1 gap-4 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-end",
50
+ children: [/* @__PURE__ */ _(o, {
51
+ label: "Provider and model",
52
+ htmlFor: "ai-model",
53
+ children: /* @__PURE__ */ v("select", {
54
+ id: "ai-model",
55
+ className: s,
56
+ value: P,
57
+ disabled: w.isLoading || N.length === 0,
58
+ onChange: (e) => k(e.target.value),
59
+ children: [N.length === 0 && /* @__PURE__ */ _("option", {
60
+ value: "",
61
+ children: "No models available"
62
+ }), N.map((e) => /* @__PURE__ */ v("option", {
63
+ value: S(e),
64
+ children: [
65
+ e.label,
66
+ " — ",
67
+ e.provider,
68
+ "/",
69
+ e.model,
70
+ e.isDefault ? " (default)" : ""
71
+ ]
72
+ }, S(e)))]
73
+ })
74
+ }), /* @__PURE__ */ v("button", {
75
+ type: "button",
76
+ onClick: () => {
77
+ F && E.mutate({
78
+ provider: F.provider,
79
+ model: F.model
80
+ }, { onSuccess: () => k(null) });
81
+ },
82
+ disabled: !I || !F || E.isPending,
83
+ className: "inline-flex h-[2.625rem] items-center justify-center gap-1.5 rounded-lg bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:cursor-not-allowed disabled:opacity-60",
84
+ children: [E.isPending ? /* @__PURE__ */ _(m, { className: "h-4 w-4 animate-spin" }) : /* @__PURE__ */ _(h, { className: "h-4 w-4" }), "Save model"]
85
+ })]
86
+ }),
87
+ /* @__PURE__ */ v("div", {
88
+ className: "mt-3 flex flex-wrap items-center gap-2 text-sm text-text-secondary",
89
+ children: [T.isLoading ? /* @__PURE__ */ v("span", {
90
+ className: "inline-flex items-center gap-1.5",
91
+ children: [/* @__PURE__ */ _(m, { className: "h-3.5 w-3.5 animate-spin" }), " Loading workspace configuration…"]
92
+ }) : T.data ? /* @__PURE__ */ v(g, { children: [
93
+ /* @__PURE__ */ _("span", { children: "In use:" }),
94
+ /* @__PURE__ */ v(y, {
95
+ variant: "secondary",
96
+ children: [
97
+ T.data.provider,
98
+ "/",
99
+ T.data.model
100
+ ]
101
+ }),
102
+ F?.isDefault && M === S(F) && /* @__PURE__ */ _(y, {
103
+ variant: "outline",
104
+ children: "Platform default"
105
+ }),
106
+ /* @__PURE__ */ v("span", {
107
+ className: "text-xs text-text-muted",
108
+ children: ["Saved ", a(T.data.updatedAt)]
109
+ })
110
+ ] }) : /* @__PURE__ */ v("span", { children: [
111
+ "This workspace has not chosen a model, so decisions run on the platform default chain",
112
+ j ? ` (${j.provider}/${j.model})` : "",
113
+ "."
114
+ ] }), E.isSuccess && !I && /* @__PURE__ */ v("span", {
115
+ className: "inline-flex items-center gap-1 text-xs text-status-success-text",
116
+ children: [/* @__PURE__ */ _(f, { className: "h-3.5 w-3.5" }), " Saved"]
117
+ })]
118
+ }),
119
+ F && F.capabilities.length > 0 && /* @__PURE__ */ _("div", {
120
+ className: "mt-2 flex flex-wrap gap-1.5",
121
+ children: F.capabilities.map((e) => /* @__PURE__ */ _("span", {
122
+ className: "inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary",
123
+ children: e
124
+ }, e))
125
+ }),
126
+ w.isError && /* @__PURE__ */ _(c, {
127
+ className: "mt-4",
128
+ error: w.error
129
+ }),
130
+ E.isError && /* @__PURE__ */ _(c, {
131
+ className: "mt-4",
132
+ error: E.error
133
+ }),
134
+ /* @__PURE__ */ v("div", {
135
+ className: "mt-6 border-t border-border-seam pt-5",
136
+ children: [
137
+ /* @__PURE__ */ v("div", {
138
+ className: "flex items-start justify-between gap-4",
139
+ children: [/* @__PURE__ */ v("div", {
140
+ className: "min-w-0",
141
+ children: [
142
+ /* @__PURE__ */ v("label", {
143
+ htmlFor: "ai-autopilot",
144
+ className: "flex items-center gap-2 text-sm font-medium text-text-primary",
145
+ children: [/* @__PURE__ */ _(d, {
146
+ className: "h-4 w-4",
147
+ "aria-hidden": "true"
148
+ }), "Autopilot"]
149
+ }),
150
+ /* @__PURE__ */ v("p", {
151
+ className: "mt-1 text-sm text-text-secondary",
152
+ children: [
153
+ "When on, a scheduled tick may assess athletes on this workspace's programs and record a ",
154
+ /* @__PURE__ */ _("strong", {
155
+ className: "font-medium text-text-primary",
156
+ children: "PROPOSED"
157
+ }),
158
+ " ",
159
+ "adjustment. It never changes prescribed training load — a coach still has to accept or override every proposal."
160
+ ]
161
+ }),
162
+ /* @__PURE__ */ v("p", {
163
+ className: "mt-1 text-xs text-text-muted",
164
+ children: [
165
+ "The loop is also gated per deployment by",
166
+ " ",
167
+ /* @__PURE__ */ _("code", {
168
+ className: "rounded bg-bg-sunken px-1 py-0.5 font-mono",
169
+ children: "ATHELETEBRIDGE_AGENT_LOOP_ENABLED"
170
+ }),
171
+ ", which is off in production. Turning this on alone does not start anything."
172
+ ]
173
+ })
174
+ ]
175
+ }), /* @__PURE__ */ v("div", {
176
+ className: "flex shrink-0 items-center gap-2 pt-1",
177
+ children: [D.isPending && /* @__PURE__ */ _(m, { className: "h-4 w-4 animate-spin text-text-secondary" }), /* @__PURE__ */ _(x, {
178
+ id: "ai-autopilot",
179
+ checked: L,
180
+ disabled: T.isLoading || D.isPending,
181
+ onCheckedChange: (e) => D.mutate(e),
182
+ "aria-label": "Enable autopilot for this workspace"
183
+ })]
184
+ })]
185
+ }),
186
+ /* @__PURE__ */ _("p", {
187
+ className: "mt-3 text-xs text-text-muted",
188
+ children: R ? `A scheduled tick last considered this workspace on ${e(R)} (${a(R)}).` : "No scheduled tick has considered this workspace yet."
189
+ }),
190
+ D.isError && /* @__PURE__ */ _(c, {
191
+ className: "mt-4",
192
+ error: D.error
193
+ })
194
+ ]
195
+ })
196
+ ]
197
+ })
198
+ });
199
+ }
200
+ //#endregion
201
+ export { C as AiModelPicker };
202
+
203
+ //# sourceMappingURL=AiModelPicker.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AiModelPicker.js","names":[],"sources":["../../../../src/atheletebridge/components/ai/AiModelPicker.tsx"],"sourcesContent":["/**\n * AI model picker + autopilot control\n * @module atheletebridge/components/ai\n *\n * The workspace's saved (provider, model) pair — read from\n * `athWorkspaceAiConfig`, chosen from `athAiModelCatalog`, saved with\n * `athSetWorkspaceAiModel` — plus the per-workspace autopilot opt-in\n * (`athSetWorkspaceAutoPilot`).\n *\n * The autopilot copy is deliberately unglamorous. The loop only ever records a\n * PROPOSED adjustment that a coach still has to accept, and it is additionally\n * gated by the `ATHELETEBRIDGE_AGENT_LOOP_ENABLED` deployment kill switch,\n * which is OFF in production. A toggle that implies \"the AI now coaches for\n * you\" would be a lie in both directions, so it says exactly what it does.\n */\n\nimport { useMemo, useState } from 'react';\nimport { Bot, Check, Cpu, Loader2, Save } from 'lucide-react';\nimport { Badge, GlassCard, Switch } from '@burdenoff/fe-libs/ui';\nimport { FormField, fieldInputClass } from '../form';\nimport {\n useAiModelCatalog,\n useSetWorkspaceAiModel,\n useSetWorkspaceAutoPilot,\n useWorkspaceAiConfig,\n} from '../../hooks/useAthleteBridgeApi';\nimport type { AthAiModelInfo } from '../../types';\nimport { formatDate } from '../../utils/formatters';\nimport { timeAgo } from '../../utils/timeAgo';\nimport { AiErrorNotice } from './AiErrorNotice';\n\n/** Stable option key. Model ids are provider-specific, so both parts matter. */\nconst optionKey = (entry: Pick<AthAiModelInfo, 'provider' | 'model'>): string =>\n `${entry.provider}::${entry.model}`;\n\nexport function AiModelPicker({ className }: { className?: string }) {\n const catalog = useAiModelCatalog();\n const config = useWorkspaceAiConfig();\n const setModel = useSetWorkspaceAiModel();\n const setAutoPilot = useSetWorkspaceAutoPilot();\n\n const [draftKey, setDraftKey] = useState<string | null>(null);\n\n const catalogEntries = useMemo(() => catalog.data ?? [], [catalog.data]);\n const defaultEntry = useMemo(\n () => catalogEntries.find((entry) => entry.isDefault) ?? null,\n [catalogEntries]\n );\n\n // The saved pair, or the catalog default when the workspace has never chosen\n // one (a null config means \"using the platform default chain\", not an error).\n const savedKey = config.data\n ? optionKey(config.data)\n : defaultEntry\n ? optionKey(defaultEntry)\n : '';\n\n // A saved pair that is no longer in the catalog still has to be selectable,\n // or the select silently displays a DIFFERENT model than the one in force.\n const entries = useMemo(() => {\n const saved = config.data;\n if (!saved || catalogEntries.some((entry) => optionKey(entry) === optionKey(saved))) {\n return catalogEntries;\n }\n return [\n {\n provider: saved.provider,\n model: saved.model,\n label: 'Saved by this workspace',\n isDefault: false,\n capabilities: [],\n },\n ...catalogEntries,\n ];\n }, [catalogEntries, config.data]);\n const selectedKey = draftKey ?? savedKey;\n const selectedEntry = entries.find((entry) => optionKey(entry) === selectedKey) ?? null;\n const isDirty = Boolean(draftKey) && draftKey !== savedKey;\n\n const autoPilotEnabled = config.data?.autoPilotEnabled ?? false;\n const lastRunAt = config.data?.autoPilotLastRunAt ?? null;\n\n const handleSave = () => {\n if (!selectedEntry) {\n return;\n }\n setModel.mutate(\n { provider: selectedEntry.provider, model: selectedEntry.model },\n { onSuccess: () => setDraftKey(null) }\n );\n };\n\n return (\n <GlassCard treatment=\"insight\" className={className}>\n <div className=\"p-6\">\n <div className=\"flex items-start gap-3\">\n <div className=\"flex h-10 w-10 shrink-0 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <Cpu className=\"h-5 w-5\" aria-hidden=\"true\" />\n </div>\n <div className=\"min-w-0 flex-1\">\n <h2 className=\"text-lg font-semibold text-text-primary\">Model</h2>\n <p className=\"mt-1 text-sm text-text-secondary\">\n The provider and model every AthleteBridge decision runs on. A named provider is a\n first preference, not a lock — the service still falls back through the rest of the\n chain if it cannot answer.\n </p>\n </div>\n </div>\n\n <div className=\"mt-5 grid grid-cols-1 gap-4 sm:grid-cols-[minmax(0,1fr)_auto] sm:items-end\">\n <FormField label=\"Provider and model\" htmlFor=\"ai-model\">\n <select\n id=\"ai-model\"\n className={fieldInputClass}\n value={selectedKey}\n disabled={catalog.isLoading || entries.length === 0}\n onChange={(event) => setDraftKey(event.target.value)}\n >\n {entries.length === 0 && <option value=\"\">No models available</option>}\n {entries.map((entry) => (\n <option key={optionKey(entry)} value={optionKey(entry)}>\n {entry.label} — {entry.provider}/{entry.model}\n {entry.isDefault ? ' (default)' : ''}\n </option>\n ))}\n </select>\n </FormField>\n <button\n type=\"button\"\n onClick={handleSave}\n disabled={!isDirty || !selectedEntry || setModel.isPending}\n className=\"inline-flex h-[2.625rem] items-center justify-center gap-1.5 rounded-lg bg-action-primary-bg px-4 text-sm font-medium text-action-primary-text transition-colors hover:bg-action-primary-bg/90 disabled:cursor-not-allowed disabled:opacity-60\"\n >\n {setModel.isPending ? (\n <Loader2 className=\"h-4 w-4 animate-spin\" />\n ) : (\n <Save className=\"h-4 w-4\" />\n )}\n Save model\n </button>\n </div>\n\n <div className=\"mt-3 flex flex-wrap items-center gap-2 text-sm text-text-secondary\">\n {config.isLoading ? (\n <span className=\"inline-flex items-center gap-1.5\">\n <Loader2 className=\"h-3.5 w-3.5 animate-spin\" /> Loading workspace configuration…\n </span>\n ) : config.data ? (\n <>\n <span>In use:</span>\n <Badge variant=\"secondary\">\n {config.data.provider}/{config.data.model}\n </Badge>\n {selectedEntry?.isDefault && savedKey === optionKey(selectedEntry) && (\n <Badge variant=\"outline\">Platform default</Badge>\n )}\n <span className=\"text-xs text-text-muted\">\n Saved {timeAgo(config.data.updatedAt)}\n </span>\n </>\n ) : (\n <span>\n This workspace has not chosen a model, so decisions run on the platform default chain\n {defaultEntry ? ` (${defaultEntry.provider}/${defaultEntry.model})` : ''}.\n </span>\n )}\n {setModel.isSuccess && !isDirty && (\n <span className=\"inline-flex items-center gap-1 text-xs text-status-success-text\">\n <Check className=\"h-3.5 w-3.5\" /> Saved\n </span>\n )}\n </div>\n\n {selectedEntry && selectedEntry.capabilities.length > 0 && (\n <div className=\"mt-2 flex flex-wrap gap-1.5\">\n {selectedEntry.capabilities.map((capability) => (\n <span\n key={capability}\n className=\"inline-flex items-center rounded-full bg-bg-sunken px-2 py-0.5 text-xs text-text-secondary\"\n >\n {capability}\n </span>\n ))}\n </div>\n )}\n\n {catalog.isError && <AiErrorNotice className=\"mt-4\" error={catalog.error} />}\n {setModel.isError && <AiErrorNotice className=\"mt-4\" error={setModel.error} />}\n\n {/* Autopilot */}\n <div className=\"mt-6 border-t border-border-seam pt-5\">\n <div className=\"flex items-start justify-between gap-4\">\n <div className=\"min-w-0\">\n <label\n htmlFor=\"ai-autopilot\"\n className=\"flex items-center gap-2 text-sm font-medium text-text-primary\"\n >\n <Bot className=\"h-4 w-4\" aria-hidden=\"true\" />\n Autopilot\n </label>\n <p className=\"mt-1 text-sm text-text-secondary\">\n When on, a scheduled tick may assess athletes on this workspace&apos;s programs and\n record a <strong className=\"font-medium text-text-primary\">PROPOSED</strong>{' '}\n adjustment. It never changes prescribed training load — a coach still has to accept\n or override every proposal.\n </p>\n <p className=\"mt-1 text-xs text-text-muted\">\n The loop is also gated per deployment by{' '}\n <code className=\"rounded bg-bg-sunken px-1 py-0.5 font-mono\">\n ATHELETEBRIDGE_AGENT_LOOP_ENABLED\n </code>\n , which is off in production. Turning this on alone does not start anything.\n </p>\n </div>\n <div className=\"flex shrink-0 items-center gap-2 pt-1\">\n {setAutoPilot.isPending && (\n <Loader2 className=\"h-4 w-4 animate-spin text-text-secondary\" />\n )}\n <Switch\n id=\"ai-autopilot\"\n checked={autoPilotEnabled}\n disabled={config.isLoading || setAutoPilot.isPending}\n onCheckedChange={(checked) => setAutoPilot.mutate(checked)}\n aria-label=\"Enable autopilot for this workspace\"\n />\n </div>\n </div>\n <p className=\"mt-3 text-xs text-text-muted\">\n {lastRunAt\n ? `A scheduled tick last considered this workspace on ${formatDate(lastRunAt)} (${timeAgo(lastRunAt)}).`\n : 'No scheduled tick has considered this workspace yet.'}\n </p>\n {setAutoPilot.isError && <AiErrorNotice className=\"mt-4\" error={setAutoPilot.error} />}\n </div>\n </div>\n </GlassCard>\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import { AthAgentRun } from '../../types';
2
+
3
+ interface DecisionCardProps {
4
+ run: AthAgentRun;
5
+ /** Highlighted because it is the run selected in the activity feed. */
6
+ isFocused?: boolean;
7
+ className?: string;
8
+ }
9
+ export declare function DecisionCard({ run, isFocused, className }: DecisionCardProps): import("react").JSX.Element;
10
+ export {};
11
+ //# sourceMappingURL=DecisionCard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"DecisionCard.d.ts","sourceRoot":"","sources":["../../../../src/atheletebridge/components/ai/DecisionCard.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAYH,OAAO,KAAK,EAAE,WAAW,EAAmB,MAAM,aAAa,CAAC;AAqBhE,UAAU,iBAAiB;IACzB,GAAG,EAAE,WAAW,CAAC;IACjB,uEAAuE;IACvE,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA6LD,wBAAgB,YAAY,CAAC,EAAE,GAAG,EAAE,SAAiB,EAAE,SAAS,EAAE,EAAE,iBAAiB,+BAwLpF"}