nod-shout 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. package/README.md +82 -0
  2. package/TASK-AGENT-POSTS.md +112 -0
  3. package/assets/shout-default.svg +5 -0
  4. package/bin/shout +68 -0
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +29 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lib/ai.d.ts +13 -0
  10. package/dist/lib/ai.d.ts.map +1 -0
  11. package/dist/lib/ai.js +135 -0
  12. package/dist/lib/ai.js.map +1 -0
  13. package/dist/lib/content-filter.d.ts +74 -0
  14. package/dist/lib/content-filter.d.ts.map +1 -0
  15. package/dist/lib/content-filter.js +188 -0
  16. package/dist/lib/content-filter.js.map +1 -0
  17. package/dist/lib/context-extractor.d.ts +39 -0
  18. package/dist/lib/context-extractor.d.ts.map +1 -0
  19. package/dist/lib/context-extractor.js +170 -0
  20. package/dist/lib/context-extractor.js.map +1 -0
  21. package/dist/lib/match-engine.d.ts +31 -0
  22. package/dist/lib/match-engine.d.ts.map +1 -0
  23. package/dist/lib/match-engine.js +322 -0
  24. package/dist/lib/match-engine.js.map +1 -0
  25. package/dist/lib/metadata.d.ts +7 -0
  26. package/dist/lib/metadata.d.ts.map +1 -0
  27. package/dist/lib/metadata.js +311 -0
  28. package/dist/lib/metadata.js.map +1 -0
  29. package/dist/lib/skills.d.ts +3 -0
  30. package/dist/lib/skills.d.ts.map +1 -0
  31. package/dist/lib/skills.js +20 -0
  32. package/dist/lib/skills.js.map +1 -0
  33. package/dist/lib/supabase.d.ts +2 -0
  34. package/dist/lib/supabase.d.ts.map +1 -0
  35. package/dist/lib/supabase.js +8 -0
  36. package/dist/lib/supabase.js.map +1 -0
  37. package/dist/tools/collections.d.ts +3 -0
  38. package/dist/tools/collections.d.ts.map +1 -0
  39. package/dist/tools/collections.js +142 -0
  40. package/dist/tools/collections.js.map +1 -0
  41. package/dist/tools/intros.d.ts +3 -0
  42. package/dist/tools/intros.d.ts.map +1 -0
  43. package/dist/tools/intros.js +483 -0
  44. package/dist/tools/intros.js.map +1 -0
  45. package/dist/tools/links.d.ts +3 -0
  46. package/dist/tools/links.d.ts.map +1 -0
  47. package/dist/tools/links.js +424 -0
  48. package/dist/tools/links.js.map +1 -0
  49. package/dist/tools/posts.d.ts +3 -0
  50. package/dist/tools/posts.d.ts.map +1 -0
  51. package/dist/tools/posts.js +212 -0
  52. package/dist/tools/posts.js.map +1 -0
  53. package/dist/tools/settings.d.ts +3 -0
  54. package/dist/tools/settings.d.ts.map +1 -0
  55. package/dist/tools/settings.js +45 -0
  56. package/dist/tools/settings.js.map +1 -0
  57. package/dist/tools/shout_agent_curate.d.ts +28 -0
  58. package/dist/tools/shout_agent_curate.d.ts.map +1 -0
  59. package/dist/tools/shout_agent_curate.js +80 -0
  60. package/dist/tools/shout_agent_curate.js.map +1 -0
  61. package/dist/tools/social.d.ts +3 -0
  62. package/dist/tools/social.d.ts.map +1 -0
  63. package/dist/tools/social.js +169 -0
  64. package/dist/tools/social.js.map +1 -0
  65. package/dist/types.d.ts +60 -0
  66. package/dist/types.d.ts.map +1 -0
  67. package/dist/types.js +3 -0
  68. package/dist/types.js.map +1 -0
  69. package/package.json +24 -0
  70. package/quick-test.ts +22 -0
  71. package/regenerate-summaries.ts +111 -0
  72. package/save-jeffries-shout.ts +38 -0
  73. package/save-openai-shout.ts +35 -0
  74. package/save-prcarly.ts +46 -0
  75. package/save-shout.ts +35 -0
  76. package/save-techcrunch-shout.ts +59 -0
  77. package/save-zdnet-shout.ts +36 -0
  78. package/skills/collection-routing/SKILL.md +34 -0
  79. package/skills/link-summary/SKILL.md +53 -0
  80. package/skills/tagging-and-routing/SKILL.md +54 -0
  81. package/src/index.ts +32 -0
  82. package/src/lib/ai.ts +166 -0
  83. package/src/lib/content-filter.ts +258 -0
  84. package/src/lib/metadata.ts +353 -0
  85. package/src/lib/skills.ts +21 -0
  86. package/src/lib/supabase.ts +12 -0
  87. package/src/tools/collections.ts +182 -0
  88. package/src/tools/links.ts +524 -0
  89. package/src/tools/posts.ts +264 -0
  90. package/src/tools/settings.ts +55 -0
  91. package/src/tools/shout_agent_curate.ts +95 -0
  92. package/src/tools/social.ts +206 -0
  93. package/src/types.ts +66 -0
  94. package/supabase/.temp/cli-latest +1 -0
  95. package/supabase/.temp/gotrue-version +1 -0
  96. package/supabase/.temp/pooler-url +1 -0
  97. package/supabase/.temp/postgres-version +1 -0
  98. package/supabase/.temp/project-ref +1 -0
  99. package/supabase/.temp/rest-version +1 -0
  100. package/supabase/.temp/storage-migration +1 -0
  101. package/supabase/.temp/storage-version +1 -0
  102. package/supabase/migrations/001_initial_schema.sql +147 -0
  103. package/supabase/migrations/20260317010000_decouple_profiles_from_auth.sql +9 -0
  104. package/supabase/migrations/20260317020000_agent_curation.sql +10 -0
  105. package/supabase/migrations/20260320000000_agent_posts.sql +41 -0
  106. package/supabase/migrations/20260320120000_fix_draft_fk.sql +2 -0
  107. package/supabase/migrations/20260320130000_fix_identity.sql +17 -0
  108. package/supabase/migrations/20260320170000_intros.sql +118 -0
  109. package/test-model-comparison.ts +89 -0
  110. package/tsconfig.json +19 -0
@@ -0,0 +1,311 @@
1
+ import * as cheerio from "cheerio";
2
+ /**
3
+ * resolve a potentially relative url against a base url.
4
+ */
5
+ function resolveUrl(candidate, baseUrl) {
6
+ if (!candidate)
7
+ return null;
8
+ try {
9
+ return new URL(candidate, baseUrl).href;
10
+ }
11
+ catch {
12
+ return null;
13
+ }
14
+ }
15
+ function cleanText(value) {
16
+ if (!value)
17
+ return null;
18
+ const cleaned = value.replace(/\s+/g, " ").trim();
19
+ return cleaned || null;
20
+ }
21
+ function extractDomainSpecificBodyText($, url) {
22
+ if (url.includes("github.com")) {
23
+ return cleanText([
24
+ $("article.markdown-body").text(),
25
+ $("div[data-testid='repository-sidebar']").text(),
26
+ $("div.Layout-sidebar").text(),
27
+ ].join(" "))?.slice(0, 1500) || null;
28
+ }
29
+ if (url.includes("anthropic.com")) {
30
+ return cleanText([
31
+ $("article").text(),
32
+ $("main").text(),
33
+ $("[data-testid='article-content']").text(),
34
+ ].join(" "))?.slice(0, 1500) || null;
35
+ }
36
+ if (url.includes("simonwillison.net")) {
37
+ return cleanText([
38
+ $("article").text(),
39
+ $(".entry-content").text(),
40
+ $(".hentry").text(),
41
+ ].join(" "))?.slice(0, 1500) || null;
42
+ }
43
+ return null;
44
+ }
45
+ /**
46
+ * try to extract structured data from json-ld script tags.
47
+ * looks for Article, BlogPosting, NewsArticle, WebPage types.
48
+ */
49
+ function extractJsonLd($) {
50
+ const result = { title: null, description: null, image: null, author: null, date: null };
51
+ const targetTypes = ["Article", "BlogPosting", "NewsArticle", "WebPage", "TechArticle"];
52
+ $('script[type="application/ld+json"]').each((_, el) => {
53
+ try {
54
+ const raw = $(el).html();
55
+ if (!raw)
56
+ return;
57
+ const parsed = JSON.parse(raw);
58
+ // handle both single objects and arrays
59
+ const items = Array.isArray(parsed) ? parsed : [parsed];
60
+ for (const item of items) {
61
+ // also check @graph arrays (common pattern)
62
+ const candidates = item["@graph"] ? [...item["@graph"], item] : [item];
63
+ for (const obj of candidates) {
64
+ const type = obj["@type"];
65
+ const types = Array.isArray(type) ? type : [type];
66
+ if (!types.some((t) => targetTypes.includes(t)))
67
+ continue;
68
+ if (!result.title && obj.headline)
69
+ result.title = obj.headline;
70
+ if (!result.title && obj.name)
71
+ result.title = obj.name;
72
+ if (!result.description && obj.description)
73
+ result.description = obj.description;
74
+ // image can be string, object, or array
75
+ if (!result.image) {
76
+ const img = obj.image;
77
+ if (typeof img === "string")
78
+ result.image = img;
79
+ else if (Array.isArray(img) && img.length > 0) {
80
+ result.image = typeof img[0] === "string" ? img[0] : img[0]?.url || null;
81
+ }
82
+ else if (img?.url) {
83
+ result.image = img.url;
84
+ }
85
+ }
86
+ // author can be string, object, or array
87
+ if (!result.author) {
88
+ const auth = obj.author;
89
+ if (typeof auth === "string")
90
+ result.author = auth;
91
+ else if (Array.isArray(auth) && auth.length > 0) {
92
+ result.author = typeof auth[0] === "string" ? auth[0] : auth[0]?.name || null;
93
+ }
94
+ else if (auth?.name) {
95
+ result.author = auth.name;
96
+ }
97
+ }
98
+ if (!result.date) {
99
+ result.date = obj.datePublished || obj.dateCreated || null;
100
+ }
101
+ }
102
+ }
103
+ }
104
+ catch {
105
+ // malformed json-ld, skip
106
+ }
107
+ });
108
+ return result;
109
+ }
110
+ /** patterns in image urls that suggest a generic default rather than real content */
111
+ const DEFAULT_IMAGE_PATTERNS = /\b(default|placeholder|logo|og-default|brand|fallback|generic|site-image)\b/i;
112
+ const SHOUT_DEFAULT_IMAGE = "https://ooykzbkcquvreeheaijy.supabase.co/storage/v1/object/public/public/shout/shout-default.svg";
113
+ /**
114
+ * try to find the first real content image from the page body.
115
+ * skips icons, avatars, tracking pixels, and tiny images.
116
+ */
117
+ function extractFirstContentImage($, baseUrl) {
118
+ const skipSrcPatterns = /\b(avatar|icon|logo|emoji|badge|button|pixel|track|beacon|spacer|blank)\b/i;
119
+ // prefer images inside content containers, fall back to body
120
+ const contentSelectors = [
121
+ "article",
122
+ "main",
123
+ ".post-content",
124
+ ".entry-content",
125
+ ".post-body",
126
+ ".article-body",
127
+ ];
128
+ let container = null;
129
+ for (const sel of contentSelectors) {
130
+ const el = $(sel);
131
+ if (el.length) {
132
+ container = el.first();
133
+ break;
134
+ }
135
+ }
136
+ if (!container)
137
+ container = $("body");
138
+ if (!container.length)
139
+ return null;
140
+ const imgs = container.find("img");
141
+ for (let i = 0; i < imgs.length; i++) {
142
+ const img = $(imgs[i]);
143
+ const src = img.attr("src") || img.attr("data-src") || null;
144
+ if (!src)
145
+ continue;
146
+ // skip tracking pixels and tiny images by attribute
147
+ const w = parseInt(img.attr("width") || "", 10);
148
+ const h = parseInt(img.attr("height") || "", 10);
149
+ if ((w > 0 && w < 100) || (h > 0 && h < 100))
150
+ continue;
151
+ if (w === 1 || h === 1)
152
+ continue;
153
+ // skip by src pattern
154
+ if (skipSrcPatterns.test(src))
155
+ continue;
156
+ const resolved = resolveUrl(src, baseUrl);
157
+ if (resolved)
158
+ return resolved;
159
+ }
160
+ return null;
161
+ }
162
+ /**
163
+ * detect if a url is a twitter/x.com tweet and extract metadata via fxtwitter api.
164
+ */
165
+ async function extractTwitterMetadata(url) {
166
+ const tweetMatch = url.match(/(?:twitter\.com|x\.com)\/(\w+)\/status\/(\d+)/);
167
+ if (!tweetMatch)
168
+ return null;
169
+ const [, username, tweetId] = tweetMatch;
170
+ try {
171
+ const res = await fetch(`https://api.fxtwitter.com/${username}/status/${tweetId}`, {
172
+ signal: AbortSignal.timeout(10000),
173
+ });
174
+ if (!res.ok)
175
+ return null;
176
+ const data = await res.json();
177
+ const tweet = data.tweet;
178
+ if (!tweet)
179
+ return null;
180
+ const title = tweet.text || tweet.raw_text?.text || null;
181
+ const description = tweet.article?.preview_text || null;
182
+ const image_url = tweet.article?.cover_media?.media_info?.__typename === "ApiImage"
183
+ ? null // article cover doesn't have direct url in this path
184
+ : tweet.media?.photos?.[0]?.url ||
185
+ tweet.media?.all?.[0]?.url ||
186
+ tweet.author?.avatar_url ||
187
+ null;
188
+ const author = tweet.author?.name ? `${tweet.author.name} (@${tweet.author.screen_name})` : null;
189
+ const date = tweet.created_at || null;
190
+ // use tweet text as body content for summarization
191
+ const bodyText = (tweet.text || tweet.raw_text?.text || "").slice(0, 1500) || null;
192
+ // if it's an article tweet, prefer article title
193
+ if (tweet.article?.title) {
194
+ return {
195
+ title: tweet.article.title,
196
+ description: description || title,
197
+ image_url,
198
+ author,
199
+ date,
200
+ bodyText,
201
+ };
202
+ }
203
+ return { title, description, image_url, author, date, bodyText };
204
+ }
205
+ catch (err) {
206
+ console.error(`fxtwitter extraction error for ${url}:`, err);
207
+ return null;
208
+ }
209
+ }
210
+ /**
211
+ * fetch a url and extract og/meta tags for link preview data.
212
+ * falls back through: twitter api -> og -> twitter -> json-ld -> html tags -> domain-specific selectors.
213
+ */
214
+ export async function extractMetadata(url) {
215
+ // try twitter/x.com specific extraction first
216
+ const twitterResult = await extractTwitterMetadata(url);
217
+ if (twitterResult)
218
+ return twitterResult;
219
+ try {
220
+ const response = await fetch(url, {
221
+ headers: {
222
+ "User-Agent": "Mozilla/5.0 (compatible; NodShout/0.1; +https://nod.social)",
223
+ Accept: "text/html,application/xhtml+xml",
224
+ },
225
+ signal: AbortSignal.timeout(10000),
226
+ });
227
+ if (!response.ok) {
228
+ console.error(`fetch failed for ${url}: ${response.status}`);
229
+ return { title: null, description: null, image_url: null, author: null, date: null, bodyText: null };
230
+ }
231
+ const html = await response.text();
232
+ const $ = cheerio.load(html);
233
+ // extract json-ld structured data
234
+ const jsonLd = extractJsonLd($);
235
+ // title: og -> twitter -> json-ld -> <title> -> first h1 -> domain-specific
236
+ let title = $('meta[property="og:title"]').attr("content") ||
237
+ $('meta[name="twitter:title"]').attr("content") ||
238
+ jsonLd.title ||
239
+ $("title").text().trim() ||
240
+ $("h1").first().text().trim() ||
241
+ null;
242
+ // simon willison's blog: specific fallback
243
+ if (!title && url.includes("simonwillison")) {
244
+ title =
245
+ $("h1.entry-title").text().trim() ||
246
+ $(".entry-title").text().trim() ||
247
+ $("article h1").text().trim() ||
248
+ $(".hentry h1").text().trim() ||
249
+ null;
250
+ }
251
+ // description: og -> standard meta -> twitter -> json-ld
252
+ const description = $('meta[property="og:description"]').attr("content") ||
253
+ $('meta[name="description"]').attr("content") ||
254
+ $('meta[name="twitter:description"]').attr("content") ||
255
+ jsonLd.description ||
256
+ null;
257
+ // image: og -> twitter:image -> json-ld -> apple-touch-icon -> favicon
258
+ const rawImage = $('meta[property="og:image"]').attr("content") ||
259
+ $('meta[name="twitter:image"]').attr("content") ||
260
+ $('meta[name="twitter:image:src"]').attr("content") ||
261
+ jsonLd.image ||
262
+ $('link[rel="apple-touch-icon"]').attr("href") ||
263
+ $('link[rel="apple-touch-icon-precomposed"]').attr("href") ||
264
+ $('link[rel="icon"][type="image/png"]').attr("href") ||
265
+ $('link[rel="icon"]').attr("href") ||
266
+ null;
267
+ // resolve relative image urls against the page url
268
+ let image_url = resolveUrl(rawImage, url);
269
+ // if no image found or it looks like a generic default, try first content image
270
+ // then apple-touch-icon, then shout branded default
271
+ if (!image_url || DEFAULT_IMAGE_PATTERNS.test(new URL(image_url).pathname)) {
272
+ const contentImage = extractFirstContentImage($, url);
273
+ if (contentImage) {
274
+ image_url = contentImage;
275
+ }
276
+ else {
277
+ // try apple-touch-icon (usually 152x152+, much better than tiny favicons)
278
+ const touchIcon = resolveUrl($('link[rel="apple-touch-icon"]').attr("href") ||
279
+ $('link[rel="apple-touch-icon-precomposed"]').attr("href") ||
280
+ null, url);
281
+ image_url = touchIcon || SHOUT_DEFAULT_IMAGE;
282
+ }
283
+ }
284
+ // author: meta -> article:author -> json-ld
285
+ const author = $('meta[name="author"]').attr("content") ||
286
+ $('meta[property="article:author"]').attr("content") ||
287
+ jsonLd.author ||
288
+ null;
289
+ // date: article:published_time -> meta date -> json-ld
290
+ const date = $('meta[property="article:published_time"]').attr("content") ||
291
+ $('meta[name="date"]').attr("content") ||
292
+ jsonLd.date ||
293
+ null;
294
+ // extract body text for AI summarization (first ~1500 chars of content)
295
+ const domainBodyText = extractDomainSpecificBodyText($, url);
296
+ const bodyEl = $("article").length ? $("article") : $("main").length ? $("main") : $("body");
297
+ const genericBodyText = bodyEl
298
+ .clone()
299
+ .find("script, style, nav, header, footer, aside, .sidebar, .comments")
300
+ .remove()
301
+ .end()
302
+ .text();
303
+ const bodyText = cleanText(domainBodyText || genericBodyText)?.slice(0, 1500) || null;
304
+ return { title, description, image_url, author, date, bodyText };
305
+ }
306
+ catch (err) {
307
+ console.error(`metadata extraction error for ${url}:`, err);
308
+ return { title: null, description: null, image_url: null, author: null, date: null, bodyText: null };
309
+ }
310
+ }
311
+ //# sourceMappingURL=metadata.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"metadata.js","sourceRoot":"","sources":["../../src/lib/metadata.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ export declare function loadSkill(name: string): string;
2
+ export declare function loadSkills(names: string[]): string;
3
+ //# sourceMappingURL=skills.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../../src/lib/skills.ts"],"names":[],"mappings":"AAKA,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAM9C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,MAAM,CAOlD"}
@@ -0,0 +1,20 @@
1
+ import { readFileSync } from "fs";
2
+ import { join } from "path";
3
+ const SKILLS_DIR = join(process.cwd(), "skills");
4
+ export function loadSkill(name) {
5
+ try {
6
+ return readFileSync(join(SKILLS_DIR, name, "SKILL.md"), "utf8");
7
+ }
8
+ catch {
9
+ return "";
10
+ }
11
+ }
12
+ export function loadSkills(names) {
13
+ return names
14
+ .map((name) => {
15
+ const content = loadSkill(name).trim();
16
+ return content ? `\n\n[skill:${name}]\n${content}` : "";
17
+ })
18
+ .join("");
19
+ }
20
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","sourceRoot":"","sources":["../../src/lib/skills.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,IAAI,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAE5B,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,QAAQ,CAAC,CAAC;AAEjD,MAAM,UAAU,SAAS,CAAC,IAAY;IACpC,IAAI,CAAC;QACH,OAAO,YAAY,CAAC,IAAI,CAAC,UAAU,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAe;IACxC,OAAO,KAAK;SACT,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,SAAS,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,OAAO,CAAC,CAAC,CAAC,cAAc,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;IAC1D,CAAC,CAAC;SACD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare const supabase: import("@supabase/supabase-js").SupabaseClient<any, "public", "public", any, any>;
2
+ //# sourceMappingURL=supabase.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.d.ts","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAWA,eAAO,MAAM,QAAQ,mFAAyC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { createClient } from "@supabase/supabase-js";
2
+ const supabaseUrl = process.env.SUPABASE_URL;
3
+ const supabaseKey = process.env.SUPABASE_SERVICE_ROLE_KEY || process.env.SUPABASE_SERVICE_KEY;
4
+ if (!supabaseUrl || !supabaseKey) {
5
+ throw new Error("missing SUPABASE_URL or SUPABASE_SERVICE_ROLE_KEY environment variables");
6
+ }
7
+ export const supabase = createClient(supabaseUrl, supabaseKey);
8
+ //# sourceMappingURL=supabase.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"supabase.js","sourceRoot":"","sources":["../../src/lib/supabase.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAErD,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AAC7C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,OAAO,CAAC,GAAG,CAAC,oBAAoB,CAAC;AAE9F,IAAI,CAAC,WAAW,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,IAAI,KAAK,CACb,yEAAyE,CAC1E,CAAC;AACJ,CAAC;AAED,MAAM,CAAC,MAAM,QAAQ,GAAG,YAAY,CAAC,WAAW,EAAE,WAAW,CAAC,CAAC"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerCollectionTools(server: McpServer): void;
3
+ //# sourceMappingURL=collections.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collections.d.ts","sourceRoot":"","sources":["../../src/tools/collections.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,QAiLxD"}
@@ -0,0 +1,142 @@
1
+ import { z } from "zod";
2
+ import { supabase } from "../lib/supabase.js";
3
+ export function registerCollectionTools(server) {
4
+ // shout_create_collection
5
+ server.tool("shout_create_collection", "create a new collection to organize your shouts.", {
6
+ user_id: z.string().uuid().describe("the user's id"),
7
+ name: z.string().describe("collection name"),
8
+ description: z.string().optional().describe("collection description"),
9
+ auto_rules: z
10
+ .record(z.unknown())
11
+ .optional()
12
+ .describe("auto-sort rules (e.g. tag-based routing)"),
13
+ }, async ({ user_id, name, description, auto_rules }) => {
14
+ // generate slug from name
15
+ const slug = name
16
+ .toLowerCase()
17
+ .replace(/[^a-z0-9\s-]/g, "")
18
+ .replace(/\s+/g, "-")
19
+ .replace(/-+/g, "-")
20
+ .trim();
21
+ const { data, error } = await supabase
22
+ .from("collections")
23
+ .insert({
24
+ user_id,
25
+ name,
26
+ description: description || null,
27
+ slug,
28
+ auto_rules: auto_rules || null,
29
+ })
30
+ .select()
31
+ .single();
32
+ if (error) {
33
+ return {
34
+ content: [
35
+ { type: "text", text: `error creating collection: ${error.message}` },
36
+ ],
37
+ };
38
+ }
39
+ return {
40
+ content: [
41
+ {
42
+ type: "text",
43
+ text: `collection "${name}" created (slug: ${slug}, id: ${data.id})`,
44
+ },
45
+ ],
46
+ };
47
+ });
48
+ // shout_add_to_collection
49
+ server.tool("shout_add_to_collection", "add a shout to a collection by slug.", {
50
+ shout_id: z.string().uuid().describe("the shout id"),
51
+ user_id: z.string().uuid().describe("the user's id"),
52
+ collection_slug: z.string().describe("the collection slug to add to"),
53
+ }, async ({ shout_id, user_id, collection_slug }) => {
54
+ // resolve collection by slug for this user
55
+ const { data: col, error: colErr } = await supabase
56
+ .from("collections")
57
+ .select("id, name")
58
+ .eq("user_id", user_id)
59
+ .eq("slug", collection_slug)
60
+ .single();
61
+ if (colErr || !col) {
62
+ return {
63
+ content: [
64
+ { type: "text", text: `collection "${collection_slug}" not found.` },
65
+ ],
66
+ };
67
+ }
68
+ // update the shout's collection_id
69
+ const { error } = await supabase
70
+ .from("shouts")
71
+ .update({ collection_id: col.id })
72
+ .eq("id", shout_id)
73
+ .eq("user_id", user_id);
74
+ if (error) {
75
+ return {
76
+ content: [
77
+ { type: "text", text: `error adding to collection: ${error.message}` },
78
+ ],
79
+ };
80
+ }
81
+ return {
82
+ content: [
83
+ { type: "text", text: `shout ${shout_id} added to "${col.name}" (${collection_slug}).` },
84
+ ],
85
+ };
86
+ });
87
+ // shout_remove_from_collection
88
+ server.tool("shout_remove_from_collection", "remove a shout from its collection (sets collection_id to null).", {
89
+ shout_id: z.string().uuid().describe("the shout id"),
90
+ user_id: z.string().uuid().describe("the user's id"),
91
+ }, async ({ shout_id, user_id }) => {
92
+ const { error } = await supabase
93
+ .from("shouts")
94
+ .update({ collection_id: null })
95
+ .eq("id", shout_id)
96
+ .eq("user_id", user_id);
97
+ if (error) {
98
+ return {
99
+ content: [
100
+ { type: "text", text: `error removing from collection: ${error.message}` },
101
+ ],
102
+ };
103
+ }
104
+ return {
105
+ content: [
106
+ { type: "text", text: `shout ${shout_id} removed from its collection.` },
107
+ ],
108
+ };
109
+ });
110
+ // shout_list_collections
111
+ server.tool("shout_list_collections", "list all your collections.", {
112
+ user_id: z.string().uuid().describe("the user's id"),
113
+ }, async ({ user_id }) => {
114
+ const { data, error } = await supabase
115
+ .from("collections")
116
+ .select("*")
117
+ .eq("user_id", user_id)
118
+ .order("created_at", { ascending: false });
119
+ if (error) {
120
+ return {
121
+ content: [
122
+ { type: "text", text: `error listing collections: ${error.message}` },
123
+ ],
124
+ };
125
+ }
126
+ if (!data || data.length === 0) {
127
+ return {
128
+ content: [{ type: "text", text: "no collections yet." }],
129
+ };
130
+ }
131
+ const lines = data.map((c, i) => `${i + 1}. ${c.name} (/${c.slug}) - ${c.description || "no description"} [${c.visibility}]`);
132
+ return {
133
+ content: [
134
+ {
135
+ type: "text",
136
+ text: `${data.length} collections:\n\n${lines.join("\n")}`,
137
+ },
138
+ ],
139
+ };
140
+ });
141
+ }
142
+ //# sourceMappingURL=collections.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"collections.js","sourceRoot":"","sources":["../../src/tools/collections.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerIntroTools(server: McpServer): void;
3
+ //# sourceMappingURL=intros.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"intros.d.ts","sourceRoot":"","sources":["../../src/tools/intros.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASzE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,QA0jBnD"}