@burdenoff/microfe-subscriberbot 2026.731.1 → 2026.827.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. package/dist/subscriberbot/SubscriberBotRoutes.js +1 -1
  2. package/dist/subscriberbot/SubscriberBotRoutes.js.map +1 -1
  3. package/dist/subscriberbot/components/viz.js +51 -27
  4. package/dist/subscriberbot/components/viz.js.map +1 -1
  5. package/dist/subscriberbot/context/SubscriberBotContext.js +1 -1
  6. package/dist/subscriberbot/context/SubscriberBotContext.js.map +1 -1
  7. package/dist/subscriberbot/hooks/index.d.ts +1 -1
  8. package/dist/subscriberbot/hooks/index.d.ts.map +1 -1
  9. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts +12 -1
  10. package/dist/subscriberbot/hooks/useSubscriberBotApi.d.ts.map +1 -1
  11. package/dist/subscriberbot/hooks/useSubscriberBotApi.js +82 -56
  12. package/dist/subscriberbot/hooks/useSubscriberBotApi.js.map +1 -1
  13. package/dist/subscriberbot/pages/AssetVaultPage.d.ts.map +1 -1
  14. package/dist/subscriberbot/pages/AssetVaultPage.js +134 -78
  15. package/dist/subscriberbot/pages/AssetVaultPage.js.map +1 -1
  16. package/dist/subscriberbot/pages/InvoicesPage.d.ts +3 -2
  17. package/dist/subscriberbot/pages/InvoicesPage.d.ts.map +1 -1
  18. package/dist/subscriberbot/pages/InvoicesPage.js +43 -31
  19. package/dist/subscriberbot/pages/InvoicesPage.js.map +1 -1
  20. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts +3 -1
  21. package/dist/subscriberbot/pages/agents/AgentDetailPage.d.ts.map +1 -1
  22. package/dist/subscriberbot/pages/agents/AgentDetailPage.js +195 -159
  23. package/dist/subscriberbot/pages/agents/AgentDetailPage.js.map +1 -1
  24. package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts +4 -2
  25. package/dist/subscriberbot/pages/providers/ProviderDetailPage.d.ts.map +1 -1
  26. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js +368 -266
  27. package/dist/subscriberbot/pages/providers/ProviderDetailPage.js.map +1 -1
  28. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js +1 -1
  29. package/dist/subscriberbot/pages/relationships/RelationshipDetailPage.js.map +1 -1
  30. package/dist/subscriberbot/types/index.d.ts +37 -0
  31. package/dist/subscriberbot/types/index.d.ts.map +1 -1
  32. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"AgentDetailPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/agents/AgentDetailPage.tsx"],"sourcesContent":["/**\n * Agent detail\n * @module subscriberbot/pages/agents\n *\n * A single AI agent: its kind, posture, last run, and the autonomous policies\n * that bound it. Reads `subAgent(id)`; changes posture via `subSetAgentStatus`.\n * The \"Run history\" timeline is derived from the agent's real `lastRunAt` and\n * each policy's real `lastTriggeredAt` — never mocked.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router-dom';\nimport {\n ArrowLeft,\n Bot,\n Search,\n RefreshCw,\n DollarSign,\n Mail,\n Building2,\n ShieldCheck,\n Handshake,\n ArrowLeftRight,\n ConciergeBell,\n Plus,\n Clock,\n Zap,\n ListChecks,\n History,\n type LucideIcon,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n EmptyState,\n Modal,\n MetricsCard,\n Timeline,\n LoadingView,\n ErrorView,\n Section,\n type TimelineItem,\n} from '../../components';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useAgent, useSetAgentStatus, useCreatePolicy } from '../../hooks/useSubscriberBotApi';\nimport { formatEnumLabel, formatRelativeTime } from '../../utils/formatters';\nimport type { SubAgentKind, SubAgentStatus, SubPolicyAction, SubPolicy } from '../../types';\n\nconst STATUS_OPTIONS: SubAgentStatus[] = ['DISABLED', 'SUGGEST_ONLY', 'AUTONOMOUS'];\n\nconst POLICY_ACTIONS: SubPolicyAction[] = [\n 'ALERT',\n 'CREATE_TASK',\n 'RENEW',\n 'CANCEL',\n 'PAUSE',\n 'UPGRADE',\n 'DOWNGRADE',\n];\n\nconst KIND_ICON: Record<SubAgentKind, LucideIcon> = {\n DISCOVERY: Search,\n RENEWAL: RefreshCw,\n COST: DollarSign,\n NEWSLETTER: Mail,\n VENDOR: Building2,\n COMPLIANCE: ShieldCheck,\n NEGOTIATION: Handshake,\n MIGRATION: ArrowLeftRight,\n CONCIERGE: ConciergeBell,\n};\n\n/** Map a policy action to a timeline tone (semantic only). */\nfunction actionTone(action: SubPolicyAction): NonNullable<TimelineItem['tone']> {\n switch (action) {\n case 'RENEW':\n case 'UPGRADE':\n return 'positive';\n case 'CANCEL':\n case 'PAUSE':\n case 'DOWNGRADE':\n case 'ALERT':\n return 'warning';\n default:\n return 'default';\n }\n}\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\n// ---------------------------------------------------------------------------\n// Read-only enabled indicator (there is no policy-toggle mutation on the svc\n// contract, so this reflects the real `isEnabled` state without pretending to\n// mutate it).\n// ---------------------------------------------------------------------------\nfunction EnabledPill({ enabled }: { enabled: boolean }) {\n return (\n <span\n className={\n enabled\n ? 'inline-flex items-center gap-1.5 rounded-full bg-status-success-bg-subtle px-2.5 py-0.5 text-xs font-medium text-status-success-text'\n : 'inline-flex items-center gap-1.5 rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary'\n }\n >\n <span\n aria-hidden\n className=\"size-1.5 rounded-full bg-current\"\n style={{ opacity: enabled ? 1 : 0.6 }}\n />\n {enabled ? 'Enabled' : 'Disabled'}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Add policy modal → subCreatePolicy\n// ---------------------------------------------------------------------------\n\nfunction AddPolicyModal({ agentId, onClose }: { agentId: string; onClose: () => void }) {\n const create = useCreatePolicy();\n const [name, setName] = useState('');\n const [action, setAction] = useState<SubPolicyAction>('ALERT');\n const [description, setDescription] = useState('');\n const [condition, setCondition] = useState('');\n const [isEnabled, setIsEnabled] = useState(true);\n const [formError, setFormError] = useState<string | null>(null);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim()) {\n setFormError('A policy name is required.');\n return;\n }\n let parsedCondition: Record<string, unknown> | undefined;\n if (condition.trim()) {\n try {\n parsedCondition = JSON.parse(condition) as Record<string, unknown>;\n } catch {\n setFormError('Condition must be valid JSON (e.g. {\"amountOver\": 100}).');\n return;\n }\n }\n create.mutate(\n {\n agentId,\n name: name.trim(),\n action,\n isEnabled,\n ...(description.trim() ? { description: description.trim() } : {}),\n ...(parsedCondition ? { condition: parsedCondition } : {}),\n },\n {\n onSuccess: () => onClose(),\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not add policy.'),\n }\n );\n };\n\n return (\n <Modal title=\"Add policy\" onClose={onClose} maxWidthClassName=\"max-w-xl\">\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n <div>\n <label htmlFor=\"policy-name\" className={labelCls}>\n Name <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"policy-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Alert on price hike over 20%\"\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"policy-action\" className={labelCls}>\n Action\n </label>\n <select\n id=\"policy-action\"\n value={action}\n onChange={(e) => setAction(e.target.value as SubPolicyAction)}\n className={inputCls}\n >\n {POLICY_ACTIONS.map((a) => (\n <option key={a} value={a}>\n {a.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"policy-condition\" className={labelCls}>\n Condition <span className=\"text-text-secondary\">(optional JSON)</span>\n </label>\n <textarea\n id=\"policy-condition\"\n value={condition}\n onChange={(e) => setCondition(e.target.value)}\n rows={3}\n placeholder={'{ \"priceIncreasePct\": 20 }'}\n className={`${inputCls} font-mono`}\n />\n </div>\n <div>\n <label htmlFor=\"policy-desc\" className={labelCls}>\n Description\n </label>\n <textarea\n id=\"policy-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n className={inputCls}\n />\n </div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={isEnabled}\n onChange={(e) => setIsEnabled(e.target.checked)}\n className=\"size-4 rounded border-border-subtle\"\n />\n Enabled\n </label>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Adding…' : 'Add policy'}\n </button>\n </div>\n </form>\n </Modal>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Policy card\n// ---------------------------------------------------------------------------\nfunction PolicyCard({ policy }: { policy: SubPolicy }) {\n return (\n <GlassCard treatment=\"metric\" className=\"flex flex-col p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"text-sm font-semibold text-text-primary\">{policy.name}</p>\n <EnabledPill enabled={policy.isEnabled} />\n </div>\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <span className=\"inline-flex items-center gap-1.5 rounded-md bg-[var(--color-accent-soft)] px-2 py-0.5 text-[11px] font-medium text-text-primary\">\n <ShieldCheck className=\"h-3 w-3\" aria-hidden /> {formatEnumLabel(policy.action)}\n </span>\n <span className=\"inline-flex items-center gap-1 rounded-md bg-bg-sunken px-2 py-0.5 text-[11px] font-medium text-text-secondary tabular-nums\">\n Triggered {policy.triggerCount}×\n </span>\n </div>\n {policy.description && (\n <p className=\"mt-2 line-clamp-2 text-xs text-text-secondary\">{policy.description}</p>\n )}\n <p className=\"mt-2 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden />\n {policy.lastTriggeredAt\n ? `Last triggered ${formatRelativeTime(policy.lastTriggeredAt)}`\n : 'Not yet triggered'}\n </p>\n </GlassCard>\n );\n}\n\nexport function AgentDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useSubscriberBot();\n const { data: agent, isLoading, isError, refetch } = useAgent(id);\n const setAgentStatus = useSetAgentStatus();\n const [actionError, setActionError] = useState<string | null>(null);\n const [showAddPolicy, setShowAddPolicy] = useState(false);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Agent\">\n <LoadingView label=\"Loading agent…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Agent\">\n <ErrorView message=\"Could not load this agent.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!agent) {\n return (\n <PageLayout title=\"Agent\">\n <EmptyState\n illustration=\"empty-data\"\n title=\"Agent not found\"\n description=\"It may have been removed, or you may not have access to it.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Back to agents\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const a = agent;\n const Icon = KIND_ICON[a.kind] ?? Bot;\n const policies = a.policies ?? [];\n const enabledCount = policies.filter((p) => p.isEnabled).length;\n const totalTriggers = policies.reduce((s, p) => s + (p.triggerCount || 0), 0);\n\n // --- Run history: derived from real timestamps, sorted most-recent first --\n const events: Array<{ ts: number; item: TimelineItem }> = [];\n if (a.lastRunAt) {\n events.push({\n ts: new Date(a.lastRunAt).getTime(),\n item: {\n title: 'Agent run',\n sub: 'Latest autonomous cycle',\n meta: formatRelativeTime(a.lastRunAt),\n tone: 'positive',\n },\n });\n }\n for (const p of policies) {\n if (p.lastTriggeredAt) {\n events.push({\n ts: new Date(p.lastTriggeredAt).getTime(),\n item: {\n title: p.name,\n sub: `${formatEnumLabel(p.action)} · fired ${p.triggerCount}×`,\n meta: formatRelativeTime(p.lastTriggeredAt),\n tone: actionTone(p.action),\n },\n });\n }\n }\n events.sort((x, y) => y.ts - x.ts);\n const timelineItems = events.map((e) => e.item);\n\n return (\n <PageLayout\n title={a.name}\n description={`${formatEnumLabel(a.kind)} agent`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n {/* Identity + posture header */}\n <GlassCard treatment=\"glass\" glow={a.status === 'AUTONOMOUS'} className=\"p-5\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex items-start gap-4\">\n <span className=\"flex size-12 shrink-0 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <Icon className=\"h-6 w-6\" />\n </span>\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"text-lg font-semibold text-text-primary\">{a.name}</p>\n <StatusBadge status={a.status} />\n </div>\n <p className=\"mt-1 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden />\n {a.lastRunAt ? `Last run ${formatRelativeTime(a.lastRunAt)}` : 'Never run'}\n </p>\n {a.description && (\n <p className=\"mt-2 max-w-2xl text-sm text-text-secondary\">{a.description}</p>\n )}\n </div>\n </div>\n\n {/* Posture control */}\n <div className=\"w-full sm:w-56 sm:shrink-0\">\n <label\n htmlFor=\"agent-posture\"\n className=\"mb-1 block text-xs font-medium text-text-secondary\"\n >\n Operating posture\n </label>\n <select\n id=\"agent-posture\"\n value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) => {\n setActionError(null);\n setAgentStatus.mutate(\n { id: a.id, status: e.target.value as SubAgentStatus },\n {\n onError: (err) =>\n setActionError(\n err instanceof Error ? err.message : 'Could not change posture.'\n ),\n }\n );\n }}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] disabled:opacity-50\"\n >\n {STATUS_OPTIONS.map((s) => (\n <option key={s} value={s}>\n {formatEnumLabel(s)}\n </option>\n ))}\n </select>\n <p className=\"mt-1.5 text-[11px] leading-snug text-text-secondary\">\n Disabled never acts · Suggest-only proposes · Autonomous acts within its policies.\n </p>\n </div>\n </div>\n </GlassCard>\n\n {actionError && (\n <div className=\"mt-4 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {actionError}\n </div>\n )}\n\n {/* Policy stats (computed) */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<ListChecks className=\"h-5 w-5\" />}\n value={policies.length}\n label=\"Policies\"\n />\n <MetricsCard\n icon={<ShieldCheck className=\"h-5 w-5\" />}\n value={enabledCount}\n label=\"Enabled\"\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={totalTriggers}\n label=\"Total triggers\"\n />\n </div>\n\n {/* Policies + Run history */}\n <div className=\"mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <Section\n title=\"Policies\"\n description=\"The autonomous rules that bound this agent\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowAddPolicy(true)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <Plus className=\"h-3.5 w-3.5\" /> Add policy\n </button>\n }\n >\n {policies.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No policies\"\n description=\"Policies define what this agent may do autonomously, and what it must alert on.\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowAddPolicy(true)}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Add policy\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {policies.map((policy) => (\n <PolicyCard key={policy.id} policy={policy} />\n ))}\n </div>\n )}\n </Section>\n </div>\n\n <div className=\"lg:col-span-1\">\n <Section title=\"Run history\" description=\"Recent agent activity\">\n <GlassCard treatment=\"metric\" className=\"p-5\">\n {timelineItems.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center gap-2 py-6 text-center\">\n <History className=\"h-8 w-8 text-text-secondary\" aria-hidden />\n <p className=\"text-sm font-medium text-text-primary\">No runs yet</p>\n <p className=\"text-xs text-text-secondary\">\n Activity appears here once the agent runs or a policy fires.\n </p>\n </div>\n ) : (\n <Timeline items={timelineItems} />\n )}\n </GlassCard>\n </Section>\n </div>\n </div>\n\n {showAddPolicy && <AddPolicyModal agentId={a.id} onClose={() => setShowAddPolicy(false)} />}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"AgentDetailPage.js","names":[],"sources":["../../../../src/subscriberbot/pages/agents/AgentDetailPage.tsx"],"sourcesContent":["/**\n * Agent detail\n * @module subscriberbot/pages/agents\n *\n * A single AI agent: its kind, posture, last run, and the autonomous policies\n * that bound it. Reads `subAgent(id)`; changes posture via `subSetAgentStatus`.\n * The \"Run history\" timeline is derived from the agent's real `lastRunAt` and\n * each policy's real `lastTriggeredAt` — never mocked. Each policy card also\n * renders its stored `condition` JSON (the rule the agent evaluates before it\n * acts), so a condition entered in \"Add policy\" is visible after it is saved.\n */\n\nimport { useState } from 'react';\nimport { useParams } from 'react-router';\nimport {\n ArrowLeft,\n Bot,\n Search,\n RefreshCw,\n DollarSign,\n Mail,\n Building2,\n ShieldCheck,\n Handshake,\n ArrowLeftRight,\n ConciergeBell,\n Plus,\n Clock,\n Zap,\n ListChecks,\n History,\n SlidersHorizontal,\n type LucideIcon,\n} from 'lucide-react';\nimport { GlassCard } from '@burdenoff/fe-libs/ui';\nimport {\n PageLayout,\n StatusBadge,\n EmptyState,\n Modal,\n MetricsCard,\n Timeline,\n LoadingView,\n ErrorView,\n Section,\n type TimelineItem,\n} from '../../components';\nimport { useSubscriberBot } from '../../context/SubscriberBotContext';\nimport { useAgent, useSetAgentStatus, useCreatePolicy } from '../../hooks/useSubscriberBotApi';\nimport { formatEnumLabel, formatNumber, formatRelativeTime } from '../../utils/formatters';\nimport type { SubAgentKind, SubAgentStatus, SubPolicyAction, SubPolicy } from '../../types';\n\nconst STATUS_OPTIONS: SubAgentStatus[] = ['DISABLED', 'SUGGEST_ONLY', 'AUTONOMOUS'];\n\nconst POLICY_ACTIONS: SubPolicyAction[] = [\n 'ALERT',\n 'CREATE_TASK',\n 'RENEW',\n 'CANCEL',\n 'PAUSE',\n 'UPGRADE',\n 'DOWNGRADE',\n];\n\nconst KIND_ICON: Record<SubAgentKind, LucideIcon> = {\n DISCOVERY: Search,\n RENEWAL: RefreshCw,\n COST: DollarSign,\n NEWSLETTER: Mail,\n VENDOR: Building2,\n COMPLIANCE: ShieldCheck,\n NEGOTIATION: Handshake,\n MIGRATION: ArrowLeftRight,\n CONCIERGE: ConciergeBell,\n};\n\n/** Map a policy action to a timeline tone (semantic only). */\nfunction actionTone(action: SubPolicyAction): NonNullable<TimelineItem['tone']> {\n switch (action) {\n case 'RENEW':\n case 'UPGRADE':\n return 'positive';\n case 'CANCEL':\n case 'PAUSE':\n case 'DOWNGRADE':\n case 'ALERT':\n return 'warning';\n default:\n return 'default';\n }\n}\n\nconst inputCls =\n 'w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary placeholder:text-text-secondary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)]';\nconst labelCls = 'mb-1 block text-xs font-medium text-text-secondary';\n\n/** `unusedDays` / `min_monthly_spend` → \"Unused days\" / \"Min monthly spend\". */\nfunction humanizeConditionKey(key: string): string {\n const spaced = key\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .replace(/[_-]+/g, ' ')\n .trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\n/** Render one condition value without losing information or inventing any. */\nfunction formatConditionValue(value: unknown): string {\n if (value === null || value === undefined) return '—';\n if (typeof value === 'string') return value;\n if (typeof value === 'number') return formatNumber(value);\n if (typeof value === 'boolean') return value ? 'Yes' : 'No';\n if (Array.isArray(value)) return value.map(formatConditionValue).join(', ');\n return JSON.stringify(value);\n}\n\n/**\n * Flatten a policy's real `condition` JSON into readable chips. The svc types\n * it as `JSON!` (DB default `{}`), so anything that is not a plain object —\n * or an empty one — yields no chips and the card simply omits the section.\n */\nfunction conditionEntries(\n condition: Record<string, unknown> | null | undefined\n): Array<{ key: string; value: string }> {\n if (!condition || Array.isArray(condition)) return [];\n return Object.entries(condition)\n .filter(([, value]) => value !== null && value !== undefined && value !== '')\n .map(([key, value]) => ({ key, value: formatConditionValue(value) }));\n}\n\n// ---------------------------------------------------------------------------\n// Read-only enabled indicator (there is no policy-toggle mutation on the svc\n// contract, so this reflects the real `isEnabled` state without pretending to\n// mutate it).\n// ---------------------------------------------------------------------------\nfunction EnabledPill({ enabled }: { enabled: boolean }) {\n return (\n <span\n className={\n enabled\n ? 'inline-flex items-center gap-1.5 rounded-full bg-status-success-bg-subtle px-2.5 py-0.5 text-xs font-medium text-status-success-text'\n : 'inline-flex items-center gap-1.5 rounded-full bg-bg-sunken px-2.5 py-0.5 text-xs font-medium text-text-secondary'\n }\n >\n <span\n aria-hidden\n className=\"size-1.5 rounded-full bg-current\"\n style={{ opacity: enabled ? 1 : 0.6 }}\n />\n {enabled ? 'Enabled' : 'Disabled'}\n </span>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Add policy modal → subCreatePolicy\n// ---------------------------------------------------------------------------\n\nfunction AddPolicyModal({ agentId, onClose }: { agentId: string; onClose: () => void }) {\n const create = useCreatePolicy();\n const [name, setName] = useState('');\n const [action, setAction] = useState<SubPolicyAction>('ALERT');\n const [description, setDescription] = useState('');\n const [condition, setCondition] = useState('');\n const [isEnabled, setIsEnabled] = useState(true);\n const [formError, setFormError] = useState<string | null>(null);\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n setFormError(null);\n if (!name.trim()) {\n setFormError('A policy name is required.');\n return;\n }\n let parsedCondition: Record<string, unknown> | undefined;\n if (condition.trim()) {\n try {\n parsedCondition = JSON.parse(condition) as Record<string, unknown>;\n } catch {\n setFormError('Condition must be valid JSON (e.g. {\"amountOver\": 100}).');\n return;\n }\n }\n create.mutate(\n {\n agentId,\n name: name.trim(),\n action,\n isEnabled,\n ...(description.trim() ? { description: description.trim() } : {}),\n ...(parsedCondition ? { condition: parsedCondition } : {}),\n },\n {\n onSuccess: () => onClose(),\n onError: (err) =>\n setFormError(err instanceof Error ? err.message : 'Could not add policy.'),\n }\n );\n };\n\n return (\n <Modal title=\"Add policy\" onClose={onClose} maxWidthClassName=\"max-w-xl\">\n <form onSubmit={handleSubmit} className=\"space-y-4\">\n {formError && (\n <div className=\"rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {formError}\n </div>\n )}\n <div>\n <label htmlFor=\"policy-name\" className={labelCls}>\n Name <span className=\"text-status-error-text\">*</span>\n </label>\n <input\n id=\"policy-name\"\n type=\"text\"\n value={name}\n onChange={(e) => setName(e.target.value)}\n placeholder=\"e.g. Alert on price hike over 20%\"\n className={inputCls}\n required\n />\n </div>\n <div>\n <label htmlFor=\"policy-action\" className={labelCls}>\n Action\n </label>\n <select\n id=\"policy-action\"\n value={action}\n onChange={(e) => setAction(e.target.value as SubPolicyAction)}\n className={inputCls}\n >\n {POLICY_ACTIONS.map((a) => (\n <option key={a} value={a}>\n {a.replace(/_/g, ' ')}\n </option>\n ))}\n </select>\n </div>\n <div>\n <label htmlFor=\"policy-condition\" className={labelCls}>\n Condition <span className=\"text-text-secondary\">(optional JSON)</span>\n </label>\n <textarea\n id=\"policy-condition\"\n value={condition}\n onChange={(e) => setCondition(e.target.value)}\n rows={3}\n placeholder={'{ \"priceIncreasePct\": 20 }'}\n className={`${inputCls} font-mono`}\n />\n </div>\n <div>\n <label htmlFor=\"policy-desc\" className={labelCls}>\n Description\n </label>\n <textarea\n id=\"policy-desc\"\n value={description}\n onChange={(e) => setDescription(e.target.value)}\n rows={2}\n className={inputCls}\n />\n </div>\n <label className=\"flex items-center gap-2 text-sm text-text-primary\">\n <input\n type=\"checkbox\"\n checked={isEnabled}\n onChange={(e) => setIsEnabled(e.target.checked)}\n className=\"size-4 rounded border-border-subtle\"\n />\n Enabled\n </label>\n <div className=\"flex justify-end gap-3\">\n <button\n type=\"button\"\n onClick={onClose}\n className=\"rounded-lg border border-border-subtle px-4 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n Cancel\n </button>\n <button\n type=\"submit\"\n disabled={create.isPending}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90 disabled:opacity-50\"\n >\n {create.isPending ? 'Adding…' : 'Add policy'}\n </button>\n </div>\n </form>\n </Modal>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Policy card\n// ---------------------------------------------------------------------------\nfunction PolicyCard({ policy }: { policy: SubPolicy }) {\n const conditions = conditionEntries(policy.condition);\n return (\n <GlassCard treatment=\"metric\" className=\"flex flex-col p-4\">\n <div className=\"flex items-start justify-between gap-2\">\n <p className=\"text-sm font-semibold text-text-primary\">{policy.name}</p>\n <EnabledPill enabled={policy.isEnabled} />\n </div>\n <div className=\"mt-2 flex flex-wrap items-center gap-2\">\n <span className=\"inline-flex items-center gap-1.5 rounded-md bg-[var(--color-accent-soft)] px-2 py-0.5 text-[11px] font-medium text-text-primary\">\n <ShieldCheck className=\"h-3 w-3\" aria-hidden /> {formatEnumLabel(policy.action)}\n </span>\n <span className=\"inline-flex items-center gap-1 rounded-md bg-bg-sunken px-2 py-0.5 text-[11px] font-medium text-text-secondary tabular-nums\">\n Triggered {policy.triggerCount}×\n </span>\n </div>\n {policy.description && (\n <p className=\"mt-2 line-clamp-2 text-xs text-text-secondary\">{policy.description}</p>\n )}\n {conditions.length > 0 && (\n <div className=\"mt-3 border-t border-border-subtle pt-2.5\">\n <p className=\"flex items-center gap-1.5 text-[10px] font-medium uppercase tracking-wide text-text-secondary\">\n <SlidersHorizontal className=\"h-3 w-3\" aria-hidden /> Fires when\n </p>\n <div className=\"mt-1.5 flex flex-wrap gap-1.5\">\n {conditions.map((entry) => (\n <span\n key={entry.key}\n className=\"inline-flex items-center gap-1.5 rounded-md border border-border-subtle bg-bg-sunken px-2 py-0.5 text-[11px] text-text-secondary\"\n >\n <span className=\"font-medium text-text-primary\">\n {humanizeConditionKey(entry.key)}\n </span>\n <span className=\"font-mono tabular-nums\">{entry.value}</span>\n </span>\n ))}\n </div>\n </div>\n )}\n <p className=\"mt-2 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden />\n {policy.lastTriggeredAt\n ? `Last triggered ${formatRelativeTime(policy.lastTriggeredAt)}`\n : 'Not yet triggered'}\n </p>\n </GlassCard>\n );\n}\n\nexport function AgentDetailPage() {\n const { id } = useParams<{ id: string }>();\n const { navigateTo } = useSubscriberBot();\n const { data: agent, isLoading, isError, refetch } = useAgent(id);\n const setAgentStatus = useSetAgentStatus();\n const [actionError, setActionError] = useState<string | null>(null);\n const [showAddPolicy, setShowAddPolicy] = useState(false);\n\n if (isLoading) {\n return (\n <PageLayout title=\"Agent\">\n <LoadingView label=\"Loading agent…\" />\n </PageLayout>\n );\n }\n\n if (isError) {\n return (\n <PageLayout title=\"Agent\">\n <ErrorView message=\"Could not load this agent.\" onRetry={() => void refetch()} />\n </PageLayout>\n );\n }\n\n if (!agent) {\n return (\n <PageLayout title=\"Agent\">\n <EmptyState\n illustration=\"empty-data\"\n title=\"Agent not found\"\n description=\"It may have been removed, or you may not have access to it.\"\n action={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Back to agents\n </button>\n }\n />\n </PageLayout>\n );\n }\n\n const a = agent;\n const Icon = KIND_ICON[a.kind] ?? Bot;\n const policies = a.policies ?? [];\n const enabledCount = policies.filter((p) => p.isEnabled).length;\n const totalTriggers = policies.reduce((s, p) => s + (p.triggerCount || 0), 0);\n\n // --- Run history: derived from real timestamps, sorted most-recent first --\n const events: Array<{ ts: number; item: TimelineItem }> = [];\n if (a.lastRunAt) {\n events.push({\n ts: new Date(a.lastRunAt).getTime(),\n item: {\n title: 'Agent run',\n sub: 'Latest autonomous cycle',\n meta: formatRelativeTime(a.lastRunAt),\n tone: 'positive',\n },\n });\n }\n for (const p of policies) {\n if (p.lastTriggeredAt) {\n events.push({\n ts: new Date(p.lastTriggeredAt).getTime(),\n item: {\n title: p.name,\n sub: `${formatEnumLabel(p.action)} · fired ${p.triggerCount}×`,\n meta: formatRelativeTime(p.lastTriggeredAt),\n tone: actionTone(p.action),\n },\n });\n }\n }\n events.sort((x, y) => y.ts - x.ts);\n const timelineItems = events.map((e) => e.item);\n\n return (\n <PageLayout\n title={a.name}\n description={`${formatEnumLabel(a.kind)} agent`}\n actions={\n <button\n type=\"button\"\n onClick={() => navigateTo('/agents')}\n className=\"inline-flex items-center gap-2 rounded-lg border border-border-subtle px-3 py-2 text-sm font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <ArrowLeft className=\"h-4 w-4\" /> Back\n </button>\n }\n >\n {/* Identity + posture header */}\n <GlassCard treatment=\"glass\" glow={a.status === 'AUTONOMOUS'} className=\"p-5\">\n <div className=\"flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between\">\n <div className=\"flex items-start gap-4\">\n <span className=\"flex size-12 shrink-0 items-center justify-center rounded-xl bg-[var(--color-accent-soft)] text-text-primary\">\n <Icon className=\"h-6 w-6\" />\n </span>\n <div className=\"min-w-0\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <p className=\"text-lg font-semibold text-text-primary\">{a.name}</p>\n <StatusBadge status={a.status} />\n </div>\n <p className=\"mt-1 flex items-center gap-1.5 text-xs text-text-secondary\">\n <Clock className=\"h-3.5 w-3.5\" aria-hidden />\n {a.lastRunAt ? `Last run ${formatRelativeTime(a.lastRunAt)}` : 'Never run'}\n </p>\n {a.description && (\n <p className=\"mt-2 max-w-2xl text-sm text-text-secondary\">{a.description}</p>\n )}\n </div>\n </div>\n\n {/* Posture control */}\n <div className=\"w-full sm:w-56 sm:shrink-0\">\n <label\n htmlFor=\"agent-posture\"\n className=\"mb-1 block text-xs font-medium text-text-secondary\"\n >\n Operating posture\n </label>\n <select\n id=\"agent-posture\"\n value={a.status}\n disabled={setAgentStatus.isPending}\n onChange={(e) => {\n setActionError(null);\n setAgentStatus.mutate(\n { id: a.id, status: e.target.value as SubAgentStatus },\n {\n onError: (err) =>\n setActionError(\n err instanceof Error ? err.message : 'Could not change posture.'\n ),\n }\n );\n }}\n className=\"w-full rounded-lg border border-border-subtle bg-bg-surface px-3 py-2 text-sm text-text-primary focus:outline-none focus:ring-2 focus:ring-[var(--color-focus-ring)] disabled:opacity-50\"\n >\n {STATUS_OPTIONS.map((s) => (\n <option key={s} value={s}>\n {formatEnumLabel(s)}\n </option>\n ))}\n </select>\n <p className=\"mt-1.5 text-[11px] leading-snug text-text-secondary\">\n Disabled never acts · Suggest-only proposes · Autonomous acts within its policies.\n </p>\n </div>\n </div>\n </GlassCard>\n\n {actionError && (\n <div className=\"mt-4 rounded-lg border border-status-error-text/30 bg-status-error-bg-subtle px-4 py-2 text-sm text-status-error-text\">\n {actionError}\n </div>\n )}\n\n {/* Policy stats (computed) */}\n <div className=\"mt-6 grid grid-cols-1 gap-4 sm:grid-cols-3\">\n <MetricsCard\n icon={<ListChecks className=\"h-5 w-5\" />}\n value={policies.length}\n label=\"Policies\"\n />\n <MetricsCard\n icon={<ShieldCheck className=\"h-5 w-5\" />}\n value={enabledCount}\n label=\"Enabled\"\n />\n <MetricsCard\n icon={<Zap className=\"h-5 w-5\" />}\n value={totalTriggers}\n label=\"Total triggers\"\n />\n </div>\n\n {/* Policies + Run history */}\n <div className=\"mt-8 grid grid-cols-1 gap-6 lg:grid-cols-3\">\n <div className=\"lg:col-span-2\">\n <Section\n title=\"Policies\"\n description=\"The autonomous rules that bound this agent\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowAddPolicy(true)}\n className=\"inline-flex items-center gap-1.5 rounded-lg border border-border-subtle px-3 py-1.5 text-xs font-medium text-text-primary hover:bg-bg-sunken\"\n >\n <Plus className=\"h-3.5 w-3.5\" /> Add policy\n </button>\n }\n >\n {policies.length === 0 ? (\n <EmptyState\n illustration=\"empty-data\"\n title=\"No policies\"\n description=\"Policies define what this agent may do autonomously, and what it must alert on.\"\n action={\n <button\n type=\"button\"\n onClick={() => setShowAddPolicy(true)}\n className=\"rounded-lg bg-action-primary-bg px-4 py-2 text-sm font-medium text-action-primary-text hover:opacity-90\"\n >\n Add policy\n </button>\n }\n />\n ) : (\n <div className=\"grid grid-cols-1 gap-3 sm:grid-cols-2\">\n {policies.map((policy) => (\n <PolicyCard key={policy.id} policy={policy} />\n ))}\n </div>\n )}\n </Section>\n </div>\n\n <div className=\"lg:col-span-1\">\n <Section title=\"Run history\" description=\"Recent agent activity\">\n <GlassCard treatment=\"metric\" className=\"p-5\">\n {timelineItems.length === 0 ? (\n <div className=\"flex flex-col items-center justify-center gap-2 py-6 text-center\">\n <History className=\"h-8 w-8 text-text-secondary\" aria-hidden />\n <p className=\"text-sm font-medium text-text-primary\">No runs yet</p>\n <p className=\"text-xs text-text-secondary\">\n Activity appears here once the agent runs or a policy fires.\n </p>\n </div>\n ) : (\n <Timeline items={timelineItems} />\n )}\n </GlassCard>\n </Section>\n </div>\n </div>\n\n {showAddPolicy && <AddPolicyModal agentId={a.id} onClose={() => setShowAddPolicy(false)} />}\n </PageLayout>\n );\n}\n"],"mappings":"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"}
@@ -3,8 +3,10 @@
3
3
  * @module subscriberbot/pages/providers
4
4
  *
5
5
  * A provider profile from the registry: category, status, region, scores,
6
- * tags and its published plans. Reads `subProvider(id)`; writes
7
- * `subUpdateProvider`, `subArchiveProvider`, `subCreatePlan`.
6
+ * tags and its published plans. Reads `subProvider(id)` and
7
+ * `subListBenchmarkDataPoints` (the observed price points behind the "Price
8
+ * history" card); writes `subUpdateProvider`, `subArchiveProvider`,
9
+ * `subCreatePlan`.
8
10
  */
9
11
  export declare function ProviderDetailPage(): import("react").JSX.Element;
10
12
  //# sourceMappingURL=ProviderDetailPage.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ProviderDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/pages/providers/ProviderDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAkkBH,wBAAgB,kBAAkB,gCAiUjC"}
1
+ {"version":3,"file":"ProviderDetailPage.d.ts","sourceRoot":"","sources":["../../../../src/subscriberbot/pages/providers/ProviderDetailPage.tsx"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAirBH,wBAAgB,kBAAkB,gCAmUjC"}