@hasna/skills 0.1.32 → 0.1.33
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 +1 -16
- package/bin/index.js +57 -14
- package/bin/mcp.js +57 -13
- package/dist/cli/commands/runtime.d.ts +1 -1
- package/dist/index.js +51 -5
- package/dist/lib/skill-validation.d.ts +2 -0
- package/package.json +1 -1
- package/skills/ad-creative-pack/package.json +4 -7
- package/skills/api-docs-portal/package.json +5 -3
- package/skills/audio/package.json +4 -22
- package/skills/audio-transcript-pack/package.json +3 -2
- package/skills/blog-article/package.json +5 -21
- package/skills/brand-kit/package.json +4 -7
- package/skills/brand-photo-shoot/package.json +3 -2
- package/skills/browse/package.json +4 -33
- package/skills/contract-review-report/package.json +3 -2
- package/skills/customer-feedback-report/package.json +3 -2
- package/skills/deepresearch/package.json +4 -37
- package/skills/domainpurchase/SKILL.md +14 -31
- package/skills/domainpurchase/package.json +3 -8
- package/skills/email-sequence/package.json +4 -7
- package/skills/generate-book-cover/package.json +5 -23
- package/skills/icon-pack/package.json +4 -22
- package/skills/image/package.json +4 -22
- package/skills/invoice-reconciliation/package.json +3 -2
- package/skills/landing-page-pack/package.json +4 -7
- package/skills/logo-design/package.json +4 -2
- package/skills/managemcp/CLAUDE.md +9 -43
- package/skills/managemcp/README.md +12 -198
- package/skills/managemcp/package.json +2 -10
- package/skills/managemcp/tsconfig.json +1 -3
- package/skills/market-research-report/package.json +5 -4
- package/skills/meeting-pack/package.json +3 -2
- package/skills/migration-plan-pack/package.json +3 -2
- package/skills/music/package.json +4 -20
- package/skills/music-album/package.json +3 -2
- package/skills/one-page-website/package.json +3 -2
- package/skills/pdf-read/package.json +5 -23
- package/skills/pdf-to-dataset/package.json +5 -4
- package/skills/pdf-to-markdown/package.json +5 -4
- package/skills/performance-audit-report/package.json +3 -2
- package/skills/photo-album/package.json +4 -2
- package/skills/pitch-deck/package.json +5 -3
- package/skills/playlist-maker/package.json +4 -2
- package/skills/product-mockup/package.json +3 -2
- package/skills/proposal-pack/package.json +5 -4
- package/skills/read-pdf/package.json +4 -29
- package/skills/remove-background/package.json +5 -21
- package/skills/repo-onboarding-report/package.json +3 -2
- package/skills/sdk-generator/package.json +3 -2
- package/skills/security-audit-report/package.json +5 -4
- package/skills/seo-content-pack/package.json +5 -3
- package/skills/short-video-pack/package.json +3 -2
- package/skills/slide-deck-generator/package.json +3 -2
- package/skills/sms/README.md +18 -56
- package/skills/sms/package.json +1 -3
- package/skills/sms/tsconfig.json +1 -2
- package/skills/social-content-calendar/package.json +4 -7
- package/skills/test-suite-generator/package.json +5 -4
- package/skills/transcript/package.json +4 -23
- package/skills/video/package.json +4 -24
- package/skills/video-highlight-pack/package.json +3 -2
- package/skills/voiceover-jingle-pack/package.json +3 -2
- package/skills/webcrawling/package.json +4 -32
- package/skills/domainpurchase/.env.example +0 -7
- package/skills/domainpurchase/src/lib/api-client.ts +0 -571
- package/skills/domainpurchase/src/lib/config.ts +0 -209
- package/skills/domainpurchase/src/lib/installer.ts +0 -165
- package/skills/managemcp/.env.example +0 -16
- package/skills/managemcp/scripts/migrate.ts +0 -57
- package/skills/managemcp/scripts/seed.ts +0 -58
- package/skills/managemcp/src/db/index.ts +0 -37
- package/skills/managemcp/src/lib/api-client.ts +0 -108
- package/skills/managemcp/src/lib/config.ts +0 -34
- package/skills/managemcp/src/lib/installer.ts +0 -140
- package/skills/managemcp/src/lib/service-dir.ts +0 -119
- package/skills/sms/scripts/buy-number.ts +0 -63
- package/skills/sms/scripts/test-send.ts +0 -67
- package/skills/sms/src/server.ts +0 -351
- package/skills/sms/src/sse-server.ts +0 -279
|
@@ -1,140 +0,0 @@
|
|
|
1
|
-
import { readFile, writeFile, readdir, unlink, mkdir } from 'fs/promises';
|
|
2
|
-
import { join } from 'path';
|
|
3
|
-
import { homedir } from 'os';
|
|
4
|
-
import { getItem } from './api-client';
|
|
5
|
-
|
|
6
|
-
export type Target = 'claude' | 'codex';
|
|
7
|
-
export type ConflictStrategy = 'skip' | 'overwrite';
|
|
8
|
-
|
|
9
|
-
export interface InstallResult {
|
|
10
|
-
success: boolean;
|
|
11
|
-
message: string;
|
|
12
|
-
itemId: string;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
export interface InstalledItem {
|
|
16
|
-
id: string;
|
|
17
|
-
name: string;
|
|
18
|
-
target: Target;
|
|
19
|
-
installedAt: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const CLAUDE_DIR = join(homedir(), '.claude', 'skills');
|
|
23
|
-
const CODEX_DIR = join(homedir(), '.codex', 'skills');
|
|
24
|
-
|
|
25
|
-
function getTargetDir(target: Target): string {
|
|
26
|
-
return target === 'claude' ? CLAUDE_DIR : CODEX_DIR;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
async function ensureDir(dir: string): Promise<void> {
|
|
30
|
-
await mkdir(dir, { recursive: true });
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
async function writeItemFile(
|
|
34
|
-
target: Target,
|
|
35
|
-
itemId: string,
|
|
36
|
-
content: string,
|
|
37
|
-
strategy: ConflictStrategy
|
|
38
|
-
): Promise<boolean> {
|
|
39
|
-
const dir = getTargetDir(target);
|
|
40
|
-
await ensureDir(dir);
|
|
41
|
-
|
|
42
|
-
const filePath = join(dir, `${itemId}.json`);
|
|
43
|
-
|
|
44
|
-
try {
|
|
45
|
-
await readFile(filePath);
|
|
46
|
-
if (strategy === 'skip') return false;
|
|
47
|
-
} catch {
|
|
48
|
-
// File doesn't exist, proceed
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
await writeFile(filePath, content, 'utf-8');
|
|
52
|
-
return true;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async function installToTarget(
|
|
56
|
-
target: Target,
|
|
57
|
-
itemId: string,
|
|
58
|
-
strategy: ConflictStrategy = 'skip'
|
|
59
|
-
): Promise<InstallResult> {
|
|
60
|
-
try {
|
|
61
|
-
const item = await getItem(itemId);
|
|
62
|
-
const content = JSON.stringify(item, null, 2);
|
|
63
|
-
const written = await writeItemFile(target, itemId, content, strategy);
|
|
64
|
-
|
|
65
|
-
const targetName = target.charAt(0).toUpperCase() + target.slice(1);
|
|
66
|
-
return {
|
|
67
|
-
success: true,
|
|
68
|
-
message: written
|
|
69
|
-
? `Installed to ${targetName}: ${item.name}`
|
|
70
|
-
: `Skipped (already exists): ${item.name}`,
|
|
71
|
-
itemId,
|
|
72
|
-
};
|
|
73
|
-
} catch (error) {
|
|
74
|
-
return {
|
|
75
|
-
success: false,
|
|
76
|
-
message: `Failed to install to ${target}: ${error instanceof Error ? error.message : 'Unknown error'}`,
|
|
77
|
-
itemId,
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export async function install(
|
|
83
|
-
itemId: string,
|
|
84
|
-
target: Target | 'both' = 'both',
|
|
85
|
-
strategy: ConflictStrategy = 'skip'
|
|
86
|
-
): Promise<InstallResult> {
|
|
87
|
-
if (target === 'both') {
|
|
88
|
-
const claudeResult = await installToTarget('claude', itemId, strategy);
|
|
89
|
-
const codexResult = await installToTarget('codex', itemId, strategy);
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
success: claudeResult.success && codexResult.success,
|
|
93
|
-
message: `${claudeResult.message}\n${codexResult.message}`,
|
|
94
|
-
itemId,
|
|
95
|
-
};
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
return await installToTarget(target, itemId, strategy);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
export async function clearTarget(target?: Target | 'both'): Promise<void> {
|
|
102
|
-
const targets: Target[] = target === 'both' || !target ? ['claude', 'codex'] : [target];
|
|
103
|
-
|
|
104
|
-
for (const t of targets) {
|
|
105
|
-
const dir = getTargetDir(t);
|
|
106
|
-
try {
|
|
107
|
-
const files = await readdir(dir);
|
|
108
|
-
const jsonFiles = files.filter((f) => f.endsWith('.json')).map((f) => unlink(join(dir, f)));
|
|
109
|
-
await Promise.all(jsonFiles);
|
|
110
|
-
} catch (error) {
|
|
111
|
-
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
export async function listInstalled(target?: Target | 'both'): Promise<InstalledItem[]> {
|
|
117
|
-
const targets: Target[] = target === 'both' || !target ? ['claude', 'codex'] : [target];
|
|
118
|
-
const items: InstalledItem[] = [];
|
|
119
|
-
|
|
120
|
-
for (const t of targets) {
|
|
121
|
-
const dir = getTargetDir(t);
|
|
122
|
-
try {
|
|
123
|
-
const files = await readdir(dir);
|
|
124
|
-
for (const file of files.filter((f) => f.endsWith('.json'))) {
|
|
125
|
-
const content = await readFile(join(dir, file), 'utf-8');
|
|
126
|
-
const item = JSON.parse(content);
|
|
127
|
-
items.push({
|
|
128
|
-
id: item.id,
|
|
129
|
-
name: item.name,
|
|
130
|
-
target: t,
|
|
131
|
-
installedAt: file,
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
} catch (error) {
|
|
135
|
-
if ((error as NodeJS.ErrnoException).code !== 'ENOENT') throw error;
|
|
136
|
-
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
return items;
|
|
140
|
-
}
|
|
@@ -1,119 +0,0 @@
|
|
|
1
|
-
import { existsSync, mkdirSync, writeFileSync, appendFileSync } from "fs";
|
|
2
|
-
import { join } from "path";
|
|
3
|
-
import { homedir } from "os";
|
|
4
|
-
|
|
5
|
-
const SERVICE_NAME = "managemcp";
|
|
6
|
-
const SERVICE_DIR_NAME = `.${SERVICE_NAME}`;
|
|
7
|
-
|
|
8
|
-
export function getServiceDir(): string {
|
|
9
|
-
return join(homedir(), SERVICE_DIR_NAME);
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getLogFilePath(): string {
|
|
13
|
-
return join(getServiceDir(), `${SERVICE_NAME}.log`);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export function getReadmePath(): string {
|
|
17
|
-
return join(getServiceDir(), "README.md");
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export function isServiceDirInstalled(): boolean {
|
|
21
|
-
return existsSync(getServiceDir());
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
export function ensureServiceDir(): void {
|
|
25
|
-
if (!isServiceDirInstalled()) {
|
|
26
|
-
initServiceDir();
|
|
27
|
-
}
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function initServiceDir(force = false): { success: boolean; path: string; message: string } {
|
|
31
|
-
const serviceDir = getServiceDir();
|
|
32
|
-
|
|
33
|
-
if (existsSync(serviceDir) && !force) {
|
|
34
|
-
return {
|
|
35
|
-
success: false,
|
|
36
|
-
path: serviceDir,
|
|
37
|
-
message: "Already installed. Use --force to reinstall.",
|
|
38
|
-
};
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
mkdirSync(serviceDir, { recursive: true });
|
|
42
|
-
|
|
43
|
-
const readmeContent = generateReadme();
|
|
44
|
-
writeFileSync(getReadmePath(), readmeContent);
|
|
45
|
-
|
|
46
|
-
const logHeader = `# ${SERVICE_NAME} log file
|
|
47
|
-
# Created: ${new Date().toISOString()}
|
|
48
|
-
# This file contains activity history and logs.
|
|
49
|
-
# -------------------------------------------------------
|
|
50
|
-
|
|
51
|
-
`;
|
|
52
|
-
writeFileSync(getLogFilePath(), logHeader);
|
|
53
|
-
|
|
54
|
-
return {
|
|
55
|
-
success: true,
|
|
56
|
-
path: serviceDir,
|
|
57
|
-
message: `Installed at ${serviceDir}`,
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
function generateReadme(): string {
|
|
62
|
-
return `# .${SERVICE_NAME}
|
|
63
|
-
|
|
64
|
-
This directory contains local configuration and logs for \`${SERVICE_NAME}\`.
|
|
65
|
-
|
|
66
|
-
## Files
|
|
67
|
-
|
|
68
|
-
| Path | Description |
|
|
69
|
-
|------|-------------|
|
|
70
|
-
| \`${SERVICE_NAME}.log\` | Activity log |
|
|
71
|
-
| \`README.md\` | This file |
|
|
72
|
-
|
|
73
|
-
## What is ${SERVICE_NAME}?
|
|
74
|
-
|
|
75
|
-
\`${SERVICE_NAME}\` is a tool for managing MCP server connections.
|
|
76
|
-
|
|
77
|
-
## Log File
|
|
78
|
-
|
|
79
|
-
The \`${SERVICE_NAME}.log\` file contains:
|
|
80
|
-
- Activity logs
|
|
81
|
-
- Error logs
|
|
82
|
-
- API activity
|
|
83
|
-
|
|
84
|
-
## More Information
|
|
85
|
-
|
|
86
|
-
For full documentation, run:
|
|
87
|
-
|
|
88
|
-
\`\`\`bash
|
|
89
|
-
${SERVICE_NAME} --help
|
|
90
|
-
\`\`\`
|
|
91
|
-
`;
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
export type LogLevel = "debug" | "info" | "warn" | "error";
|
|
95
|
-
|
|
96
|
-
export function logToFile(message: string, level: LogLevel = "info"): void {
|
|
97
|
-
ensureServiceDir();
|
|
98
|
-
|
|
99
|
-
const timestamp = new Date().toISOString();
|
|
100
|
-
const logLine = `[${timestamp}] [${level.toUpperCase()}] ${message}\n`;
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
appendFileSync(getLogFilePath(), logLine);
|
|
104
|
-
} catch {
|
|
105
|
-
// Silently fail
|
|
106
|
-
}
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export function logInfo(message: string): void {
|
|
110
|
-
logToFile(message, "info");
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
export function logError(message: string): void {
|
|
114
|
-
logToFile(message, "error");
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
export function logWarn(message: string): void {
|
|
118
|
-
logToFile(message, "warn");
|
|
119
|
-
}
|
|
@@ -1,63 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Script to buy a Twilio phone number for an agent
|
|
4
|
-
* Usage: bun run scripts/buy-number.ts [agent_name] [area_code]
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import twilio from "twilio";
|
|
8
|
-
|
|
9
|
-
const CONFIG = {
|
|
10
|
-
accountSid: process.env.TWILIO_ACCOUNT_SID || "",
|
|
11
|
-
authToken: process.env.TWILIO_AUTH_TOKEN || "",
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const twilioClient = twilio(CONFIG.accountSid, CONFIG.authToken);
|
|
15
|
-
|
|
16
|
-
function capitalize(str: string): string {
|
|
17
|
-
return str.charAt(0).toUpperCase() + str.slice(1).toLowerCase();
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
async function buyPhoneNumber() {
|
|
21
|
-
const agentName = process.argv[2] || "claude";
|
|
22
|
-
const areaCode = process.argv[3] || "302"; // Default to Delaware
|
|
23
|
-
|
|
24
|
-
const friendlyName = `${capitalize(agentName)} (AI Agent)`;
|
|
25
|
-
|
|
26
|
-
console.log(`Searching for available numbers with area code ${areaCode}...`);
|
|
27
|
-
|
|
28
|
-
try {
|
|
29
|
-
// Search for available numbers
|
|
30
|
-
const availableNumbers = await twilioClient
|
|
31
|
-
.availablePhoneNumbers("US")
|
|
32
|
-
.local.list({ areaCode: parseInt(areaCode), limit: 5 });
|
|
33
|
-
|
|
34
|
-
if (availableNumbers.length === 0) {
|
|
35
|
-
console.error(`No available phone numbers found with area code ${areaCode}`);
|
|
36
|
-
process.exit(1);
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
console.log(`Found ${availableNumbers.length} available numbers:`);
|
|
40
|
-
availableNumbers.forEach((n, i) => {
|
|
41
|
-
console.log(` ${i + 1}. ${n.phoneNumber}`);
|
|
42
|
-
});
|
|
43
|
-
|
|
44
|
-
// Purchase the first available number
|
|
45
|
-
const phoneNumber = availableNumbers[0].phoneNumber;
|
|
46
|
-
console.log(`\nPurchasing ${phoneNumber} for ${friendlyName}...`);
|
|
47
|
-
|
|
48
|
-
const purchased = await twilioClient.incomingPhoneNumbers.create({
|
|
49
|
-
phoneNumber,
|
|
50
|
-
friendlyName,
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
console.log("\nPhone number purchased successfully!");
|
|
54
|
-
console.log(` SID: ${purchased.sid}`);
|
|
55
|
-
console.log(` Phone Number: ${purchased.phoneNumber}`);
|
|
56
|
-
console.log(` Friendly Name: ${purchased.friendlyName}`);
|
|
57
|
-
} catch (error: any) {
|
|
58
|
-
console.error("Failed to buy phone number:", error.message);
|
|
59
|
-
process.exit(1);
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
buyPhoneNumber();
|
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
/**
|
|
3
|
-
* Test script to send SMS via Twilio
|
|
4
|
-
* Usage: bun run scripts/test-send.ts [from_number] [to_number] [message]
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import twilio from "twilio";
|
|
8
|
-
|
|
9
|
-
const CONFIG = {
|
|
10
|
-
accountSid: process.env.TWILIO_ACCOUNT_SID || "",
|
|
11
|
-
authToken: process.env.TWILIO_AUTH_TOKEN || "",
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
const twilioClient = twilio(CONFIG.accountSid, CONFIG.authToken);
|
|
15
|
-
|
|
16
|
-
function formatPhoneNumber(phone: string): string {
|
|
17
|
-
const digits = phone.replace(/\D/g, "");
|
|
18
|
-
if (digits.length === 10) {
|
|
19
|
-
return `+1${digits}`;
|
|
20
|
-
}
|
|
21
|
-
if (digits.length === 11 && digits.startsWith("1")) {
|
|
22
|
-
return `+${digits}`;
|
|
23
|
-
}
|
|
24
|
-
if (!phone.startsWith("+")) {
|
|
25
|
-
return `+${digits}`;
|
|
26
|
-
}
|
|
27
|
-
return phone;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
async function sendTestSms() {
|
|
31
|
-
const fromNumber = process.argv[2];
|
|
32
|
-
const toNumber = process.argv[3];
|
|
33
|
-
const messageBody =
|
|
34
|
-
process.argv[4] ||
|
|
35
|
-
`Hello from the SMS agent!\n\nThis is a test SMS sent at ${new Date().toISOString()}.`;
|
|
36
|
-
|
|
37
|
-
if (!fromNumber || !toNumber) {
|
|
38
|
-
console.error("Usage: bun run scripts/test-send.ts <from_number> <to_number> [message]");
|
|
39
|
-
console.error("\nAvailable numbers:");
|
|
40
|
-
const numbers = await twilioClient.incomingPhoneNumbers.list();
|
|
41
|
-
numbers.forEach((n) => {
|
|
42
|
-
console.log(` ${n.phoneNumber} - ${n.friendlyName}`);
|
|
43
|
-
});
|
|
44
|
-
process.exit(1);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
console.log(`Sending test SMS from ${formatPhoneNumber(fromNumber)} to ${formatPhoneNumber(toNumber)}...`);
|
|
48
|
-
|
|
49
|
-
try {
|
|
50
|
-
const message = await twilioClient.messages.create({
|
|
51
|
-
body: messageBody,
|
|
52
|
-
from: formatPhoneNumber(fromNumber),
|
|
53
|
-
to: formatPhoneNumber(toNumber),
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
console.log("SMS sent successfully!");
|
|
57
|
-
console.log(` Message SID: ${message.sid}`);
|
|
58
|
-
console.log(` Status: ${message.status}`);
|
|
59
|
-
console.log(` From: ${message.from}`);
|
|
60
|
-
console.log(` To: ${message.to}`);
|
|
61
|
-
} catch (error: any) {
|
|
62
|
-
console.error("Failed to send SMS:", error.message);
|
|
63
|
-
process.exit(1);
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
sendTestSms();
|