@noelclaw/mcp 2.3.1 → 3.0.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.
- package/README.md +216 -116
- package/dist/index.js +10 -9
- package/dist/server.js +39 -29
- package/dist/tools/automation.js +38 -0
- package/dist/tools/coder.js +62 -105
- package/dist/tools/defi.js +113 -24
- package/dist/tools/framework.js +0 -108
- package/dist/tools/humanizer.js +143 -2
- package/dist/tools/insight.js +197 -19
- package/dist/tools/market.js +182 -7
- package/dist/tools/memory.js +159 -43
- package/dist/tools/miroshark.js +15 -4
- package/dist/tools/os.js +223 -0
- package/dist/tools/scanner.js +183 -52
- package/dist/tools/swarm.js +37 -79
- package/dist/tools/vault.js +39 -200
- package/package.json +5 -2
- package/dist/tools/news.js +0 -6
- package/dist/tools/research.js +0 -8
- package/dist/tools/twitter.js +0 -67
package/dist/tools/vault.js
CHANGED
|
@@ -6,14 +6,14 @@ const zod_1 = require("zod");
|
|
|
6
6
|
const convex_js_1 = require("../convex.js");
|
|
7
7
|
const memory_js_1 = require("./memory.js");
|
|
8
8
|
const VAULT_TYPES = ["research", "execution", "workflow", "prompt", "file", "memory", "credential"];
|
|
9
|
-
const LINK_RELATIONS = ["references", "derived_from", "supersedes", "related", "continues"];
|
|
10
9
|
exports.VAULT_TOOLS = [
|
|
11
10
|
{
|
|
12
11
|
name: "vault_save",
|
|
13
12
|
description: "Save or update an artifact in Noel-Vault — the persistent memory layer for agents. " +
|
|
14
13
|
"Use this to store research outputs, execution logs, workflows, versioned prompts, " +
|
|
15
14
|
"generated files, or long-term memory. Each save creates a new version automatically. " +
|
|
16
|
-
"Same key = update existing (git-style). Types: research | execution | workflow | prompt | file | memory."
|
|
15
|
+
"Same key = update existing (git-style). Types: research | execution | workflow | prompt | file | memory. " +
|
|
16
|
+
"For a quick note or preference, use type='memory' with just content — title is optional.",
|
|
17
17
|
inputSchema: {
|
|
18
18
|
type: "object",
|
|
19
19
|
properties: {
|
|
@@ -100,7 +100,7 @@ exports.VAULT_TOOLS = [
|
|
|
100
100
|
{
|
|
101
101
|
name: "vault_export",
|
|
102
102
|
description: "Export your entire Noel-Vault or a specific type as a structured bundle. " +
|
|
103
|
-
"Useful for archiving, syncing to
|
|
103
|
+
"Useful for archiving, syncing to GitHub, or passing context to another agent.",
|
|
104
104
|
inputSchema: {
|
|
105
105
|
type: "object",
|
|
106
106
|
properties: {
|
|
@@ -109,38 +109,6 @@ exports.VAULT_TOOLS = [
|
|
|
109
109
|
required: [],
|
|
110
110
|
},
|
|
111
111
|
},
|
|
112
|
-
{
|
|
113
|
-
name: "vault_remember",
|
|
114
|
-
description: "One-liner: save anything to Noel-Vault without specifying type or title. " +
|
|
115
|
-
"Just pass content — Noel infers the title and saves as a memory entry. " +
|
|
116
|
-
"Use this for quick notes, preferences, decisions, and things to remember across sessions. " +
|
|
117
|
-
"Example: vault_remember content: 'User prefers low-risk DeFi, confirmed multiple times'",
|
|
118
|
-
inputSchema: {
|
|
119
|
-
type: "object",
|
|
120
|
-
properties: {
|
|
121
|
-
content: { type: "string", description: "What to remember — plain text, markdown, or a short note" },
|
|
122
|
-
title: { type: "string", description: "Optional title. Auto-inferred from content if omitted." },
|
|
123
|
-
tags: { type: "array", items: { type: "string" }, description: "Optional tags for later retrieval" },
|
|
124
|
-
},
|
|
125
|
-
required: ["content"],
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
|
-
{
|
|
129
|
-
name: "vault_context",
|
|
130
|
-
description: "Load semantically relevant vault entries for a topic — formatted context ready to inject into a prompt. " +
|
|
131
|
-
"Uses Supermemory vector search when available (understands meaning, not just keywords), " +
|
|
132
|
-
"with automatic fallback to full-text search. " +
|
|
133
|
-
"Call this at the start of any research or analysis task to prime your AI with all past knowledge on the topic. " +
|
|
134
|
-
"Returns full content of matching entries. Credentials are never included.",
|
|
135
|
-
inputSchema: {
|
|
136
|
-
type: "object",
|
|
137
|
-
properties: {
|
|
138
|
-
topic: { type: "string", description: "Topic or query to load context for, e.g. 'ETH DeFi strategy' or 'BTC market thesis'" },
|
|
139
|
-
limit: { type: "number", description: "Max entries to return (default 8, max 20)" },
|
|
140
|
-
},
|
|
141
|
-
required: ["topic"],
|
|
142
|
-
},
|
|
143
|
-
},
|
|
144
112
|
{
|
|
145
113
|
name: "vault_store_credential",
|
|
146
114
|
description: "Securely store an API key, token, or secret in your vault. " +
|
|
@@ -169,50 +137,42 @@ exports.VAULT_TOOLS = [
|
|
|
169
137
|
},
|
|
170
138
|
},
|
|
171
139
|
{
|
|
172
|
-
name: "
|
|
173
|
-
description: "
|
|
174
|
-
"
|
|
175
|
-
"You can also unpublish by setting isPublic to false.",
|
|
140
|
+
name: "vault_pin",
|
|
141
|
+
description: "Pin or unpin a Noel-Vault entry. Pinned entries always appear first in vault_list and are " +
|
|
142
|
+
"prioritized in memory_context and search results. Use for your most important research, key prompts, or canonical references.",
|
|
176
143
|
inputSchema: {
|
|
177
144
|
type: "object",
|
|
178
145
|
properties: {
|
|
179
|
-
key: { type: "string", description: "Entry key to
|
|
180
|
-
|
|
181
|
-
authorName: { type: "string", description: "Display name shown to the community (default: Anonymous)" },
|
|
146
|
+
key: { type: "string", description: "Entry key to pin or unpin" },
|
|
147
|
+
pinned: { type: "boolean", description: "true to pin, false to unpin (default: true)" },
|
|
182
148
|
},
|
|
183
149
|
required: ["key"],
|
|
184
150
|
},
|
|
185
151
|
},
|
|
186
152
|
{
|
|
187
|
-
name: "
|
|
188
|
-
description: "
|
|
189
|
-
"
|
|
190
|
-
"Use vault_save to fork any entry into your own vault.",
|
|
153
|
+
name: "vault_delete",
|
|
154
|
+
description: "Permanently delete a Noel-Vault entry including all its version history. This cannot be undone. " +
|
|
155
|
+
"Use vault_list to browse entries before deleting.",
|
|
191
156
|
inputSchema: {
|
|
192
157
|
type: "object",
|
|
193
158
|
properties: {
|
|
194
|
-
|
|
195
|
-
search: { type: "string", description: "Search query to filter community entries" },
|
|
196
|
-
limit: { type: "number", description: "Max entries to return (default 20)" },
|
|
159
|
+
key: { type: "string", description: "Entry key to delete permanently" },
|
|
197
160
|
},
|
|
198
|
-
required: [],
|
|
161
|
+
required: ["key"],
|
|
199
162
|
},
|
|
200
163
|
},
|
|
201
164
|
{
|
|
202
|
-
name: "
|
|
203
|
-
description: "
|
|
204
|
-
"
|
|
205
|
-
"Perfect for indexing GitHub repos, research papers, Notion pages, or any web page. " +
|
|
206
|
-
"For full Google Drive / Gmail / Notion workspace sync, connect via the Noelclaw dashboard.",
|
|
165
|
+
name: "vault_tag",
|
|
166
|
+
description: "Add or replace tags on an existing Noel-Vault entry without modifying its content. " +
|
|
167
|
+
"Useful for organizing entries retroactively. Set replace=true to overwrite all existing tags.",
|
|
207
168
|
inputSchema: {
|
|
208
169
|
type: "object",
|
|
209
170
|
properties: {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
tags: { type: "array", items: { type: "string" }, description: "Tags for filtering" },
|
|
171
|
+
key: { type: "string", description: "Entry key to update tags on" },
|
|
172
|
+
tags: { type: "array", items: { type: "string" }, description: "Tags to add (or replace if replace=true)" },
|
|
173
|
+
replace: { type: "boolean", description: "If true, replaces all existing tags. If false (default), merges with existing." },
|
|
214
174
|
},
|
|
215
|
-
required: ["
|
|
175
|
+
required: ["key", "tags"],
|
|
216
176
|
},
|
|
217
177
|
},
|
|
218
178
|
];
|
|
@@ -243,13 +203,11 @@ const SearchSchema = zod_1.z.object({
|
|
|
243
203
|
const HistorySchema = zod_1.z.object({ key: zod_1.z.string().min(1) });
|
|
244
204
|
const DiffSchema = zod_1.z.object({ key: zod_1.z.string().min(1), fromVersion: zod_1.z.number(), toVersion: zod_1.z.number() });
|
|
245
205
|
const ExportSchema = zod_1.z.object({ type: zod_1.z.enum(VAULT_TYPES).optional() });
|
|
246
|
-
const RememberSchema = zod_1.z.object({ content: zod_1.z.string().min(1), title: zod_1.z.string().optional(), tags: zod_1.z.array(zod_1.z.string()).optional() });
|
|
247
|
-
const ContextSchema = zod_1.z.object({ topic: zod_1.z.string().min(1), limit: zod_1.z.number().optional() });
|
|
248
206
|
const StoreCredentialSchema = zod_1.z.object({ name: zod_1.z.string().min(1), value: zod_1.z.string().min(1), description: zod_1.z.string().optional() });
|
|
249
207
|
const GetCredentialSchema = zod_1.z.object({ name: zod_1.z.string().min(1) });
|
|
250
|
-
const
|
|
251
|
-
const
|
|
252
|
-
const
|
|
208
|
+
const PinSchema = zod_1.z.object({ key: zod_1.z.string().min(1), pinned: zod_1.z.boolean().optional() });
|
|
209
|
+
const DeleteSchema = zod_1.z.object({ key: zod_1.z.string().min(1) });
|
|
210
|
+
const TagSchema = zod_1.z.object({ key: zod_1.z.string().min(1), tags: zod_1.z.array(zod_1.z.string()).min(1), replace: zod_1.z.boolean().optional() });
|
|
253
211
|
// ─── Helpers ─────────────────────────────────────────────────────────────────
|
|
254
212
|
function formatBytes(n) {
|
|
255
213
|
if (!n)
|
|
@@ -437,69 +395,6 @@ async function handleVaultTool(name, args) {
|
|
|
437
395
|
const rows = entries.map((e) => `**[\`${e.key}\`]** ${e.title} (${e.type} · v${e.version})\n${e.content.slice(0, 500)}${e.content.length > 500 ? "\n…" : ""}`);
|
|
438
396
|
return { content: [{ type: "text", text: [...header, ...rows.join("\n\n---\n\n").split("\n")].join("\n") }] };
|
|
439
397
|
}
|
|
440
|
-
case "vault_remember": {
|
|
441
|
-
const parsed = RememberSchema.safeParse(args);
|
|
442
|
-
if (!parsed.success)
|
|
443
|
-
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
444
|
-
const { content, title, tags } = parsed.data;
|
|
445
|
-
const inferredTitle = title ?? content.slice(0, 60).replace(/\n/g, " ").trim() + (content.length > 60 ? "…" : "");
|
|
446
|
-
const data = await (0, convex_js_1.callConvex)("/vault/save", "POST", {
|
|
447
|
-
type: "memory",
|
|
448
|
-
title: inferredTitle,
|
|
449
|
-
content,
|
|
450
|
-
tags,
|
|
451
|
-
commitMsg: "vault_remember",
|
|
452
|
-
}, "vault_remember");
|
|
453
|
-
if (data.error)
|
|
454
|
-
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
455
|
-
// Mirror to semantic memory
|
|
456
|
-
(0, memory_js_1.syncToSupermemory)(content, {
|
|
457
|
-
vaultKey: data.key, title: inferredTitle, type: "memory",
|
|
458
|
-
tags, version: data.version, source: "vault_remember",
|
|
459
|
-
});
|
|
460
|
-
const smNote = " 🧠 Synced to semantic memory";
|
|
461
|
-
return { content: [{ type: "text", text: `✅ Remembered — key: \`${data.key}\` (v${data.version})${smNote}\nRetrieve later with: \`vault_context topic: "${inferredTitle.slice(0, 40)}"\`` }] };
|
|
462
|
-
}
|
|
463
|
-
case "vault_context": {
|
|
464
|
-
const parsed = ContextSchema.safeParse(args);
|
|
465
|
-
if (!parsed.success)
|
|
466
|
-
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
467
|
-
const limit = parsed.data.limit ?? 8;
|
|
468
|
-
// Semantic context (proxied through Convex)
|
|
469
|
-
{
|
|
470
|
-
const smResults = await (0, memory_js_1.searchSupermemory)(parsed.data.topic, limit);
|
|
471
|
-
if (smResults.length > 0) {
|
|
472
|
-
const contextParts = smResults.map((r, i) => {
|
|
473
|
-
const title = r.metadata?.title ?? `Entry ${i + 1}`;
|
|
474
|
-
return `### ${title}\n${r.content}`;
|
|
475
|
-
});
|
|
476
|
-
const summary = smResults.map(r => r.metadata?.title ?? r.content.slice(0, 50)).join(", ");
|
|
477
|
-
return {
|
|
478
|
-
content: [{
|
|
479
|
-
type: "text",
|
|
480
|
-
text: [
|
|
481
|
-
`📚 **Vault Context** [Semantic] for: "${parsed.data.topic}"`,
|
|
482
|
-
`Entries: ${summary}`,
|
|
483
|
-
``,
|
|
484
|
-
`---`,
|
|
485
|
-
``,
|
|
486
|
-
contextParts.join("\n\n---\n\n"),
|
|
487
|
-
].join("\n"),
|
|
488
|
-
}],
|
|
489
|
-
};
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
// Fallback: Convex full-text context
|
|
493
|
-
const params = new URLSearchParams({ q: parsed.data.topic });
|
|
494
|
-
params.set("limit", String(limit));
|
|
495
|
-
const data = await (0, convex_js_1.callConvex)(`/vault/context?${params}`, "GET", undefined, "vault_context");
|
|
496
|
-
if (data.error)
|
|
497
|
-
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
498
|
-
if (!data.context)
|
|
499
|
-
return { content: [{ type: "text", text: `No vault context found for: "${parsed.data.topic}"\nStart building your knowledge base with vault_remember or vault_save.` }] };
|
|
500
|
-
const summary = data.entries.map((e) => `[${e.type}] ${e.title}`).join(", ");
|
|
501
|
-
return { content: [{ type: "text", text: `📚 **Vault Context** loaded for: "${parsed.data.topic}"\nEntries: ${summary}\n\n---\n\n${data.context}` }] };
|
|
502
|
-
}
|
|
503
398
|
case "vault_store_credential": {
|
|
504
399
|
const parsed = StoreCredentialSchema.safeParse(args);
|
|
505
400
|
if (!parsed.success)
|
|
@@ -524,90 +419,34 @@ async function handleVaultTool(name, args) {
|
|
|
524
419
|
lines.push(`Stored: ${data.storedAt}`);
|
|
525
420
|
return { content: [{ type: "text", text: lines.join("\n") }] };
|
|
526
421
|
}
|
|
527
|
-
case "
|
|
528
|
-
const parsed =
|
|
422
|
+
case "vault_pin": {
|
|
423
|
+
const parsed = PinSchema.safeParse(args);
|
|
529
424
|
if (!parsed.success)
|
|
530
425
|
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
531
|
-
const { key,
|
|
532
|
-
const
|
|
533
|
-
const data = await (0, convex_js_1.callConvex)(endpoint, "POST", { key, authorName }, "vault_publish");
|
|
426
|
+
const { key, pinned = true } = parsed.data;
|
|
427
|
+
const data = await (0, convex_js_1.callConvex)("/vault/pin", "POST", { key, pinned }, "vault_pin");
|
|
534
428
|
if (data.error)
|
|
535
429
|
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
536
|
-
return {
|
|
537
|
-
content: [{
|
|
538
|
-
type: "text",
|
|
539
|
-
text: isPublic
|
|
540
|
-
? `🌐 **Published to community vault**\nKey: \`${key}\`\nOther Noelclaw users can now discover this entry.\nUse \`vault_publish key: "${key}" isPublic: false\` to unpublish.`
|
|
541
|
-
: `🔒 **Unpublished**\nKey: \`${key}\` is now private.`,
|
|
542
|
-
}],
|
|
543
|
-
};
|
|
430
|
+
return { content: [{ type: "text", text: pinned ? `📌 Pinned: \`${key}\`` : `📌 Unpinned: \`${key}\`` }] };
|
|
544
431
|
}
|
|
545
|
-
case "
|
|
546
|
-
const parsed =
|
|
432
|
+
case "vault_delete": {
|
|
433
|
+
const parsed = DeleteSchema.safeParse(args);
|
|
547
434
|
if (!parsed.success)
|
|
548
435
|
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
549
|
-
const
|
|
550
|
-
if (parsed.data.type)
|
|
551
|
-
params.set("type", parsed.data.type);
|
|
552
|
-
if (parsed.data.search)
|
|
553
|
-
params.set("search", parsed.data.search);
|
|
554
|
-
if (parsed.data.limit)
|
|
555
|
-
params.set("limit", String(parsed.data.limit));
|
|
556
|
-
const data = await (0, convex_js_1.callConvex)(`/vault/community?${params}`, "GET", undefined, "vault_explore");
|
|
436
|
+
const data = await (0, convex_js_1.callConvex)("/vault/delete", "POST", { key: parsed.data.key }, "vault_delete");
|
|
557
437
|
if (data.error)
|
|
558
438
|
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
559
|
-
|
|
560
|
-
if (!entries.length)
|
|
561
|
-
return { content: [{ type: "text", text: `No community vault entries found${parsed.data.type ? ` of type '${parsed.data.type}'` : ""}.${parsed.data.search ? ` Try a different search term.` : "\nBe the first to publish with vault_publish!"}` }] };
|
|
562
|
-
const header = `🌐 **Community Vault** — ${entries.length} public entries`;
|
|
563
|
-
const rows = entries.map((e) => [
|
|
564
|
-
`**[${e.type}]** ${e.title} · by ${e.authorName ?? "Anonymous"}`,
|
|
565
|
-
` \`${e.key}\` · v${e.version} · ${formatDate(e.updatedAt)}`,
|
|
566
|
-
e.content ? ` ${e.content.slice(0, 100)}${e.content.length > 100 ? "…" : ""}` : "",
|
|
567
|
-
].filter(Boolean).join("\n"));
|
|
568
|
-
return {
|
|
569
|
-
content: [{
|
|
570
|
-
type: "text",
|
|
571
|
-
text: [header, "", ...rows, "", "To fork an entry: `vault_save type: <type> title: <title> content: <content>`"].join("\n"),
|
|
572
|
-
}],
|
|
573
|
-
};
|
|
439
|
+
return { content: [{ type: "text", text: `🗑️ Deleted: \`${parsed.data.key}\` (${data.versionsRemoved ?? 0} versions removed)` }] };
|
|
574
440
|
}
|
|
575
|
-
case "
|
|
576
|
-
const parsed =
|
|
441
|
+
case "vault_tag": {
|
|
442
|
+
const parsed = TagSchema.safeParse(args);
|
|
577
443
|
if (!parsed.success)
|
|
578
444
|
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
579
|
-
const {
|
|
580
|
-
const
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
title: inferredTitle,
|
|
585
|
-
content: `Connected from: ${url}\n\n(Content indexed into semantic memory via Supermemory)`,
|
|
586
|
-
key: `connected/${inferredTitle.toLowerCase().replace(/[^a-z0-9]+/g, "-").slice(0, 50)}`,
|
|
587
|
-
tags: [...(tags ?? []), "connected", new URL(url).hostname],
|
|
588
|
-
commitMsg: "vault_connect",
|
|
589
|
-
metadata: JSON.stringify({ sourceUrl: url }),
|
|
590
|
-
}, "vault_connect");
|
|
591
|
-
// Mirror full content to Supermemory with source URL for ingestion
|
|
592
|
-
(0, memory_js_1.syncToSupermemory)("", {
|
|
593
|
-
vaultKey: vaultData.key, title: inferredTitle, type, tags, source: "vault_connect",
|
|
594
|
-
}, url);
|
|
595
|
-
if (vaultData.error)
|
|
596
|
-
return { content: [{ type: "text", text: `Error: ${vaultData.error}` }], isError: true };
|
|
597
|
-
return {
|
|
598
|
-
content: [{
|
|
599
|
-
type: "text",
|
|
600
|
-
text: [
|
|
601
|
-
`🔗 **Vault Connected**`,
|
|
602
|
-
`URL: ${url}`,
|
|
603
|
-
`Vault key: \`${vaultData.key}\``,
|
|
604
|
-
`🧠 Indexing to semantic memory… searchable in ~30s`,
|
|
605
|
-
``,
|
|
606
|
-
`Search it with: \`vault_search query: "${inferredTitle}"\``,
|
|
607
|
-
`Or load as context: \`vault_context topic: "${inferredTitle}"\``,
|
|
608
|
-
].filter(Boolean).join("\n"),
|
|
609
|
-
}],
|
|
610
|
-
};
|
|
445
|
+
const { key, tags, replace = false } = parsed.data;
|
|
446
|
+
const data = await (0, convex_js_1.callConvex)("/vault/tag", "POST", { key, tags, replace }, "vault_tag");
|
|
447
|
+
if (data.error)
|
|
448
|
+
return { content: [{ type: "text", text: `Error: ${data.error}` }], isError: true };
|
|
449
|
+
return { content: [{ type: "text", text: `🏷️ Tags ${replace ? "set" : "updated"} on \`${key}\`: ${(data.tags ?? tags).join(", ")}` }] };
|
|
611
450
|
}
|
|
612
451
|
default:
|
|
613
452
|
return null;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@noelclaw/mcp",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "Noelclaw
|
|
3
|
+
"version": "3.0.0",
|
|
4
|
+
"description": "Noelclaw AI Operating System — persistent memory, multi-agent swarm, DeFi execution, market intelligence, and Sentinel-gated playbooks.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"bin": {
|
|
7
7
|
"noelclaw-mcp": "dist/index.js"
|
|
@@ -52,5 +52,8 @@
|
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=18"
|
|
55
|
+
},
|
|
56
|
+
"publishConfig": {
|
|
57
|
+
"access": "public"
|
|
55
58
|
}
|
|
56
59
|
}
|
package/dist/tools/news.js
DELETED
package/dist/tools/research.js
DELETED
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.RESEARCH_TOOLS = void 0;
|
|
4
|
-
exports.handleResearchTool = handleResearchTool;
|
|
5
|
-
exports.RESEARCH_TOOLS = [];
|
|
6
|
-
async function handleResearchTool(_name, _args) {
|
|
7
|
-
return null;
|
|
8
|
-
}
|
package/dist/tools/twitter.js
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.TWITTER_TOOLS = void 0;
|
|
4
|
-
exports.handleTwitterTool = handleTwitterTool;
|
|
5
|
-
const zod_1 = require("zod");
|
|
6
|
-
exports.TWITTER_TOOLS = [
|
|
7
|
-
{
|
|
8
|
-
name: "post_tweet",
|
|
9
|
-
description: "Post a tweet on X (Twitter) via Ayrshare. Requires AYRSHARE_API_KEY env var.",
|
|
10
|
-
inputSchema: {
|
|
11
|
-
type: "object",
|
|
12
|
-
properties: {
|
|
13
|
-
text: { type: "string", description: "Tweet content (max 280 characters)" },
|
|
14
|
-
reply_to: { type: "string", description: "Optional: tweet ID to reply to" },
|
|
15
|
-
},
|
|
16
|
-
required: ["text"],
|
|
17
|
-
},
|
|
18
|
-
},
|
|
19
|
-
];
|
|
20
|
-
const PostTweetSchema = zod_1.z.object({
|
|
21
|
-
text: zod_1.z.string().min(1).max(280),
|
|
22
|
-
reply_to: zod_1.z.string().optional(),
|
|
23
|
-
});
|
|
24
|
-
async function handleTwitterTool(name, args) {
|
|
25
|
-
if (name !== "post_tweet")
|
|
26
|
-
return null;
|
|
27
|
-
const parsed = PostTweetSchema.safeParse(args);
|
|
28
|
-
if (!parsed.success)
|
|
29
|
-
return { content: [{ type: "text", text: `Invalid input: ${parsed.error.issues[0].message}` }], isError: true };
|
|
30
|
-
const apiKey = process.env.AYRSHARE_API_KEY;
|
|
31
|
-
if (!apiKey) {
|
|
32
|
-
return {
|
|
33
|
-
content: [{ type: "text", text: "AYRSHARE_API_KEY not set.\n\nGet your key at ayrshare.com → Profile → API Key" }],
|
|
34
|
-
isError: true,
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
const body = {
|
|
38
|
-
post: parsed.data.text,
|
|
39
|
-
platforms: ["twitter"],
|
|
40
|
-
};
|
|
41
|
-
if (parsed.data.reply_to)
|
|
42
|
-
body.twitterOptions = { inReplyToStatusId: parsed.data.reply_to };
|
|
43
|
-
try {
|
|
44
|
-
const res = await fetch("https://app.ayrshare.com/api/post", {
|
|
45
|
-
method: "POST",
|
|
46
|
-
headers: {
|
|
47
|
-
"Content-Type": "application/json",
|
|
48
|
-
Authorization: `Bearer ${apiKey}`,
|
|
49
|
-
},
|
|
50
|
-
body: JSON.stringify(body),
|
|
51
|
-
signal: AbortSignal.timeout(15000),
|
|
52
|
-
});
|
|
53
|
-
const data = await res.json();
|
|
54
|
-
if (!res.ok || data.status === "error") {
|
|
55
|
-
const msg = data?.message ?? data?.errors?.[0] ?? JSON.stringify(data);
|
|
56
|
-
return { content: [{ type: "text", text: `Ayrshare error: ${msg}` }], isError: true };
|
|
57
|
-
}
|
|
58
|
-
const tweetId = data?.postIds?.find((p) => p.platform === "twitter")?.id;
|
|
59
|
-
const tweetUrl = tweetId ? `https://x.com/i/web/status/${tweetId}` : "";
|
|
60
|
-
return {
|
|
61
|
-
content: [{ type: "text", text: `✅ Tweet posted!\n\n"${parsed.data.text}"${tweetUrl ? `\n\n${tweetUrl}` : ""}` }],
|
|
62
|
-
};
|
|
63
|
-
}
|
|
64
|
-
catch (err) {
|
|
65
|
-
return { content: [{ type: "text", text: `Failed to post tweet: ${err.message}` }], isError: true };
|
|
66
|
-
}
|
|
67
|
-
}
|