@hasna/skills 0.1.32 → 0.1.34

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 (95) hide show
  1. package/README.md +1 -16
  2. package/bin/index.js +57 -14
  3. package/bin/mcp.js +57 -13
  4. package/dist/cli/commands/runtime.d.ts +1 -1
  5. package/dist/index.js +51 -5
  6. package/dist/lib/skill-validation.d.ts +2 -0
  7. package/package.json +1 -1
  8. package/skills/ad-creative-pack/package.json +4 -7
  9. package/skills/api-docs-portal/package.json +5 -3
  10. package/skills/audio/package.json +4 -22
  11. package/skills/audio-transcript-pack/package.json +3 -2
  12. package/skills/blog-article/package.json +5 -21
  13. package/skills/brand-kit/package.json +4 -7
  14. package/skills/brand-photo-shoot/package.json +3 -2
  15. package/skills/browse/README.md +13 -256
  16. package/skills/browse/SKILL.md +24 -45
  17. package/skills/browse/package.json +4 -33
  18. package/skills/contract-review-report/package.json +3 -2
  19. package/skills/customer-feedback-report/package.json +3 -2
  20. package/skills/deepresearch/CLAUDE.md +6 -39
  21. package/skills/deepresearch/README.md +15 -150
  22. package/skills/deepresearch/SKILL.md +23 -32
  23. package/skills/deepresearch/package.json +4 -37
  24. package/skills/domainpurchase/SKILL.md +14 -31
  25. package/skills/domainpurchase/package.json +3 -8
  26. package/skills/email-sequence/package.json +4 -7
  27. package/skills/generate-book-cover/package.json +5 -23
  28. package/skills/icon-pack/package.json +4 -22
  29. package/skills/image/README.md +13 -183
  30. package/skills/image/package.json +4 -22
  31. package/skills/invoice-reconciliation/package.json +3 -2
  32. package/skills/landing-page-pack/package.json +4 -7
  33. package/skills/logo-design/package.json +4 -2
  34. package/skills/managemcp/CLAUDE.md +9 -43
  35. package/skills/managemcp/README.md +12 -198
  36. package/skills/managemcp/package.json +2 -10
  37. package/skills/managemcp/tsconfig.json +1 -3
  38. package/skills/market-research-report/package.json +5 -4
  39. package/skills/meeting-pack/package.json +3 -2
  40. package/skills/migration-plan-pack/package.json +3 -2
  41. package/skills/music/package.json +4 -20
  42. package/skills/music-album/package.json +3 -2
  43. package/skills/one-page-website/package.json +3 -2
  44. package/skills/pdf-read/package.json +5 -23
  45. package/skills/pdf-to-dataset/package.json +5 -4
  46. package/skills/pdf-to-markdown/package.json +5 -4
  47. package/skills/performance-audit-report/package.json +3 -2
  48. package/skills/photo-album/package.json +4 -2
  49. package/skills/pitch-deck/package.json +5 -3
  50. package/skills/playlist-maker/package.json +4 -2
  51. package/skills/product-mockup/package.json +3 -2
  52. package/skills/proposal-pack/package.json +5 -4
  53. package/skills/read-pdf/package.json +4 -29
  54. package/skills/remove-background/package.json +5 -21
  55. package/skills/repo-onboarding-report/package.json +3 -2
  56. package/skills/sdk-generator/package.json +3 -2
  57. package/skills/security-audit-report/package.json +5 -4
  58. package/skills/seo-content-pack/package.json +5 -3
  59. package/skills/short-video-pack/package.json +3 -2
  60. package/skills/slide-deck-generator/package.json +3 -2
  61. package/skills/sms/README.md +18 -56
  62. package/skills/sms/package.json +1 -3
  63. package/skills/sms/tsconfig.json +1 -2
  64. package/skills/social-content-calendar/package.json +4 -7
  65. package/skills/test-suite-generator/package.json +5 -4
  66. package/skills/transcript/package.json +4 -23
  67. package/skills/video/package.json +4 -24
  68. package/skills/video-highlight-pack/package.json +3 -2
  69. package/skills/voiceover-jingle-pack/package.json +3 -2
  70. package/skills/webcrawling/CLAUDE.md +6 -17
  71. package/skills/webcrawling/README.md +13 -66
  72. package/skills/webcrawling/package.json +4 -32
  73. package/skills/browse/.env.example +0 -14
  74. package/skills/deepresearch/.env.example +0 -9
  75. package/skills/domainpurchase/.env.example +0 -7
  76. package/skills/domainpurchase/src/lib/api-client.ts +0 -571
  77. package/skills/domainpurchase/src/lib/config.ts +0 -209
  78. package/skills/domainpurchase/src/lib/installer.ts +0 -165
  79. package/skills/image/.env.example +0 -12
  80. package/skills/image/PROJECT_OVERVIEW.md +0 -216
  81. package/skills/image/QUICKSTART.md +0 -111
  82. package/skills/managemcp/.env.example +0 -16
  83. package/skills/managemcp/scripts/migrate.ts +0 -57
  84. package/skills/managemcp/scripts/seed.ts +0 -58
  85. package/skills/managemcp/src/db/index.ts +0 -37
  86. package/skills/managemcp/src/lib/api-client.ts +0 -108
  87. package/skills/managemcp/src/lib/config.ts +0 -34
  88. package/skills/managemcp/src/lib/installer.ts +0 -140
  89. package/skills/managemcp/src/lib/service-dir.ts +0 -119
  90. package/skills/sms/scripts/buy-number.ts +0 -63
  91. package/skills/sms/scripts/test-send.ts +0 -67
  92. package/skills/sms/src/server.ts +0 -351
  93. package/skills/sms/src/sse-server.ts +0 -279
  94. package/skills/transcript/.env.example +0 -10
  95. package/skills/webcrawling/.env.example +0 -2
@@ -1,16 +0,0 @@
1
- # Database (individual connection params)
2
- DB_HOST=localhost
3
- DB_PORT=5432
4
- DB_NAME=managemcp_db
5
- DB_USER=postgres
6
- DB_PASSWORD=your-password-here
7
-
8
- # Or use a full connection string
9
- # DATABASE_URL=postgres://user:password@host:port/dbname
10
-
11
- # Server
12
- PORT=3000
13
-
14
- # API (for CLI usage)
15
- API_URL=https://api.example.com
16
- API_KEY=your-api-key-here
@@ -1,57 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { sql, testConnection, closeConnection } from '../src/db';
4
-
5
- console.log('Running database migrations...');
6
-
7
- const connected = await testConnection();
8
- if (!connected) {
9
- console.error('Failed to connect to database');
10
- process.exit(1);
11
- }
12
-
13
- console.log('Database connected\n');
14
-
15
- try {
16
- console.log('Creating tables...');
17
- await sql`
18
- CREATE TABLE IF NOT EXISTS items (
19
- id SERIAL PRIMARY KEY,
20
- name VARCHAR(255) NOT NULL,
21
- description TEXT,
22
- metadata JSONB DEFAULT '{}',
23
- created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
24
- updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
25
- )
26
- `;
27
-
28
- console.log('Creating indexes...');
29
- await sql`CREATE INDEX IF NOT EXISTS idx_items_name ON items(name)`;
30
- await sql`CREATE INDEX IF NOT EXISTS idx_items_created_at ON items(created_at DESC)`;
31
-
32
- console.log('Creating triggers...');
33
- await sql`
34
- CREATE OR REPLACE FUNCTION update_updated_at_column()
35
- RETURNS TRIGGER AS $$
36
- BEGIN
37
- NEW.updated_at = CURRENT_TIMESTAMP;
38
- RETURN NEW;
39
- END;
40
- $$ language 'plpgsql'
41
- `;
42
-
43
- await sql`DROP TRIGGER IF EXISTS update_items_updated_at ON items`;
44
- await sql`
45
- CREATE TRIGGER update_items_updated_at
46
- BEFORE UPDATE ON items
47
- FOR EACH ROW
48
- EXECUTE FUNCTION update_updated_at_column()
49
- `;
50
-
51
- console.log('\nMigrations completed successfully');
52
- } catch (error) {
53
- console.error('\nMigration failed:', error);
54
- process.exit(1);
55
- } finally {
56
- await closeConnection();
57
- }
@@ -1,58 +0,0 @@
1
- #!/usr/bin/env bun
2
-
3
- import { sql, testConnection, closeConnection } from '../src/db';
4
-
5
- console.log('Seeding database...');
6
-
7
- const connected = await testConnection();
8
- if (!connected) {
9
- console.error('Failed to connect to database');
10
- process.exit(1);
11
- }
12
-
13
- console.log('Database connected\n');
14
-
15
- try {
16
- const [{ count }] = await sql`SELECT COUNT(*) as count FROM items`;
17
-
18
- if (parseInt(count) > 0) {
19
- console.log(`Database already has ${count} items - skipping seed`);
20
- console.log('To re-seed, truncate the items table first\n');
21
- process.exit(0);
22
- }
23
-
24
- console.log('Inserting seed data...');
25
-
26
- const seedItems = [
27
- {
28
- name: 'Example Item 1',
29
- description: 'This is the first example item',
30
- metadata: { category: 'example', priority: 'high' },
31
- },
32
- {
33
- name: 'Example Item 2',
34
- description: 'This is the second example item',
35
- metadata: { category: 'sample', priority: 'medium' },
36
- },
37
- {
38
- name: 'Example Item 3',
39
- description: 'This is the third example item',
40
- metadata: { category: 'demo', priority: 'low' },
41
- },
42
- ];
43
-
44
- for (const item of seedItems) {
45
- await sql`
46
- INSERT INTO items (name, description, metadata)
47
- VALUES (${item.name}, ${item.description}, ${JSON.stringify(item.metadata)})
48
- `;
49
- console.log(` Created: ${item.name}`);
50
- }
51
-
52
- console.log(`\nSeeded ${seedItems.length} items successfully`);
53
- } catch (error) {
54
- console.error('\nSeeding failed:', error);
55
- process.exit(1);
56
- } finally {
57
- await closeConnection();
58
- }
@@ -1,37 +0,0 @@
1
- import postgres from 'postgres';
2
-
3
- function getConnectionString(): string {
4
- if (process.env.DATABASE_URL) return process.env.DATABASE_URL;
5
-
6
- const {
7
- DB_USER = 'postgres',
8
- DB_PASSWORD = '',
9
- DB_HOST = 'localhost',
10
- DB_PORT = '5432',
11
- DB_NAME = 'managemcp_db',
12
- } = process.env;
13
-
14
- return `postgres://${DB_USER}:${DB_PASSWORD}@${DB_HOST}:${DB_PORT}/${DB_NAME}`;
15
- }
16
-
17
- export const sql = postgres(getConnectionString(), {
18
- max: 10,
19
- idle_timeout: 20,
20
- connect_timeout: 10,
21
- });
22
-
23
- export async function testConnection(): Promise<boolean> {
24
- try {
25
- await sql`SELECT 1`;
26
- return true;
27
- } catch (error) {
28
- console.error('Database connection failed:', error instanceof Error ? error.message : 'Unknown error');
29
- return false;
30
- }
31
- }
32
-
33
- export async function closeConnection(): Promise<void> {
34
- await sql.end({ timeout: 5 });
35
- }
36
-
37
- export type Sql = typeof sql;
@@ -1,108 +0,0 @@
1
- import { getApiKey, getApiUrl } from './config';
2
-
3
- export interface ApiItem {
4
- id: string;
5
- name: string;
6
- description?: string;
7
- metadata?: Record<string, unknown>;
8
- createdAt?: string;
9
- updatedAt?: string;
10
- }
11
-
12
- export interface ListOptions {
13
- filter?: string;
14
- limit?: number;
15
- offset?: number;
16
- }
17
-
18
- export interface CreateItemData {
19
- name: string;
20
- description?: string;
21
- metadata?: Record<string, unknown>;
22
- }
23
-
24
- export class ApiError extends Error {
25
- constructor(
26
- message: string,
27
- public statusCode?: number,
28
- public response?: unknown
29
- ) {
30
- super(message);
31
- this.name = 'ApiError';
32
- }
33
- }
34
-
35
- async function makeRequest<T>(
36
- endpoint: string,
37
- options: RequestInit = {}
38
- ): Promise<T> {
39
- const apiUrl = await getApiUrl();
40
- const apiKey = await getApiKey();
41
-
42
- if (!apiUrl) {
43
- throw new ApiError('API URL not configured. Run: managemcp config --set-api-url <url>');
44
- }
45
-
46
- if (!apiKey) {
47
- throw new ApiError('API key not configured. Run: managemcp config --set-api-key <key>');
48
- }
49
-
50
- const url = `${apiUrl}${endpoint}`;
51
- const headers = {
52
- 'Authorization': `Bearer ${apiKey}`,
53
- 'Content-Type': 'application/json',
54
- ...options.headers,
55
- };
56
-
57
- try {
58
- const response = await fetch(url, {
59
- ...options,
60
- headers,
61
- });
62
-
63
- if (!response.ok) {
64
- const errorData = await response.json().catch(() => null);
65
- const message = errorData?.error || response.statusText;
66
- throw new ApiError(`API request failed: ${message}`, response.status, errorData);
67
- }
68
-
69
- return await response.json();
70
- } catch (error) {
71
- if (error instanceof ApiError) throw error;
72
- throw new ApiError(`Network error: ${error instanceof Error ? error.message : 'Unknown error'}`);
73
- }
74
- }
75
-
76
- export async function listItems(options: ListOptions = {}): Promise<ApiItem[]> {
77
- const params = new URLSearchParams();
78
- if (options.filter) params.set('filter', options.filter);
79
- if (options.limit) params.set('limit', options.limit.toString());
80
- if (options.offset) params.set('offset', options.offset.toString());
81
-
82
- const query = params.toString();
83
- const endpoint = `/items${query ? `?${query}` : ''}`;
84
-
85
- const response = await makeRequest<{ items: ApiItem[] }>(endpoint);
86
- return response.items;
87
- }
88
-
89
- export async function getItem(id: string): Promise<ApiItem> {
90
- return await makeRequest<ApiItem>(`/items/${id}`);
91
- }
92
-
93
- export async function searchItems(query: string, limit = 10): Promise<ApiItem[]> {
94
- const params = new URLSearchParams({
95
- q: query,
96
- limit: limit.toString(),
97
- });
98
-
99
- const response = await makeRequest<{ items: ApiItem[] }>(`/items/search?${params}`);
100
- return response.items;
101
- }
102
-
103
- export async function createItem(data: CreateItemData): Promise<ApiItem> {
104
- return await makeRequest<ApiItem>('/items', {
105
- method: 'POST',
106
- body: JSON.stringify(data),
107
- });
108
- }
@@ -1,34 +0,0 @@
1
- import { readFile, writeFile } from 'fs/promises';
2
- import { join } from 'path';
3
- import { homedir } from 'os';
4
-
5
- export interface Config {
6
- apiUrl?: string;
7
- apiKey?: string;
8
- }
9
-
10
- export const CONFIG_FILE = join(homedir(), '.managemcp.json');
11
-
12
- export async function loadConfig(): Promise<Config> {
13
- try {
14
- const data = await readFile(CONFIG_FILE, 'utf-8');
15
- return JSON.parse(data);
16
- } catch (error) {
17
- if ((error as NodeJS.ErrnoException).code === 'ENOENT') return {};
18
- throw error;
19
- }
20
- }
21
-
22
- export async function saveConfig(config: Config): Promise<void> {
23
- await writeFile(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
24
- }
25
-
26
- export async function getApiKey(): Promise<string | undefined> {
27
- const config = await loadConfig();
28
- return config.apiKey || process.env.API_KEY;
29
- }
30
-
31
- export async function getApiUrl(): Promise<string | undefined> {
32
- const config = await loadConfig();
33
- return config.apiUrl || process.env.API_URL;
34
- }
@@ -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();