peak6-x-intelligence-plugin 0.1.0 → 0.1.2

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.
package/dist/ui/index.js CHANGED
@@ -1,5 +1,6 @@
1
1
  // src/ui/index.tsx
2
2
  import { usePluginAction, usePluginData } from "@paperclipai/plugin-sdk/ui";
3
+ import { useState } from "react";
3
4
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
4
5
  function DashboardWidget(_props) {
5
6
  const { data, loading, error } = usePluginData("dashboard-summary");
@@ -45,7 +46,7 @@ function DashboardWidget(_props) {
45
46
  ] }),
46
47
  summary.top_items.length > 0 && /* @__PURE__ */ jsxs("div", { children: [
47
48
  /* @__PURE__ */ jsx("div", { style: { fontSize: "0.75rem", fontWeight: 600, marginBottom: "0.25rem" }, children: "Top Items" }),
48
- summary.top_items.slice(0, 3).map((tweet) => /* @__PURE__ */ jsx(TweetCard, { tweet }, tweet.tweet_id))
49
+ summary.top_items.slice(0, 3).map((tweet) => /* @__PURE__ */ jsx(TweetCard, { tweet, compact: true }, tweet.tweet_id))
49
50
  ] })
50
51
  ] }) : /* @__PURE__ */ jsx("div", { style: { opacity: 0.5, fontSize: "0.85rem" }, children: "No corpus for today. Discovery runs daily at 6:00 AM UTC." }),
51
52
  /* @__PURE__ */ jsx(
@@ -67,51 +68,289 @@ function DashboardWidget(_props) {
67
68
  )
68
69
  ] });
69
70
  }
71
+ function CorpusBrowserPage(_props) {
72
+ const todayStr = (/* @__PURE__ */ new Date()).toISOString().split("T")[0];
73
+ const [date, setDate] = useState(todayStr);
74
+ const [pillar, setPillar] = useState("");
75
+ const [minScore, setMinScore] = useState(0);
76
+ const [minEngagement, setMinEngagement] = useState(0);
77
+ const [authorityOnly, setAuthorityOnly] = useState(false);
78
+ const [page, setPage] = useState(1);
79
+ const params = {
80
+ date,
81
+ page,
82
+ page_size: 25
83
+ };
84
+ if (pillar) params.pillar = pillar;
85
+ if (minScore > 0) params.min_score = minScore;
86
+ if (minEngagement > 0) params.min_engagement = minEngagement;
87
+ if (authorityOnly) params.authority_only = true;
88
+ const { data, loading, error } = usePluginData("corpus-browser", params);
89
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "1.5rem", maxWidth: "960px", margin: "0 auto" }, children: [
90
+ /* @__PURE__ */ jsx("h2", { style: { margin: "0 0 1rem" }, children: "X Intelligence Corpus" }),
91
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.5rem", marginBottom: "1rem", alignItems: "center" }, children: [
92
+ /* @__PURE__ */ jsx("div", { style: { display: "flex", gap: "0.25rem" }, children: (data?.available_dates ?? [todayStr]).slice(0, 7).map((d) => /* @__PURE__ */ jsx(
93
+ "button",
94
+ {
95
+ onClick: () => {
96
+ setDate(d);
97
+ setPage(1);
98
+ },
99
+ style: {
100
+ padding: "0.25rem 0.5rem",
101
+ fontSize: "0.75rem",
102
+ border: "1px solid currentColor",
103
+ borderRadius: "3px",
104
+ background: d === date ? "rgba(128,128,128,0.25)" : "transparent",
105
+ color: "inherit",
106
+ cursor: "pointer",
107
+ fontWeight: d === date ? 600 : 400
108
+ },
109
+ children: d === todayStr ? "Today" : d.slice(5)
110
+ },
111
+ d
112
+ )) }),
113
+ /* @__PURE__ */ jsxs(
114
+ "select",
115
+ {
116
+ value: pillar,
117
+ onChange: (e) => {
118
+ setPillar(e.target.value);
119
+ setPage(1);
120
+ },
121
+ style: {
122
+ padding: "0.25rem 0.5rem",
123
+ fontSize: "0.75rem",
124
+ border: "1px solid currentColor",
125
+ borderRadius: "3px",
126
+ background: "transparent",
127
+ color: "inherit"
128
+ },
129
+ children: [
130
+ /* @__PURE__ */ jsx("option", { value: "", children: "All pillars" }),
131
+ (data?.available_pillars ?? []).map((p) => /* @__PURE__ */ jsx("option", { value: p, children: p }, p))
132
+ ]
133
+ }
134
+ ),
135
+ /* @__PURE__ */ jsxs("label", { style: { fontSize: "0.75rem", display: "flex", alignItems: "center", gap: "0.25rem" }, children: [
136
+ "Score ",
137
+ ">",
138
+ "=",
139
+ /* @__PURE__ */ jsx(
140
+ "input",
141
+ {
142
+ type: "number",
143
+ min: 0,
144
+ max: 1,
145
+ step: 0.1,
146
+ value: minScore,
147
+ onChange: (e) => {
148
+ setMinScore(parseFloat(e.target.value) || 0);
149
+ setPage(1);
150
+ },
151
+ style: {
152
+ width: "3.5rem",
153
+ padding: "0.2rem 0.35rem",
154
+ fontSize: "0.75rem",
155
+ border: "1px solid currentColor",
156
+ borderRadius: "3px",
157
+ background: "transparent",
158
+ color: "inherit"
159
+ }
160
+ }
161
+ )
162
+ ] }),
163
+ /* @__PURE__ */ jsxs("label", { style: { fontSize: "0.75rem", display: "flex", alignItems: "center", gap: "0.25rem" }, children: [
164
+ "Engmt ",
165
+ ">",
166
+ "=",
167
+ /* @__PURE__ */ jsx(
168
+ "input",
169
+ {
170
+ type: "number",
171
+ min: 0,
172
+ step: 10,
173
+ value: minEngagement,
174
+ onChange: (e) => {
175
+ setMinEngagement(parseInt(e.target.value) || 0);
176
+ setPage(1);
177
+ },
178
+ style: {
179
+ width: "3.5rem",
180
+ padding: "0.2rem 0.35rem",
181
+ fontSize: "0.75rem",
182
+ border: "1px solid currentColor",
183
+ borderRadius: "3px",
184
+ background: "transparent",
185
+ color: "inherit"
186
+ }
187
+ }
188
+ )
189
+ ] }),
190
+ /* @__PURE__ */ jsxs("label", { style: { fontSize: "0.75rem", display: "flex", alignItems: "center", gap: "0.25rem", cursor: "pointer" }, children: [
191
+ /* @__PURE__ */ jsx(
192
+ "input",
193
+ {
194
+ type: "checkbox",
195
+ checked: authorityOnly,
196
+ onChange: (e) => {
197
+ setAuthorityOnly(e.target.checked);
198
+ setPage(1);
199
+ }
200
+ }
201
+ ),
202
+ "Authority only"
203
+ ] })
204
+ ] }),
205
+ loading && /* @__PURE__ */ jsx("div", { style: { padding: "1rem", opacity: 0.5 }, children: "Loading corpus..." }),
206
+ error && /* @__PURE__ */ jsxs("div", { style: { padding: "1rem", color: "#ef4444" }, children: [
207
+ "Error: ",
208
+ error.message
209
+ ] }),
210
+ data && !loading && /* @__PURE__ */ jsxs(Fragment, { children: [
211
+ /* @__PURE__ */ jsxs("div", { style: { fontSize: "0.8rem", opacity: 0.6, marginBottom: "0.75rem" }, children: [
212
+ data.pagination.totalCount,
213
+ " tweets",
214
+ data.pagination.totalPages > 1 && ` \u2014 page ${data.pagination.page} of ${data.pagination.totalPages}`
215
+ ] }),
216
+ data.items.length === 0 ? /* @__PURE__ */ jsx("div", { style: { padding: "2rem", textAlign: "center", opacity: 0.5 }, children: "No tweets match the current filters." }) : /* @__PURE__ */ jsx("div", { style: { display: "grid", gap: "0.5rem" }, children: data.items.map((tweet) => /* @__PURE__ */ jsx(TweetCard, { tweet }, tweet.tweet_id)) }),
217
+ data.pagination.totalPages > 1 && /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "center", gap: "0.5rem", marginTop: "1rem" }, children: [
218
+ /* @__PURE__ */ jsx(
219
+ "button",
220
+ {
221
+ onClick: () => setPage((p) => Math.max(1, p - 1)),
222
+ disabled: page <= 1,
223
+ style: {
224
+ padding: "0.3rem 0.75rem",
225
+ fontSize: "0.8rem",
226
+ border: "1px solid currentColor",
227
+ borderRadius: "3px",
228
+ background: "transparent",
229
+ color: "inherit",
230
+ cursor: page <= 1 ? "default" : "pointer",
231
+ opacity: page <= 1 ? 0.3 : 0.7
232
+ },
233
+ children: "Previous"
234
+ }
235
+ ),
236
+ /* @__PURE__ */ jsxs("span", { style: { fontSize: "0.8rem", lineHeight: "1.8rem" }, children: [
237
+ page,
238
+ " / ",
239
+ data.pagination.totalPages
240
+ ] }),
241
+ /* @__PURE__ */ jsx(
242
+ "button",
243
+ {
244
+ onClick: () => setPage((p) => Math.min(data.pagination.totalPages, p + 1)),
245
+ disabled: page >= data.pagination.totalPages,
246
+ style: {
247
+ padding: "0.3rem 0.75rem",
248
+ fontSize: "0.8rem",
249
+ border: "1px solid currentColor",
250
+ borderRadius: "3px",
251
+ background: "transparent",
252
+ color: "inherit",
253
+ cursor: page >= data.pagination.totalPages ? "default" : "pointer",
254
+ opacity: page >= data.pagination.totalPages ? 0.3 : 0.7
255
+ },
256
+ children: "Next"
257
+ }
258
+ )
259
+ ] })
260
+ ] })
261
+ ] });
262
+ }
263
+ function SettingsPage() {
264
+ const { data, loading, error } = usePluginData("plugin-config");
265
+ if (loading) return /* @__PURE__ */ jsx("div", { children: "Loading settings..." });
266
+ if (error) return /* @__PURE__ */ jsxs("div", { children: [
267
+ "Error: ",
268
+ error.message
269
+ ] });
270
+ return /* @__PURE__ */ jsxs("div", { style: { padding: "1rem" }, children: [
271
+ /* @__PURE__ */ jsx("h2", { children: "X Intelligence Settings" }),
272
+ /* @__PURE__ */ jsx("p", { style: { opacity: 0.5 }, children: "Configure authority lists, scoring weights, and discovery topics via the plugin configuration panel." }),
273
+ /* @__PURE__ */ jsx("pre", { style: { background: "rgba(128,128,128,0.1)", padding: "1rem", borderRadius: "4px", overflow: "auto", fontSize: "0.8rem" }, children: JSON.stringify(data, null, 2) })
274
+ ] });
275
+ }
70
276
  function StatCard({ label, value }) {
71
277
  return /* @__PURE__ */ jsxs("div", { style: { textAlign: "center", padding: "0.5rem", background: "rgba(128,128,128,0.1)", borderRadius: "4px" }, children: [
72
278
  /* @__PURE__ */ jsx("div", { style: { fontSize: "1.1rem", fontWeight: 600 }, children: value }),
73
279
  /* @__PURE__ */ jsx("div", { style: { fontSize: "0.7rem", opacity: 0.5 }, children: label })
74
280
  ] });
75
281
  }
76
- function TweetCard({ tweet }) {
282
+ function TweetCard({ tweet, compact }) {
283
+ const totalEngagement = tweet.metrics.like_count + tweet.metrics.retweet_count + tweet.metrics.reply_count + tweet.metrics.quote_count;
284
+ const ratingCount = tweet.ratings?.length ?? 0;
77
285
  return /* @__PURE__ */ jsxs(
78
286
  "div",
79
287
  {
80
288
  style: {
81
- padding: "0.4rem",
82
- marginBottom: "0.25rem",
289
+ padding: compact ? "0.4rem" : "0.6rem",
290
+ marginBottom: compact ? "0.25rem" : 0,
83
291
  background: "rgba(128,128,128,0.1)",
84
292
  borderRadius: "4px",
85
- fontSize: "0.8rem"
293
+ fontSize: compact ? "0.8rem" : "0.85rem"
86
294
  },
87
295
  children: [
88
- /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between" }, children: [
296
+ /* @__PURE__ */ jsxs("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" }, children: [
89
297
  /* @__PURE__ */ jsxs("span", { style: { fontWeight: 600 }, children: [
90
298
  "@",
91
299
  tweet.author_username,
92
- tweet.is_authority && /* @__PURE__ */ jsx("span", { style: { color: "#2563eb", marginLeft: "0.25rem" }, title: "Authority handle", children: "*" })
300
+ tweet.is_authority && /* @__PURE__ */ jsx("span", { style: { color: "#2563eb", marginLeft: "0.25rem" }, title: "Authority handle", children: "*" }),
301
+ !compact && tweet.author_verified_type && /* @__PURE__ */ jsx("span", { style: { color: "#9333ea", marginLeft: "0.25rem", fontSize: "0.7rem" }, title: `Verified: ${tweet.author_verified_type}`, children: "V" })
93
302
  ] }),
94
- /* @__PURE__ */ jsx("span", { style: { opacity: 0.5 }, children: tweet.score.toFixed(2) })
303
+ /* @__PURE__ */ jsx("span", { style: { opacity: 0.5, fontSize: "0.75rem" }, children: tweet.score.toFixed(2) })
95
304
  ] }),
96
- /* @__PURE__ */ jsx("div", { style: { opacity: 0.7, marginTop: "0.15rem" }, children: tweet.text.length > 120 ? `${tweet.text.slice(0, 120)}...` : tweet.text })
305
+ /* @__PURE__ */ jsx("div", { style: { opacity: 0.7, marginTop: "0.15rem" }, children: compact ? tweet.text.length > 120 ? `${tweet.text.slice(0, 120)}...` : tweet.text : tweet.text.length > 280 ? `${tweet.text.slice(0, 280)}...` : tweet.text }),
306
+ !compact && /* @__PURE__ */ jsxs("div", { style: { display: "flex", flexWrap: "wrap", gap: "0.75rem", marginTop: "0.4rem", fontSize: "0.7rem", opacity: 0.5 }, children: [
307
+ /* @__PURE__ */ jsxs("span", { title: "Relevance / Recency / Engagement", children: [
308
+ "Scores: ",
309
+ tweet.relevance_score.toFixed(2),
310
+ " / ",
311
+ tweet.recency_score.toFixed(2),
312
+ " / ",
313
+ tweet.engagement_score.toFixed(2)
314
+ ] }),
315
+ /* @__PURE__ */ jsxs("span", { children: [
316
+ tweet.metrics.like_count,
317
+ "L ",
318
+ tweet.metrics.retweet_count,
319
+ "RT ",
320
+ tweet.metrics.reply_count,
321
+ "Re ",
322
+ tweet.metrics.quote_count,
323
+ "Q (",
324
+ totalEngagement,
325
+ " total)"
326
+ ] }),
327
+ tweet.author_followers_count > 0 && /* @__PURE__ */ jsxs("span", { children: [
328
+ tweet.author_followers_count.toLocaleString(),
329
+ " followers"
330
+ ] }),
331
+ ratingCount > 0 && /* @__PURE__ */ jsxs("span", { children: [
332
+ ratingCount,
333
+ " rating",
334
+ ratingCount > 1 ? "s" : ""
335
+ ] }),
336
+ /* @__PURE__ */ jsx("span", { children: tweet.source }),
337
+ /* @__PURE__ */ jsx(
338
+ "a",
339
+ {
340
+ href: `https://x.com/i/status/${tweet.tweet_id}`,
341
+ target: "_blank",
342
+ rel: "noopener noreferrer",
343
+ style: { color: "#2563eb", textDecoration: "none" },
344
+ children: "View on X"
345
+ }
346
+ )
347
+ ] })
97
348
  ]
98
349
  }
99
350
  );
100
351
  }
101
- function SettingsPage() {
102
- const { data, loading, error } = usePluginData("plugin-config");
103
- if (loading) return /* @__PURE__ */ jsx("div", { children: "Loading settings..." });
104
- if (error) return /* @__PURE__ */ jsxs("div", { children: [
105
- "Error: ",
106
- error.message
107
- ] });
108
- return /* @__PURE__ */ jsxs("div", { style: { padding: "1rem" }, children: [
109
- /* @__PURE__ */ jsx("h2", { children: "X Intelligence Settings" }),
110
- /* @__PURE__ */ jsx("p", { style: { opacity: 0.5 }, children: "Configure authority lists, scoring weights, and discovery topics via the plugin configuration panel." }),
111
- /* @__PURE__ */ jsx("pre", { style: { background: "rgba(128,128,128,0.1)", padding: "1rem", borderRadius: "4px", overflow: "auto", fontSize: "0.8rem" }, children: JSON.stringify(data, null, 2) })
112
- ] });
113
- }
114
352
  export {
353
+ CorpusBrowserPage,
115
354
  DashboardWidget,
116
355
  SettingsPage
117
356
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/ui/index.tsx"],
4
- "sourcesContent": ["import { usePluginAction, usePluginData, type PluginWidgetProps } from \"@paperclipai/plugin-sdk/ui\";\nimport type { CorpusSummary, ScoredTweet } from \"../types.js\";\n\ntype DashboardData = {\n today: CorpusSummary | null;\n lastRun: { date: string; corpusSize: number; generatedAt: string } | null;\n trackedHandles: number;\n};\n\nexport function DashboardWidget(_props: PluginWidgetProps) {\n const { data, loading, error } = usePluginData<DashboardData>(\"dashboard-summary\");\n const triggerDiscovery = usePluginAction(\"trigger-discovery\");\n\n if (loading) return <div style={{ padding: \"1rem\" }}>Loading X Intelligence...</div>;\n if (error) return <div style={{ padding: \"1rem\", color: \"#ef4444\" }}>Error: {error.message}</div>;\n\n const summary = data?.today;\n const lastRun = data?.lastRun;\n\n return (\n <div style={{ display: \"grid\", gap: \"0.75rem\", padding: \"0.5rem\" }}>\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\" }}>\n <strong>X Intelligence</strong>\n <span style={{ fontSize: \"0.75rem\", opacity: 0.5 }}>\n {lastRun ? `Last run: ${lastRun.date}` : \"No runs yet\"}\n </span>\n </div>\n\n {summary ? (\n <>\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr 1fr\", gap: \"0.5rem\" }}>\n <StatCard label=\"Tweets\" value={summary.total_tweets} />\n <StatCard label=\"Handles\" value={data?.trackedHandles ?? 0} />\n <StatCard\n label=\"Cost\"\n value={`$${(\n summary.discovery_stats.xai_cost_estimate +\n summary.discovery_stats.x_api_cost_estimate\n ).toFixed(2)}`}\n />\n </div>\n\n <div style={{ fontSize: \"0.8rem\" }}>\n <div>\n Queries: {summary.discovery_stats.open_queries} open + {summary.discovery_stats.focused_queries} focused\n </div>\n <div>\n New handles: {summary.discovery_stats.new_handles_discovered} | Promoted: {summary.discovery_stats.handles_promoted}\n </div>\n </div>\n\n {summary.top_items.length > 0 && (\n <div>\n <div style={{ fontSize: \"0.75rem\", fontWeight: 600, marginBottom: \"0.25rem\" }}>Top Items</div>\n {summary.top_items.slice(0, 3).map((tweet) => (\n <TweetCard key={tweet.tweet_id} tweet={tweet} />\n ))}\n </div>\n )}\n </>\n ) : (\n <div style={{ opacity: 0.5, fontSize: \"0.85rem\" }}>\n No corpus for today. Discovery runs daily at 6:00 AM UTC.\n </div>\n )}\n\n <button\n onClick={() => void triggerDiscovery()}\n style={{\n padding: \"0.4rem 0.75rem\",\n fontSize: \"0.8rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"4px\",\n background: \"transparent\",\n color: \"inherit\",\n opacity: 0.7,\n cursor: \"pointer\",\n }}\n >\n Trigger Discovery\n </button>\n </div>\n );\n}\n\nfunction StatCard({ label, value }: { label: string; value: string | number }) {\n return (\n <div style={{ textAlign: \"center\", padding: \"0.5rem\", background: \"rgba(128,128,128,0.1)\", borderRadius: \"4px\" }}>\n <div style={{ fontSize: \"1.1rem\", fontWeight: 600 }}>{value}</div>\n <div style={{ fontSize: \"0.7rem\", opacity: 0.5 }}>{label}</div>\n </div>\n );\n}\n\nfunction TweetCard({ tweet }: { tweet: ScoredTweet }) {\n return (\n <div\n style={{\n padding: \"0.4rem\",\n marginBottom: \"0.25rem\",\n background: \"rgba(128,128,128,0.1)\",\n borderRadius: \"4px\",\n fontSize: \"0.8rem\",\n }}\n >\n <div style={{ display: \"flex\", justifyContent: \"space-between\" }}>\n <span style={{ fontWeight: 600 }}>\n @{tweet.author_username}\n {tweet.is_authority && (\n <span style={{ color: \"#2563eb\", marginLeft: \"0.25rem\" }} title=\"Authority handle\">\n *\n </span>\n )}\n </span>\n <span style={{ opacity: 0.5 }}>{tweet.score.toFixed(2)}</span>\n </div>\n <div style={{ opacity: 0.7, marginTop: \"0.15rem\" }}>\n {tweet.text.length > 120 ? `${tweet.text.slice(0, 120)}...` : tweet.text}\n </div>\n </div>\n );\n}\n\nexport function SettingsPage() {\n const { data, loading, error } = usePluginData<Record<string, unknown>>(\"plugin-config\");\n\n if (loading) return <div>Loading settings...</div>;\n if (error) return <div>Error: {error.message}</div>;\n\n return (\n <div style={{ padding: \"1rem\" }}>\n <h2>X Intelligence Settings</h2>\n <p style={{ opacity: 0.5 }}>\n Configure authority lists, scoring weights, and discovery topics via the plugin configuration panel.\n </p>\n <pre style={{ background: \"rgba(128,128,128,0.1)\", padding: \"1rem\", borderRadius: \"4px\", overflow: \"auto\", fontSize: \"0.8rem\" }}>\n {JSON.stringify(data, null, 2)}\n </pre>\n </div>\n );\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { usePluginAction, usePluginData, type PluginWidgetProps, type PluginPageProps } from \"@paperclipai/plugin-sdk/ui\";\nimport { useState } from \"react\";\nimport type { CorpusSummary, ScoredTweet, CorpusBrowserData } from \"../types.js\";\n\ntype DashboardData = {\n today: CorpusSummary | null;\n lastRun: { date: string; corpusSize: number; generatedAt: string } | null;\n trackedHandles: number;\n};\n\nexport function DashboardWidget(_props: PluginWidgetProps) {\n const { data, loading, error } = usePluginData<DashboardData>(\"dashboard-summary\");\n const triggerDiscovery = usePluginAction(\"trigger-discovery\");\n\n if (loading) return <div style={{ padding: \"1rem\" }}>Loading X Intelligence...</div>;\n if (error) return <div style={{ padding: \"1rem\", color: \"#ef4444\" }}>Error: {error.message}</div>;\n\n const summary = data?.today;\n const lastRun = data?.lastRun;\n\n return (\n <div style={{ display: \"grid\", gap: \"0.75rem\", padding: \"0.5rem\" }}>\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\" }}>\n <strong>X Intelligence</strong>\n <span style={{ fontSize: \"0.75rem\", opacity: 0.5 }}>\n {lastRun ? `Last run: ${lastRun.date}` : \"No runs yet\"}\n </span>\n </div>\n\n {summary ? (\n <>\n <div style={{ display: \"grid\", gridTemplateColumns: \"1fr 1fr 1fr\", gap: \"0.5rem\" }}>\n <StatCard label=\"Tweets\" value={summary.total_tweets} />\n <StatCard label=\"Handles\" value={data?.trackedHandles ?? 0} />\n <StatCard\n label=\"Cost\"\n value={`$${(\n summary.discovery_stats.xai_cost_estimate +\n summary.discovery_stats.x_api_cost_estimate\n ).toFixed(2)}`}\n />\n </div>\n\n <div style={{ fontSize: \"0.8rem\" }}>\n <div>\n Queries: {summary.discovery_stats.open_queries} open + {summary.discovery_stats.focused_queries} focused\n </div>\n <div>\n New handles: {summary.discovery_stats.new_handles_discovered} | Promoted: {summary.discovery_stats.handles_promoted}\n </div>\n </div>\n\n {summary.top_items.length > 0 && (\n <div>\n <div style={{ fontSize: \"0.75rem\", fontWeight: 600, marginBottom: \"0.25rem\" }}>Top Items</div>\n {summary.top_items.slice(0, 3).map((tweet) => (\n <TweetCard key={tweet.tweet_id} tweet={tweet} compact />\n ))}\n </div>\n )}\n </>\n ) : (\n <div style={{ opacity: 0.5, fontSize: \"0.85rem\" }}>\n No corpus for today. Discovery runs daily at 6:00 AM UTC.\n </div>\n )}\n\n <button\n onClick={() => void triggerDiscovery()}\n style={{\n padding: \"0.4rem 0.75rem\",\n fontSize: \"0.8rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"4px\",\n background: \"transparent\",\n color: \"inherit\",\n opacity: 0.7,\n cursor: \"pointer\",\n }}\n >\n Trigger Discovery\n </button>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Corpus Browser Page\n// ---------------------------------------------------------------------------\n\nexport function CorpusBrowserPage(_props: PluginPageProps) {\n const todayStr = new Date().toISOString().split(\"T\")[0]!;\n const [date, setDate] = useState(todayStr);\n const [pillar, setPillar] = useState(\"\");\n const [minScore, setMinScore] = useState(0);\n const [minEngagement, setMinEngagement] = useState(0);\n const [authorityOnly, setAuthorityOnly] = useState(false);\n const [page, setPage] = useState(1);\n\n const params: Record<string, unknown> = {\n date,\n page,\n page_size: 25,\n };\n if (pillar) params.pillar = pillar;\n if (minScore > 0) params.min_score = minScore;\n if (minEngagement > 0) params.min_engagement = minEngagement;\n if (authorityOnly) params.authority_only = true;\n\n const { data, loading, error } = usePluginData<CorpusBrowserData>(\"corpus-browser\", params);\n\n return (\n <div style={{ padding: \"1.5rem\", maxWidth: \"960px\", margin: \"0 auto\" }}>\n <h2 style={{ margin: \"0 0 1rem\" }}>X Intelligence Corpus</h2>\n\n {/* Filter bar */}\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.5rem\", marginBottom: \"1rem\", alignItems: \"center\" }}>\n {/* Date buttons */}\n <div style={{ display: \"flex\", gap: \"0.25rem\" }}>\n {(data?.available_dates ?? [todayStr]).slice(0, 7).map((d) => (\n <button\n key={d}\n onClick={() => { setDate(d); setPage(1); }}\n style={{\n padding: \"0.25rem 0.5rem\",\n fontSize: \"0.75rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"3px\",\n background: d === date ? \"rgba(128,128,128,0.25)\" : \"transparent\",\n color: \"inherit\",\n cursor: \"pointer\",\n fontWeight: d === date ? 600 : 400,\n }}\n >\n {d === todayStr ? \"Today\" : d.slice(5)}\n </button>\n ))}\n </div>\n\n {/* Pillar filter */}\n <select\n value={pillar}\n onChange={(e) => { setPillar(e.target.value); setPage(1); }}\n style={{\n padding: \"0.25rem 0.5rem\",\n fontSize: \"0.75rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"3px\",\n background: \"transparent\",\n color: \"inherit\",\n }}\n >\n <option value=\"\">All pillars</option>\n {(data?.available_pillars ?? []).map((p) => (\n <option key={p} value={p}>{p}</option>\n ))}\n </select>\n\n {/* Score threshold */}\n <label style={{ fontSize: \"0.75rem\", display: \"flex\", alignItems: \"center\", gap: \"0.25rem\" }}>\n Score {\">\"}=\n <input\n type=\"number\"\n min={0}\n max={1}\n step={0.1}\n value={minScore}\n onChange={(e) => { setMinScore(parseFloat(e.target.value) || 0); setPage(1); }}\n style={{\n width: \"3.5rem\",\n padding: \"0.2rem 0.35rem\",\n fontSize: \"0.75rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"3px\",\n background: \"transparent\",\n color: \"inherit\",\n }}\n />\n </label>\n\n {/* Engagement threshold */}\n <label style={{ fontSize: \"0.75rem\", display: \"flex\", alignItems: \"center\", gap: \"0.25rem\" }}>\n Engmt {\">\"}=\n <input\n type=\"number\"\n min={0}\n step={10}\n value={minEngagement}\n onChange={(e) => { setMinEngagement(parseInt(e.target.value) || 0); setPage(1); }}\n style={{\n width: \"3.5rem\",\n padding: \"0.2rem 0.35rem\",\n fontSize: \"0.75rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"3px\",\n background: \"transparent\",\n color: \"inherit\",\n }}\n />\n </label>\n\n {/* Authority only toggle */}\n <label style={{ fontSize: \"0.75rem\", display: \"flex\", alignItems: \"center\", gap: \"0.25rem\", cursor: \"pointer\" }}>\n <input\n type=\"checkbox\"\n checked={authorityOnly}\n onChange={(e) => { setAuthorityOnly(e.target.checked); setPage(1); }}\n />\n Authority only\n </label>\n </div>\n\n {/* Loading / Error */}\n {loading && <div style={{ padding: \"1rem\", opacity: 0.5 }}>Loading corpus...</div>}\n {error && <div style={{ padding: \"1rem\", color: \"#ef4444\" }}>Error: {error.message}</div>}\n\n {/* Results */}\n {data && !loading && (\n <>\n <div style={{ fontSize: \"0.8rem\", opacity: 0.6, marginBottom: \"0.75rem\" }}>\n {data.pagination.totalCount} tweets\n {data.pagination.totalPages > 1 && ` \u2014 page ${data.pagination.page} of ${data.pagination.totalPages}`}\n </div>\n\n {data.items.length === 0 ? (\n <div style={{ padding: \"2rem\", textAlign: \"center\", opacity: 0.5 }}>\n No tweets match the current filters.\n </div>\n ) : (\n <div style={{ display: \"grid\", gap: \"0.5rem\" }}>\n {data.items.map((tweet) => (\n <TweetCard key={tweet.tweet_id} tweet={tweet} />\n ))}\n </div>\n )}\n\n {/* Pagination */}\n {data.pagination.totalPages > 1 && (\n <div style={{ display: \"flex\", justifyContent: \"center\", gap: \"0.5rem\", marginTop: \"1rem\" }}>\n <button\n onClick={() => setPage((p) => Math.max(1, p - 1))}\n disabled={page <= 1}\n style={{\n padding: \"0.3rem 0.75rem\",\n fontSize: \"0.8rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"3px\",\n background: \"transparent\",\n color: \"inherit\",\n cursor: page <= 1 ? \"default\" : \"pointer\",\n opacity: page <= 1 ? 0.3 : 0.7,\n }}\n >\n Previous\n </button>\n <span style={{ fontSize: \"0.8rem\", lineHeight: \"1.8rem\" }}>\n {page} / {data.pagination.totalPages}\n </span>\n <button\n onClick={() => setPage((p) => Math.min(data.pagination.totalPages, p + 1))}\n disabled={page >= data.pagination.totalPages}\n style={{\n padding: \"0.3rem 0.75rem\",\n fontSize: \"0.8rem\",\n border: \"1px solid currentColor\",\n borderRadius: \"3px\",\n background: \"transparent\",\n color: \"inherit\",\n cursor: page >= data.pagination.totalPages ? \"default\" : \"pointer\",\n opacity: page >= data.pagination.totalPages ? 0.3 : 0.7,\n }}\n >\n Next\n </button>\n </div>\n )}\n </>\n )}\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Settings page\n// ---------------------------------------------------------------------------\n\nexport function SettingsPage() {\n const { data, loading, error } = usePluginData<Record<string, unknown>>(\"plugin-config\");\n\n if (loading) return <div>Loading settings...</div>;\n if (error) return <div>Error: {error.message}</div>;\n\n return (\n <div style={{ padding: \"1rem\" }}>\n <h2>X Intelligence Settings</h2>\n <p style={{ opacity: 0.5 }}>\n Configure authority lists, scoring weights, and discovery topics via the plugin configuration panel.\n </p>\n <pre style={{ background: \"rgba(128,128,128,0.1)\", padding: \"1rem\", borderRadius: \"4px\", overflow: \"auto\", fontSize: \"0.8rem\" }}>\n {JSON.stringify(data, null, 2)}\n </pre>\n </div>\n );\n}\n\n// ---------------------------------------------------------------------------\n// Shared components\n// ---------------------------------------------------------------------------\n\nfunction StatCard({ label, value }: { label: string; value: string | number }) {\n return (\n <div style={{ textAlign: \"center\", padding: \"0.5rem\", background: \"rgba(128,128,128,0.1)\", borderRadius: \"4px\" }}>\n <div style={{ fontSize: \"1.1rem\", fontWeight: 600 }}>{value}</div>\n <div style={{ fontSize: \"0.7rem\", opacity: 0.5 }}>{label}</div>\n </div>\n );\n}\n\nfunction TweetCard({ tweet, compact }: { tweet: ScoredTweet; compact?: boolean }) {\n const totalEngagement = tweet.metrics.like_count + tweet.metrics.retweet_count + tweet.metrics.reply_count + tweet.metrics.quote_count;\n const ratingCount = tweet.ratings?.length ?? 0;\n\n return (\n <div\n style={{\n padding: compact ? \"0.4rem\" : \"0.6rem\",\n marginBottom: compact ? \"0.25rem\" : 0,\n background: \"rgba(128,128,128,0.1)\",\n borderRadius: \"4px\",\n fontSize: compact ? \"0.8rem\" : \"0.85rem\",\n }}\n >\n {/* Header */}\n <div style={{ display: \"flex\", justifyContent: \"space-between\", alignItems: \"center\" }}>\n <span style={{ fontWeight: 600 }}>\n @{tweet.author_username}\n {tweet.is_authority && (\n <span style={{ color: \"#2563eb\", marginLeft: \"0.25rem\" }} title=\"Authority handle\">*</span>\n )}\n {!compact && tweet.author_verified_type && (\n <span style={{ color: \"#9333ea\", marginLeft: \"0.25rem\", fontSize: \"0.7rem\" }} title={`Verified: ${tweet.author_verified_type}`}>V</span>\n )}\n </span>\n <span style={{ opacity: 0.5, fontSize: \"0.75rem\" }}>{tweet.score.toFixed(2)}</span>\n </div>\n\n {/* Text */}\n <div style={{ opacity: 0.7, marginTop: \"0.15rem\" }}>\n {compact\n ? (tweet.text.length > 120 ? `${tweet.text.slice(0, 120)}...` : tweet.text)\n : (tweet.text.length > 280 ? `${tweet.text.slice(0, 280)}...` : tweet.text)\n }\n </div>\n\n {/* Extended info (non-compact) */}\n {!compact && (\n <div style={{ display: \"flex\", flexWrap: \"wrap\", gap: \"0.75rem\", marginTop: \"0.4rem\", fontSize: \"0.7rem\", opacity: 0.5 }}>\n {/* Score breakdown */}\n <span title=\"Relevance / Recency / Engagement\">\n Scores: {tweet.relevance_score.toFixed(2)} / {tweet.recency_score.toFixed(2)} / {tweet.engagement_score.toFixed(2)}\n </span>\n\n {/* Engagement metrics */}\n <span>\n {tweet.metrics.like_count}L {tweet.metrics.retweet_count}RT {tweet.metrics.reply_count}Re {tweet.metrics.quote_count}Q\n ({totalEngagement} total)\n </span>\n\n {/* Followers */}\n {tweet.author_followers_count > 0 && (\n <span>{tweet.author_followers_count.toLocaleString()} followers</span>\n )}\n\n {/* Ratings */}\n {ratingCount > 0 && (\n <span>{ratingCount} rating{ratingCount > 1 ? \"s\" : \"\"}</span>\n )}\n\n {/* Source */}\n <span>{tweet.source}</span>\n\n {/* Link to original tweet */}\n <a\n href={`https://x.com/i/status/${tweet.tweet_id}`}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n style={{ color: \"#2563eb\", textDecoration: \"none\" }}\n >\n View on X\n </a>\n </div>\n )}\n </div>\n );\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }