diff --git a/.github/workflows/prettier.yml b/.github/workflows/prettier.yml new file mode 100644 index 0000000..048256a --- /dev/null +++ b/.github/workflows/prettier.yml @@ -0,0 +1,31 @@ +name: Code Formatting Check + +on: + pull_request: + branches: [main] + push: + branches: [main] + +jobs: + format-check: + name: Prettier Check + runs-on: ubuntu-latest + defaults: + run: + working-directory: auto-kol/agent + + steps: + - uses: actions/checkout@v4 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: '20' + cache: 'yarn' + cache-dependency-path: 'auto-kol/agent/yarn.lock' + + - name: Install Dependencies + run: yarn install --frozen-lockfile + + - name: Check Formatting + run: yarn prettier --check "src/**/*.ts" diff --git a/auto-kol/agent/.prettierrc.js b/auto-kol/agent/.prettierrc.js new file mode 100644 index 0000000..2d0b13e --- /dev/null +++ b/auto-kol/agent/.prettierrc.js @@ -0,0 +1,8 @@ +export default { + semi: true, + trailingComma: 'all', + singleQuote: true, + printWidth: 100, + tabWidth: 2, + arrowParens: 'avoid', +}; \ No newline at end of file diff --git a/auto-kol/agent/package.json b/auto-kol/agent/package.json index 3c37486..b7a0e0c 100644 --- a/auto-kol/agent/package.json +++ b/auto-kol/agent/package.json @@ -7,7 +7,9 @@ "scripts": { "build": "tsc", "start": "node dist/index.js", - "dev": "tsx watch src/index.ts" + "dev": "tsx watch src/index.ts", + "format": "prettier --write \"src/**/*.ts\"", + "format:check": "prettier --check \"src/**/*.ts\"" }, "dependencies": { "@autonomys/auto-dag-data": "^1.0.12", @@ -37,7 +39,8 @@ "@types/express": "4.17.21", "@types/node": "22.10.0", "@types/sqlite3": "^3.1.11", - "@types/uuid": "10.0.0", + "@types/uuid": "10.0.0", + "prettier": "^3.2.2", "tsx": "^4.7.1", "typescript": "^5.3.3" } diff --git a/auto-kol/agent/src/abi/memory.ts b/auto-kol/agent/src/abi/memory.ts index e0f77e0..4dac720 100644 --- a/auto-kol/agent/src/abi/memory.ts +++ b/auto-kol/agent/src/abi/memory.ts @@ -1,72 +1,72 @@ export const MEMORY_ABI = [ - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "agent", - "type": "address" - }, - { - "indexed": false, - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - } - ], - "name": "LastMemoryHashSet", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "_agent", - "type": "address" - } - ], - "name": "getLastMemoryHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "name": "lastMemoryHash", - "outputs": [ - { - "internalType": "bytes32", - "name": "", - "type": "bytes32" - } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "bytes32", - "name": "hash", - "type": "bytes32" - } - ], - "name": "setLastMemoryHash", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] as const \ No newline at end of file + { + anonymous: false, + inputs: [ + { + indexed: true, + internalType: 'address', + name: 'agent', + type: 'address', + }, + { + indexed: false, + internalType: 'bytes32', + name: 'hash', + type: 'bytes32', + }, + ], + name: 'LastMemoryHashSet', + type: 'event', + }, + { + inputs: [ + { + internalType: 'address', + name: '_agent', + type: 'address', + }, + ], + name: 'getLastMemoryHash', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'address', + name: '', + type: 'address', + }, + ], + name: 'lastMemoryHash', + outputs: [ + { + internalType: 'bytes32', + name: '', + type: 'bytes32', + }, + ], + stateMutability: 'view', + type: 'function', + }, + { + inputs: [ + { + internalType: 'bytes32', + name: 'hash', + type: 'bytes32', + }, + ], + name: 'setLastMemoryHash', + outputs: [], + stateMutability: 'nonpayable', + type: 'function', + }, +] as const; diff --git a/auto-kol/agent/src/api/index.ts b/auto-kol/agent/src/api/index.ts index 44184cc..e28c2c6 100644 --- a/auto-kol/agent/src/api/index.ts +++ b/auto-kol/agent/src/api/index.ts @@ -11,4 +11,4 @@ router.use('/', responseRoutes); router.use('/', tweetRoutes); router.use('/', dsnRoutes); -export default router; \ No newline at end of file +export default router; diff --git a/auto-kol/agent/src/api/middleware/cors.ts b/auto-kol/agent/src/api/middleware/cors.ts index 65ddf37..60b14f0 100644 --- a/auto-kol/agent/src/api/middleware/cors.ts +++ b/auto-kol/agent/src/api/middleware/cors.ts @@ -4,19 +4,19 @@ import { config } from '../../config/index.js'; const allowedOrigins = config.CORS_ORIGINS?.split(',') || ['http://localhost:3000']; export const corsMiddleware = cors({ - origin: (origin, callback) => { - if (!origin) { - return callback(null, true); - } + origin: (origin, callback) => { + if (!origin) { + return callback(null, true); + } - if (allowedOrigins.indexOf(origin) !== -1 || config.NODE_ENV === 'development') { - callback(null, true); - } else { - callback(new Error('Not allowed by CORS')); - } - }, - credentials: true, - methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], - allowedHeaders: ['Content-Type', 'Authorization'], - maxAge: 86400 // 24 hours -}); \ No newline at end of file + if (allowedOrigins.indexOf(origin) !== -1 || config.NODE_ENV === 'development') { + callback(null, true); + } else { + callback(new Error('Not allowed by CORS')); + } + }, + credentials: true, + methods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'], + allowedHeaders: ['Content-Type', 'Authorization'], + maxAge: 86400, // 24 hours +}); diff --git a/auto-kol/agent/src/api/routes/dsn.ts b/auto-kol/agent/src/api/routes/dsn.ts index bde1161..5df8a08 100644 --- a/auto-kol/agent/src/api/routes/dsn.ts +++ b/auto-kol/agent/src/api/routes/dsn.ts @@ -8,55 +8,56 @@ const router = Router(); const logger = createLogger('dsn-api'); router.get('/memories', async (req, res) => { - try { - const page = parseInt(req.query.page as string) || 1; - const limit = parseInt(req.query.limit as string) || 10; - - if (page < 1 || limit < 1 || limit > 100) { - return res.status(400).json({ - error: 'Invalid pagination parameters. Page must be >= 1 and limit must be between 1 and 100' - }); - } - - const dsnRecords = await getAllDsn(page, limit); - res.json(dsnRecords); - } catch (error) { - logger.error('Error fetching DSN records:', error); - res.status(500).json({ error: 'Failed to fetch DSN records' }); + try { + const page = parseInt(req.query.page as string) || 1; + const limit = parseInt(req.query.limit as string) || 10; + + if (page < 1 || limit < 1 || limit > 100) { + return res.status(400).json({ + error: + 'Invalid pagination parameters. Page must be >= 1 and limit must be between 1 and 100', + }); } + + const dsnRecords = await getAllDsn(page, limit); + res.json(dsnRecords); + } catch (error) { + logger.error('Error fetching DSN records:', error); + res.status(500).json({ error: 'Failed to fetch DSN records' }); + } }); router.get('/memories/:cid', async (req, res) => { - try { - const api = createAutoDriveApi({ - apiKey: config.DSN_API_KEY || '' - }); - - const stream = await downloadObject(api, { cid: req.params.cid }); - const reader = stream.getReader(); - const chunks: Uint8Array[] = []; - - while (true) { - const { done, value } = await reader.read(); - if (done) break; - chunks.push(value); - } - - const allChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); - let position = 0; - for (const chunk of chunks) { - allChunks.set(chunk, position); - position += chunk.length; - } - - const decompressed = inflate(allChunks); - const jsonString = new TextDecoder().decode(decompressed); - const memoryData = JSON.parse(jsonString); - res.json(memoryData); - } catch (error) { - logger.error('Error fetching memory data:', error); - res.status(500).json({ error: 'Failed to fetch memory data' }); + try { + const api = createAutoDriveApi({ + apiKey: config.DSN_API_KEY || '', + }); + + const stream = await downloadObject(api, { cid: req.params.cid }); + const reader = stream.getReader(); + const chunks: Uint8Array[] = []; + + while (true) { + const { done, value } = await reader.read(); + if (done) break; + chunks.push(value); } + + const allChunks = new Uint8Array(chunks.reduce((acc, chunk) => acc + chunk.length, 0)); + let position = 0; + for (const chunk of chunks) { + allChunks.set(chunk, position); + position += chunk.length; + } + + const decompressed = inflate(allChunks); + const jsonString = new TextDecoder().decode(decompressed); + const memoryData = JSON.parse(jsonString); + res.json(memoryData); + } catch (error) { + logger.error('Error fetching memory data:', error); + res.status(500).json({ error: 'Failed to fetch memory data' }); + } }); -export default router; \ No newline at end of file +export default router; diff --git a/auto-kol/agent/src/api/routes/health.ts b/auto-kol/agent/src/api/routes/health.ts index 5b74bf4..d99c8cb 100644 --- a/auto-kol/agent/src/api/routes/health.ts +++ b/auto-kol/agent/src/api/routes/health.ts @@ -3,7 +3,7 @@ import { Router } from 'express'; const router = Router(); router.get('/health', (_, res) => { - res.json({ status: 'ok' }); + res.json({ status: 'ok' }); }); -export default router; \ No newline at end of file +export default router; diff --git a/auto-kol/agent/src/api/routes/responses.ts b/auto-kol/agent/src/api/routes/responses.ts index d65d7b5..fbf0155 100644 --- a/auto-kol/agent/src/api/routes/responses.ts +++ b/auto-kol/agent/src/api/routes/responses.ts @@ -6,18 +6,17 @@ const router = Router(); const logger = createLogger('responses-api'); router.get('/responses/:id/workflow', async (req, res) => { - try { - const responses = await getAllPendingResponses(); - const response = responses.find(r => r.id === req.params.id); - if (!response) { - return res.status(404).json({ error: 'Response not found' }); - } - res.json(response.workflowState); - } catch (error) { - logger.error('Error getting workflow state:', error); - res.status(500).json({ error: 'Failed to get workflow state' }); + try { + const responses = await getAllPendingResponses(); + const response = responses.find(r => r.id === req.params.id); + if (!response) { + return res.status(404).json({ error: 'Response not found' }); } + res.json(response.workflowState); + } catch (error) { + logger.error('Error getting workflow state:', error); + res.status(500).json({ error: 'Failed to get workflow state' }); + } }); - -export default router; \ No newline at end of file +export default router; diff --git a/auto-kol/agent/src/api/routes/tweets.ts b/auto-kol/agent/src/api/routes/tweets.ts index d68fcfc..7bae996 100644 --- a/auto-kol/agent/src/api/routes/tweets.ts +++ b/auto-kol/agent/src/api/routes/tweets.ts @@ -1,44 +1,43 @@ import { Router } from 'express'; import { createLogger } from '../../utils/logger.js'; import { getSkippedTweets, getSkippedTweetById } from '../../services/database/index.js'; -import { recheckSkippedTweet } from '../../database/index.js' +import { recheckSkippedTweet } from '../../database/index.js'; const router = Router(); const logger = createLogger('tweets-api'); - router.get('/tweets/skipped', async (_, res) => { - const skippedTweets = await getSkippedTweets(); - res.json(skippedTweets); + const skippedTweets = await getSkippedTweets(); + res.json(skippedTweets); }); router.get('/tweets/skipped/:id', async (req, res) => { - const skipped = await getSkippedTweetById(req.params.id); - if (!skipped) { - return res.status(404).json({ error: 'Skipped tweet not found' }); - } - res.json(skipped); + const skipped = await getSkippedTweetById(req.params.id); + if (!skipped) { + return res.status(404).json({ error: 'Skipped tweet not found' }); + } + res.json(skipped); }); router.post('/tweets/skipped/:id/queue', async (req, res) => { - try { - logger.info(`Received request to move skipped tweet to queue: ${req.params.id}`); - const skipped = await getSkippedTweetById(req.params.id); - if (!skipped) { - return res.status(404).json({ error: 'Skipped tweet not found' }); - } - const recheck = await recheckSkippedTweet(req.params.id); - if (!recheck) { - return res.status(404).json({ error: 'Failed to recheck skipped tweet' }); - } - res.json({ - message: 'Skipped tweet rechecked and moved to queue - if will be processed in next workflow run' - }); - } catch (error) { - logger.error('Error moving skipped tweet to queue:', error); - res.status(500).json({ error: 'Failed to move tweet to queue' }); + try { + logger.info(`Received request to move skipped tweet to queue: ${req.params.id}`); + const skipped = await getSkippedTweetById(req.params.id); + if (!skipped) { + return res.status(404).json({ error: 'Skipped tweet not found' }); } + const recheck = await recheckSkippedTweet(req.params.id); + if (!recheck) { + return res.status(404).json({ error: 'Failed to recheck skipped tweet' }); + } + res.json({ + message: + 'Skipped tweet rechecked and moved to queue - if will be processed in next workflow run', + }); + } catch (error) { + logger.error('Error moving skipped tweet to queue:', error); + res.status(500).json({ error: 'Failed to move tweet to queue' }); + } }); - -export default router; \ No newline at end of file +export default router; diff --git a/auto-kol/agent/src/config/index.ts b/auto-kol/agent/src/config/index.ts index dd8b30d..d2c6ace 100644 --- a/auto-kol/agent/src/config/index.ts +++ b/auto-kol/agent/src/config/index.ts @@ -10,53 +10,53 @@ const __dirname = dirname(__filename); dotenv.config(); export const config = { - // Twitter API Configuration - TWITTER_USERNAME: process.env.TWITTER_USERNAME, - TWITTER_PASSWORD: process.env.TWITTER_PASSWORD, - - // LLM Configuration - LLM_MODEL: process.env.LLM_MODEL || "gpt-4o-mini", - OPENAI_API_KEY: process.env.OPENAI_API_KEY, - TEMPERATURE: 0.7, - - // Agent Configuration - CHECK_INTERVAL: (Number(process.env.CHECK_INTERVAL_MINUTES) || 30) * 60 * 1000, - MEMORY_DIR: path.join(__dirname, '../../data/memory'), - - // Server Configuration - PORT: process.env.PORT || 3001, - - // Environment - NODE_ENV: process.env.NODE_ENV || 'development', - - // Chroma Configuration - CHROMA_DIR: path.join(__dirname, '../../data/chroma'), - CHROMA_URL: process.env.CHROMA_URL || 'http://localhost:8000', - - // AutoDrive Configuration - DSN_API_KEY: process.env.DSN_API_KEY, - DSN_UPLOAD: process.env.DSN_UPLOAD === 'true', - DSN_SKIP_UPLOAD: process.env.DSN_SKIP_UPLOAD === 'true', - DSN_ENCRYPTION_PASSWORD: process.env.DSN_ENCRYPTION_PASSWORD, - - // CORS Configuration - CORS_ORIGINS: process.env.CORS_ORIGINS, - - // SC Configuration - RPC_URL: process.env.RPC_URL, - CONTRACT_ADDRESS: process.env.CONTRACT_ADDRESS, - PRIVATE_KEY: process.env.PRIVATE_KEY, - WALLET_ADDRESS: process.env.WALLET_ADDRESS, - - // Tweet Search/Fetch Configuration - ACCOUNTS_PER_BATCH: Number(process.env.ACCOUNTS_PER_BATCH) || 10, - MAX_SEARCH_TWEETS: Number(process.env.MAX_SEARCH_TWEETS) || 20, - // BATCH CONFIG - ENGAGEMENT_BATCH_SIZE: process.env.ENGAGEMENT_BATCH_SIZE || 15, - - // RESPONSE CONFIG - RETRY_LIMIT: process.env.RETRY_LIMIT || 2, - - // POSTING TWEETS PERMISSION - POST_TWEETS: process.env.POST_TWEETS === 'true', -}; + // Twitter API Configuration + TWITTER_USERNAME: process.env.TWITTER_USERNAME, + TWITTER_PASSWORD: process.env.TWITTER_PASSWORD, + + // LLM Configuration + LLM_MODEL: process.env.LLM_MODEL || 'gpt-4o-mini', + OPENAI_API_KEY: process.env.OPENAI_API_KEY, + TEMPERATURE: 0.7, + + // Agent Configuration + CHECK_INTERVAL: (Number(process.env.CHECK_INTERVAL_MINUTES) || 30) * 60 * 1000, + MEMORY_DIR: path.join(__dirname, '../../data/memory'), + + // Server Configuration + PORT: process.env.PORT || 3001, + + // Environment + NODE_ENV: process.env.NODE_ENV || 'development', + + // Chroma Configuration + CHROMA_DIR: path.join(__dirname, '../../data/chroma'), + CHROMA_URL: process.env.CHROMA_URL || 'http://localhost:8000', + + // AutoDrive Configuration + DSN_API_KEY: process.env.DSN_API_KEY, + DSN_UPLOAD: process.env.DSN_UPLOAD === 'true', + DSN_SKIP_UPLOAD: process.env.DSN_SKIP_UPLOAD === 'true', + DSN_ENCRYPTION_PASSWORD: process.env.DSN_ENCRYPTION_PASSWORD, + + // CORS Configuration + CORS_ORIGINS: process.env.CORS_ORIGINS, + + // SC Configuration + RPC_URL: process.env.RPC_URL, + CONTRACT_ADDRESS: process.env.CONTRACT_ADDRESS, + PRIVATE_KEY: process.env.PRIVATE_KEY, + WALLET_ADDRESS: process.env.WALLET_ADDRESS, + + // Tweet Search/Fetch Configuration + ACCOUNTS_PER_BATCH: Number(process.env.ACCOUNTS_PER_BATCH) || 10, + MAX_SEARCH_TWEETS: Number(process.env.MAX_SEARCH_TWEETS) || 20, + // BATCH CONFIG + ENGAGEMENT_BATCH_SIZE: process.env.ENGAGEMENT_BATCH_SIZE || 15, + + // RESPONSE CONFIG + RETRY_LIMIT: process.env.RETRY_LIMIT || 2, + + // POSTING TWEETS PERMISSION + POST_TWEETS: process.env.POST_TWEETS === 'true', +}; diff --git a/auto-kol/agent/src/database/index.ts b/auto-kol/agent/src/database/index.ts index d305686..4ca0746 100644 --- a/auto-kol/agent/src/database/index.ts +++ b/auto-kol/agent/src/database/index.ts @@ -11,49 +11,47 @@ import { SkippedTweet, PendingResponse } from '../types/queue.js'; const logger = createLogger('database'); - let db: Awaited> | null = null; - ///////////DATABASE/////////// export async function initializeDatabase() { - if (!db) { - try { - const dbDir = path.dirname('./data/engagement.db'); - await fs.mkdir(dbDir, { recursive: true }); - - db = await open({ - filename: './data/engagement.db', - driver: sqlite3.Database - }); - - await db.run('PRAGMA foreign_keys = ON'); - - // Test database connection - await db.get('SELECT 1'); - } catch (error) { - db = null; - throw new Error(`Failed to initialize database: ${error}`); - } + if (!db) { + try { + const dbDir = path.dirname('./data/engagement.db'); + await fs.mkdir(dbDir, { recursive: true }); + + db = await open({ + filename: './data/engagement.db', + driver: sqlite3.Database, + }); + + await db.run('PRAGMA foreign_keys = ON'); + + // Test database connection + await db.get('SELECT 1'); + } catch (error) { + db = null; + throw new Error(`Failed to initialize database: ${error}`); } - return db; + } + return db; } export async function closeDatabase() { - if (db) { - await db.close(); - db = null; - } + if (db) { + await db.close(); + db = null; + } } export async function initializeSchema() { - const db = await initializeDatabase(); - - try { - await db.run('BEGIN TRANSACTION'); + const db = await initializeDatabase(); + + try { + await db.run('BEGIN TRANSACTION'); - // Check if tables exist first - const tables = await db.all(` + // Check if tables exist first + const tables = await db.all(` SELECT name FROM sqlite_master WHERE type='table' AND name IN ( @@ -65,117 +63,121 @@ export async function initializeSchema() { ) `); - const existingTables = new Set(tables.map(t => t.name)); + const existingTables = new Set(tables.map(t => t.name)); - const __filename = fileURLToPath(import.meta.url); - const __dirname = dirname(__filename); - const schemaPath = join(__dirname, 'schema.sql'); - const schema = await fs.readFile(schemaPath, 'utf-8'); + const __filename = fileURLToPath(import.meta.url); + const __dirname = dirname(__filename); + const schemaPath = join(__dirname, 'schema.sql'); + const schema = await fs.readFile(schemaPath, 'utf-8'); - const statements = schema - .split(';') - .map(s => s.trim()) - .filter(s => s.length > 0); + const statements = schema + .split(';') + .map(s => s.trim()) + .filter(s => s.length > 0); - for (const statement of statements) { - const tableName = statement.match(/CREATE TABLE (?:IF NOT EXISTS )?([^\s(]+)/i)?.[1]; - if (tableName && !existingTables.has(tableName)) { - await db.run(statement); - logger.info(`Created table: ${tableName}`); - } - } - - await db.run('COMMIT'); - logger.info('Schema initialization completed successfully'); - } catch (error) { - await db.run('ROLLBACK'); - logger.error('Failed to initialize schema:', error); - throw new Error(`Failed to initialize schema: ${error}`); + for (const statement of statements) { + const tableName = statement.match(/CREATE TABLE (?:IF NOT EXISTS )?([^\s(]+)/i)?.[1]; + if (tableName && !existingTables.has(tableName)) { + await db.run(statement); + logger.info(`Created table: ${tableName}`); + } } -} - + await db.run('COMMIT'); + logger.info('Schema initialization completed successfully'); + } catch (error) { + await db.run('ROLLBACK'); + logger.error('Failed to initialize schema:', error); + throw new Error(`Failed to initialize schema: ${error}`); + } +} ///////////KOL/////////// export async function addKOL(kol: { - id: string; - username: string; - created_at?: Date; + id: string; + username: string; + created_at?: Date; }): Promise { - const db = await initializeDatabase(); - - try { - await db.run(` + const db = await initializeDatabase(); + + try { + await db.run( + ` INSERT INTO kol_accounts ( id, username, created_at, updated_at ) VALUES (?, ?, ?, CURRENT_TIMESTAMP) - `, [kol.id, kol.username, kol.created_at || new Date()]); - - logger.info(`Added KOL account: ${kol.username}`); - } catch (error: any) { - if (error?.code === 'SQLITE_CONSTRAINT' && error?.message?.includes('UNIQUE')) { - logger.warn(`KOL account already exists: ${kol.username}`); - return; - } - logger.error(`Failed to add KOL account: ${kol.username}`, error); - throw new Error(`Failed to add KOL account: ${error.message}`); + `, + [kol.id, kol.username, kol.created_at || new Date()], + ); + + logger.info(`Added KOL account: ${kol.username}`); + } catch (error: any) { + if (error?.code === 'SQLITE_CONSTRAINT' && error?.message?.includes('UNIQUE')) { + logger.warn(`KOL account already exists: ${kol.username}`); + return; } + logger.error(`Failed to add KOL account: ${kol.username}`, error); + throw new Error(`Failed to add KOL account: ${error.message}`); + } } export async function getKOLAccounts(): Promise { - const db = await initializeDatabase(); - try { - const accounts = await db.all(` + const db = await initializeDatabase(); + try { + const accounts = await db.all(` SELECT id, username, created_at, updated_at FROM kol_accounts ORDER BY created_at DESC `); - - return accounts.map(account => ({ - id: account.id, - username: account.username, - created_at: new Date(account.created_at), - updatedAt: new Date(account.updated_at) - })); - } catch (error) { - logger.error('Failed to get KOL accounts:', error); - throw error; - } + + return accounts.map(account => ({ + id: account.id, + username: account.username, + created_at: new Date(account.created_at), + updatedAt: new Date(account.updated_at), + })); + } catch (error) { + logger.error('Failed to get KOL accounts:', error); + throw error; + } } export async function isKOLExists(username: string): Promise { - const db = await initializeDatabase(); - const kol = await db.get(`SELECT * FROM kol_accounts WHERE username = ?`, [username]); - return kol !== undefined; + const db = await initializeDatabase(); + const kol = await db.get(`SELECT * FROM kol_accounts WHERE username = ?`, [username]); + return kol !== undefined; } ///////////RESPONSE/////////// export async function addResponse(response: PendingResponse) { - const db = await initializeDatabase(); - return db.run(` + const db = await initializeDatabase(); + return db.run( + ` INSERT INTO responses ( id, tweet_id, content, tone, strategy, estimated_impact, confidence, status ) VALUES (?, ?, ?, ?, ?, ?, ?, ?) - `, [ - response.id, - response.tweet_id, - response.content, - response.tone, - response.strategy, - response.estimatedImpact, - response.confidence, - 'pending' - ]); + `, + [ + response.id, + response.tweet_id, + response.content, + response.tone, + response.strategy, + response.estimatedImpact, + response.confidence, + 'pending', + ], + ); } - export async function updateResponse(response: PendingResponse) { - const db = await initializeDatabase(); - return db.run(` + const db = await initializeDatabase(); + return db.run( + ` UPDATE responses SET content = ?, @@ -185,19 +187,21 @@ export async function updateResponse(response: PendingResponse) { confidence = ?, updated_at = CURRENT_TIMESTAMP WHERE ${response.id ? 'id = ?' : 'tweet_id = ?'} - `, [ - response.content, - response.tone, - response.strategy, - response.estimatedImpact, - response.confidence, - response.id || response.tweet_id - ]); + `, + [ + response.content, + response.tone, + response.strategy, + response.estimatedImpact, + response.confidence, + response.id || response.tweet_id, + ], + ); } export async function getPendingResponses() { - const db = await initializeDatabase(); - return db.all(` + const db = await initializeDatabase(); + return db.all(` SELECT pr.*, t.author_username, @@ -212,104 +216,109 @@ export async function getPendingResponses() { } export async function getResponseByTweetId(tweet_id: string): Promise { - const db = await initializeDatabase(); - const response = await db.all(` + const db = await initializeDatabase(); + const response = await db.all( + ` SELECT * FROM responses WHERE tweet_id = ? - `, [tweet_id]); - return response[0] as PendingResponse; + `, + [tweet_id], + ); + return response[0] as PendingResponse; } export async function getPendingResponsesByTweetId(id: string): Promise { - const db = await initializeDatabase(); - const pending_response = await db.all(` + const db = await initializeDatabase(); + const pending_response = await db.all( + ` SELECT * FROM responses WHERE id = ? AND status = 'pending' - `, [id]); - return pending_response[0] as PendingResponse; + `, + [id], + ); + return pending_response[0] as PendingResponse; } -export async function updateResponseStatus( - id: string, - status: 'approved' | 'rejected', -) { - const db = await initializeDatabase(); - - await db.run('BEGIN TRANSACTION'); - - try { - await db.run(` +export async function updateResponseStatus(id: string, status: 'approved' | 'rejected') { + const db = await initializeDatabase(); + + await db.run('BEGIN TRANSACTION'); + + try { + await db.run( + ` UPDATE responses SET status = ?, updated_at = CURRENT_TIMESTAMP WHERE id = ? - `, [status, id]); - await db.run('COMMIT'); - logger.info(`Updated response status: ${id}`); - } catch (error) { - await db.run('ROLLBACK'); - throw error; - } + `, + [status, id], + ); + await db.run('COMMIT'); + logger.info(`Updated response status: ${id}`); + } catch (error) { + await db.run('ROLLBACK'); + throw error; + } } -export async function updateResponseStatusByTweetId(tweet_id: string, status: 'approved' | 'rejected') { - const db = await initializeDatabase(); - return db.run(` +export async function updateResponseStatusByTweetId( + tweet_id: string, + status: 'approved' | 'rejected', +) { + const db = await initializeDatabase(); + return db.run( + ` UPDATE responses SET status = ? WHERE tweet_id = ? - `, [status, tweet_id]); + `, + [status, tweet_id], + ); } - ///////////TWEET/////////// export async function addTweet(tweet: { - id: string; - author_id: string; - author_username: string; - content: string; - created_at: string; + id: string; + author_id: string; + author_username: string; + content: string; + created_at: string; }) { - const db = await initializeDatabase(); - return db.run(` + const db = await initializeDatabase(); + return db.run( + ` INSERT INTO tweets ( id, author_id, author_username, content, created_at ) VALUES (?, ?, ?, ?, ?) - `, [ - tweet.id, - tweet.author_id, - tweet.author_username, - tweet.content, - tweet.created_at, - ]); + `, + [tweet.id, tweet.author_id, tweet.author_username, tweet.content, tweet.created_at], + ); } export async function getTweetById(tweetId: string): Promise { - const db = await initializeDatabase(); - const tweet = await db.get(`SELECT * FROM tweets WHERE id = ?`, [tweetId]); - return tweet as Tweet; + const db = await initializeDatabase(); + const tweet = await db.get(`SELECT * FROM tweets WHERE id = ?`, [tweetId]); + return tweet as Tweet; } - ///////////SKIPPED TWEET/////////// export async function addSkippedTweet(skipped: { - id: string; - tweetId: string; - reason: string; - confidence: number; + id: string; + tweetId: string; + reason: string; + confidence: number; }) { - const db = await initializeDatabase(); - return db.run(` + const db = await initializeDatabase(); + return db.run( + ` INSERT INTO skipped_tweets ( id, tweet_id, reason, confidence ) VALUES (?, ?, ?, ?) - `, [ - skipped.id, - skipped.tweetId, - skipped.reason, - skipped.confidence - ]); + `, + [skipped.id, skipped.tweetId, skipped.reason, skipped.confidence], + ); } export async function getSkippedTweets() { - const db = await initializeDatabase(); - return db.all(` + const db = await initializeDatabase(); + return db.all(` SELECT st.*, t.author_username, @@ -321,44 +330,47 @@ export async function getSkippedTweets() { } export async function getSkippedTweetById(skippedId: string): Promise { - const db = await initializeDatabase(); - const skipped = await db.get(`SELECT * FROM skipped_tweets WHERE id = ?`, [skippedId]); - return skipped; + const db = await initializeDatabase(); + const skipped = await db.get(`SELECT * FROM skipped_tweets WHERE id = ?`, [skippedId]); + return skipped; } export async function recheckSkippedTweet(skippedId: string): Promise { - const db = await initializeDatabase(); - const result = await db.run(`UPDATE skipped_tweets SET recheck = TRUE WHERE id = ?`, [skippedId]); - return result !== undefined; + const db = await initializeDatabase(); + const result = await db.run(`UPDATE skipped_tweets SET recheck = TRUE WHERE id = ?`, [skippedId]); + return result !== undefined; } export async function flagBackSkippedTweet(skippedId: string, reason: string): Promise { - const db = await initializeDatabase(); - const result = await db.run(`UPDATE skipped_tweets SET recheck = FALSE, reason = ? WHERE id = ?`, [reason, skippedId]); - return result !== undefined; + const db = await initializeDatabase(); + const result = await db.run( + `UPDATE skipped_tweets SET recheck = FALSE, reason = ? WHERE id = ?`, + [reason, skippedId], + ); + return result !== undefined; } export async function getAllSkippedTweetsToRecheck(): Promise { - const db = await initializeDatabase(); - const recheckTweets = await db.all(`SELECT * FROM skipped_tweets WHERE recheck = TRUE`); - return recheckTweets; + const db = await initializeDatabase(); + const recheckTweets = await db.all(`SELECT * FROM skipped_tweets WHERE recheck = TRUE`); + return recheckTweets; } ///////////DSN/////////// -export async function addDsn(dsn: { - id: string; - tweetId: string; - cid: string; -}) { - return db?.run(` +export async function addDsn(dsn: { id: string; tweetId: string; cid: string }) { + return db?.run( + ` INSERT INTO dsn (id, tweet_id, cid) VALUES (?, ?, ?) - `, [dsn.id, dsn.tweetId, dsn.cid]); + `, + [dsn.id, dsn.tweetId, dsn.cid], + ); } export async function getDsnByCID(cid: string) { - try { - return await db?.get(` + try { + return await db?.get( + ` SELECT dsn.id, dsn.tweet_id, @@ -379,22 +391,25 @@ export async function getDsnByCID(cid: string) { LEFT JOIN responses r ON t.id = r.tweet_id LEFT JOIN skipped_tweets st ON t.id = st.tweet_id WHERE dsn.cid = ? - `, [cid]); - } catch (error) { - logger.error(`Failed to get DSN by CID: ${cid}`, error); - throw error; - } + `, + [cid], + ); + } catch (error) { + logger.error(`Failed to get DSN by CID: ${cid}`, error); + throw error; + } } export async function getAllDsn(page: number = 1, limit: number = 10) { - try { - const offset = (page - 1) * limit; - - const totalCount = await db?.get(` + try { + const offset = (page - 1) * limit; + + const totalCount = await db?.get(` SELECT COUNT(*) as count FROM dsn `); - const results = await db?.all(` + const results = await db?.all( + ` SELECT dsn.id, dsn.tweet_id, @@ -416,42 +431,45 @@ export async function getAllDsn(page: number = 1, limit: number = 10) { LEFT JOIN skipped_tweets st ON t.id = st.tweet_id ORDER BY dsn.created_at DESC LIMIT ? OFFSET ? - `, [limit, offset]); - - return { - data: results, - pagination: { - total: totalCount?.count || 0, - page, - limit, - totalPages: Math.ceil((totalCount?.count || 0) / limit) - } - }; - } catch (error) { - logger.error('Failed to get all DSN records', error); - throw error; - } + `, + [limit, offset], + ); + + return { + data: results, + pagination: { + total: totalCount?.count || 0, + page, + limit, + totalPages: Math.ceil((totalCount?.count || 0) / limit), + }, + }; + } catch (error) { + logger.error('Failed to get all DSN records', error); + throw error; + } } export async function getLastDsnCid(): Promise { - const dsn = await db?.get(`SELECT cid FROM dsn ORDER BY created_at DESC LIMIT 1`); - return dsn?.cid || ''; + const dsn = await db?.get(`SELECT cid FROM dsn ORDER BY created_at DESC LIMIT 1`); + return dsn?.cid || ''; } ///////////MENTIONS/////////// -export async function addMention(mention: { - latest_id: string; -}) { - return db?.run(` +export async function addMention(mention: { latest_id: string }) { + return db?.run( + ` INSERT INTO mentions (latest_id) VALUES (?) ON CONFLICT(latest_id) DO UPDATE SET latest_id = excluded.latest_id, updated_at = CURRENT_TIMESTAMP - `, [mention.latest_id]); + `, + [mention.latest_id], + ); } export async function getLatestMentionId(): Promise { - const mention = await db?.get(`SELECT latest_id FROM mentions ORDER BY updated_at DESC LIMIT 1`); - return mention?.latest_id || ''; -} \ No newline at end of file + const mention = await db?.get(`SELECT latest_id FROM mentions ORDER BY updated_at DESC LIMIT 1`); + return mention?.latest_id || ''; +} diff --git a/auto-kol/agent/src/index.ts b/auto-kol/agent/src/index.ts index e1d9c3c..dc42698 100644 --- a/auto-kol/agent/src/index.ts +++ b/auto-kol/agent/src/index.ts @@ -13,36 +13,33 @@ app.use(corsMiddleware); app.use(express.json()); app.use(apiRoutes); - const startWorkflowPolling = async () => { - try { - await runWorkflow(); - logger.info('Workflow execution completed successfully'); - } catch (error) { - logger.error('Error running workflow:', error); - } + try { + await runWorkflow(); + logger.info('Workflow execution completed successfully'); + } catch (error) { + logger.error('Error running workflow:', error); + } }; - - const main = async () => { - try { - await initializeSchema(); - - app.listen(config.PORT, () => { - logger.info(`Server running on port ${config.PORT}`); - }); - await startWorkflowPolling(); - setInterval(startWorkflowPolling, config.CHECK_INTERVAL); - - logger.info('Application started successfully', { - checkInterval: config.CHECK_INTERVAL, - port: config.PORT - }); - } catch (error) { - logger.error('Failed to start application:', error); - process.exit(1); - } + try { + await initializeSchema(); + + app.listen(config.PORT, () => { + logger.info(`Server running on port ${config.PORT}`); + }); + await startWorkflowPolling(); + setInterval(startWorkflowPolling, config.CHECK_INTERVAL); + + logger.info('Application started successfully', { + checkInterval: config.CHECK_INTERVAL, + port: config.PORT, + }); + } catch (error) { + logger.error('Failed to start application:', error); + process.exit(1); + } }; -main(); \ No newline at end of file +main(); diff --git a/auto-kol/agent/src/schemas/workflow.ts b/auto-kol/agent/src/schemas/workflow.ts index 374e76f..26b9cc4 100644 --- a/auto-kol/agent/src/schemas/workflow.ts +++ b/auto-kol/agent/src/schemas/workflow.ts @@ -1,74 +1,84 @@ import { z } from 'zod'; export const tweetSearchSchema = z.object({ - tweets: z.array(z.object({ - id: z.string(), - text: z.string(), - author_id: z.string(), - author_username: z.string(), - created_at: z.string(), - mention: z.boolean().optional() - })), - lastProcessedId: z.string().nullable().optional() + tweets: z.array( + z.object({ + id: z.string(), + text: z.string(), + author_id: z.string(), + author_username: z.string(), + created_at: z.string(), + mention: z.boolean().optional(), + }), + ), + lastProcessedId: z.string().nullable().optional(), }); export const engagementSchema = z.object({ - shouldEngage: z.boolean(), - reason: z.string(), - priority: z.number().min(1).max(10), - confidence: z.number().min(0).max(1) + shouldEngage: z.boolean(), + reason: z.string(), + priority: z.number().min(1).max(10), + confidence: z.number().min(0).max(1), }); export const toneSchema = z.object({ - dominantTone: z.string(), - suggestedTone: z.string(), - reasoning: z.string(), - confidence: z.number().min(0).max(1) + dominantTone: z.string(), + suggestedTone: z.string(), + reasoning: z.string(), + confidence: z.number().min(0).max(1), }); export const responseSchema = z.object({ - content: z.string(), - tone: z.string(), - strategy: z.string(), - estimatedImpact: z.number().min(1).max(10), - confidence: z.number().min(0).max(1), - referencedTweets: z.array(z.object({ + content: z.string(), + tone: z.string(), + strategy: z.string(), + estimatedImpact: z.number().min(1).max(10), + confidence: z.number().min(0).max(1), + referencedTweets: z + .array( + z.object({ text: z.string(), reason: z.string(), - similarity_score: z.number() - })).optional(), - mentions: z.array(z.object({ + similarity_score: z.number(), + }), + ) + .optional(), + mentions: z + .array( + z.object({ id: z.string(), text: z.string(), author_id: z.string(), author_username: z.string(), - created_at: z.string() - })).optional(), - rejectionReason: z.string().optional(), - suggestedChanges: z.string().optional() + created_at: z.string(), + }), + ) + .optional(), + rejectionReason: z.string().optional(), + suggestedChanges: z.string().optional(), }); export const queueActionSchema = z.object({ - tweet: z.object({ - id: z.string(), - text: z.string(), - author_id: z.string(), - author_username: z.string(), - created_at: z.string() - }), - reason: z.string().optional(), - priority: z.number().optional(), - workflowState: z.record(z.any()).optional() + tweet: z.object({ + id: z.string(), + text: z.string(), + author_id: z.string(), + author_username: z.string(), + created_at: z.string(), + }), + reason: z.string().optional(), + priority: z.number().optional(), + workflowState: z.record(z.any()).optional(), }); export const dsnUploadSchema = z.object({ - previousCid: z.string().optional(), - data: z.any(), + previousCid: z.string().optional(), + data: z.any(), }); export const autoApprovalSchema = z.object({ - approved: z.boolean(), - reason: z.string(), - confidence: z.number().min(0).max(1), - suggestedChanges: z.string().optional() + approved: z.boolean(), + reason: z.string(), + confidence: z.number().min(0).max(1), + suggestedChanges: z.string().optional(), }); diff --git a/auto-kol/agent/src/services/agents/nodes.ts b/auto-kol/agent/src/services/agents/nodes.ts index c79c966..243a63e 100644 --- a/auto-kol/agent/src/services/agents/nodes.ts +++ b/auto-kol/agent/src/services/agents/nodes.ts @@ -1,50 +1,49 @@ import { WorkflowConfig } from './workflow.js'; import { createTwitterClientScraper } from '../twitter/api.js'; import { createSearchNode } from './nodes/searchNode.js'; -import { createEngagementNode } from "./nodes/engagementNode.js"; -import { createToneAnalysisNode } from "./nodes/toneAnalysisNode.js"; -import { createResponseGenerationNode } from "./nodes/responseGenerationNode.js"; -import { createRecheckSkippedNode } from "./nodes/recheckSkippedNode.js"; -import { createTimelineNode } from "./nodes/timelineNode.js"; -import { createMentionNode } from "./nodes/mentionNode.js"; +import { createEngagementNode } from './nodes/engagementNode.js'; +import { createToneAnalysisNode } from './nodes/toneAnalysisNode.js'; +import { createResponseGenerationNode } from './nodes/responseGenerationNode.js'; +import { createRecheckSkippedNode } from './nodes/recheckSkippedNode.js'; +import { createTimelineNode } from './nodes/timelineNode.js'; +import { createMentionNode } from './nodes/mentionNode.js'; import { createAutoApprovalNode } from './nodes/autoApprovalNode.js'; export const createNodes = async (config: WorkflowConfig) => { + const scraper = await createTwitterClientScraper(); - const scraper = await createTwitterClientScraper(); + ///////////MENTIONS/////////// + const mentionNode = createMentionNode(config); - ///////////MENTIONS/////////// - const mentionNode = createMentionNode(config); + ///////////TIMELINE/////////// + const timelineNode = createTimelineNode(config); - ///////////TIMELINE/////////// - const timelineNode = createTimelineNode(config); + ///////////SEARCH/////////// + const searchNode = createSearchNode(config); - ///////////SEARCH/////////// - const searchNode = createSearchNode(config); + ///////////ENGAGEMENT/////////// + const engagementNode = createEngagementNode(config); - ///////////ENGAGEMENT/////////// - const engagementNode = createEngagementNode(config); + ///////////TONE ANALYSIS/////////// + const toneAnalysisNode = createToneAnalysisNode(config); - ///////////TONE ANALYSIS/////////// - const toneAnalysisNode = createToneAnalysisNode(config); + ///////////RESPONSE GENERATION/////////// + const responseGenerationNode = createResponseGenerationNode(config, scraper); - ///////////RESPONSE GENERATION/////////// - const responseGenerationNode = createResponseGenerationNode(config, scraper); + ///////////RECHECK SKIPPED/////////// + const recheckSkippedNode = createRecheckSkippedNode(config); - ///////////RECHECK SKIPPED/////////// - const recheckSkippedNode = createRecheckSkippedNode(config); + ///////////AUTO APPROVAL/////////// + const autoApprovalNode = createAutoApprovalNode(config, scraper); - ///////////AUTO APPROVAL/////////// - const autoApprovalNode = createAutoApprovalNode(config, scraper); - - return { - mentionNode, - timelineNode, - searchNode, - engagementNode, - toneAnalysisNode, - responseGenerationNode, - recheckSkippedNode, - autoApprovalNode - }; -}; \ No newline at end of file + return { + mentionNode, + timelineNode, + searchNode, + engagementNode, + toneAnalysisNode, + responseGenerationNode, + recheckSkippedNode, + autoApprovalNode, + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/autoApprovalNode.ts b/auto-kol/agent/src/services/agents/nodes/autoApprovalNode.ts index 49659d3..fc6d504 100644 --- a/auto-kol/agent/src/services/agents/nodes/autoApprovalNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/autoApprovalNode.ts @@ -1,114 +1,121 @@ -import { AIMessage } from "@langchain/core/messages"; +import { AIMessage } from '@langchain/core/messages'; import { State, logger, parseMessageContent } from '../workflow.js'; import * as prompts from '../prompts.js'; import { WorkflowConfig } from '../workflow.js'; import { getLastDsnCid, updateResponseStatusByTweetId } from '../../../database/index.js'; -import { uploadToDsn } from "../../../utils/dsn.js"; +import { uploadToDsn } from '../../../utils/dsn.js'; import { config as globalConfig } from '../../../config/index.js'; import { ResponseStatus } from '../../../types/queue.js'; import { ExtendedScraper } from '../../../services/twitter/api.js'; export const createAutoApprovalNode = (config: WorkflowConfig, scraper: ExtendedScraper) => { - return async (state: typeof State.State) => { - logger.info('Auto Approval Node - Evaluating pending responses'); - try { - const lastMessage = state.messages[state.messages.length - 1]; - const parsedContent = parseMessageContent(lastMessage.content); - const { tweets, currentTweetIndex, batchToFeedback } = parsedContent; + return async (state: typeof State.State) => { + logger.info('Auto Approval Node - Evaluating pending responses'); + try { + const lastMessage = state.messages[state.messages.length - 1]; + const parsedContent = parseMessageContent(lastMessage.content); + const { tweets, currentTweetIndex, batchToFeedback } = parsedContent; - if (!batchToFeedback.length) { - logger.info('No pending responses found'); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - fromAutoApproval: true, - batchToRespond: [] - }) - })] - }; - } + if (!batchToFeedback.length) { + logger.info('No pending responses found'); + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + fromAutoApproval: true, + batchToRespond: [], + }), + }), + ], + }; + } - const processedResponses = []; + const processedResponses = []; - for (const response of batchToFeedback) { - logger.info('Processing response', { - tweetId: response.tweet.id, - retry: response.retry - }); + for (const response of batchToFeedback) { + logger.info('Processing response', { + tweetId: response.tweet.id, + retry: response.retry, + }); - const approval = await prompts.autoApprovalPrompt - .pipe(config.llms.decision) - .pipe(prompts.autoApprovalParser) - .invoke({ - tweet: response.tweet, - response: response.response, - tone: response.toneAnalysis?.dominantTone, - strategy: response.responseStrategy?.strategy - }); + const approval = await prompts.autoApprovalPrompt + .pipe(config.llms.decision) + .pipe(prompts.autoApprovalParser) + .invoke({ + tweet: response.tweet, + response: response.response, + tone: response.toneAnalysis?.dominantTone, + strategy: response.responseStrategy?.strategy, + }); - if (approval.approved) { - response.type = ResponseStatus.APPROVED; + if (approval.approved) { + response.type = ResponseStatus.APPROVED; - await updateResponseStatusByTweetId(response.tweet.id, ResponseStatus.APPROVED); + await updateResponseStatusByTweetId(response.tweet.id, ResponseStatus.APPROVED); - if (globalConfig.POST_TWEETS) { - logger.info('Sending tweet', { - response: response.response, - tweetId: response.tweet.id - }); + if (globalConfig.POST_TWEETS) { + logger.info('Sending tweet', { + response: response.response, + tweetId: response.tweet.id, + }); - const sendTweetResponse = await scraper.sendTweet(response.response, response.tweet.id); - logger.info('Tweet sent', { - sendTweetResponse - }); - } + const sendTweetResponse = await scraper.sendTweet(response.response, response.tweet.id); + logger.info('Tweet sent', { + sendTweetResponse, + }); + } - if (globalConfig.DSN_UPLOAD) { - await uploadToDsn({ - data: response, - }); - } - } else if (response.retry > globalConfig.RETRY_LIMIT) { - response.type = ResponseStatus.REJECTED; - logger.info('Rejecting tweet', { - tweetId: response.tweet.id, - }); - await updateResponseStatusByTweetId(response.tweet.id, ResponseStatus.REJECTED); - if (globalConfig.DSN_UPLOAD) { - await uploadToDsn({ - data: response, - }); - } - } else { - processedResponses.push({ - ...response, - type: ResponseStatus.PENDING, - workflowState: { - ...response.workflowState, - autoFeedback: [...response.workflowState.autoFeedback, { - response: response.response, - reason: approval.reason, - suggestedChanges: approval.suggestedChanges - }] - }, - feedbackDecision: 'reject' - }); - } - } - - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: tweets, - currentTweetIndex: currentTweetIndex, - fromAutoApproval: true, - batchToRespond: processedResponses - }) - })] - }; - } catch (error) { - logger.error('Error in auto approval node:', error); - return { messages: [] }; + if (globalConfig.DSN_UPLOAD) { + await uploadToDsn({ + data: response, + }); + } + } else if (response.retry > globalConfig.RETRY_LIMIT) { + response.type = ResponseStatus.REJECTED; + logger.info('Rejecting tweet', { + tweetId: response.tweet.id, + }); + await updateResponseStatusByTweetId(response.tweet.id, ResponseStatus.REJECTED); + if (globalConfig.DSN_UPLOAD) { + await uploadToDsn({ + data: response, + }); + } + } else { + processedResponses.push({ + ...response, + type: ResponseStatus.PENDING, + workflowState: { + ...response.workflowState, + autoFeedback: [ + ...response.workflowState.autoFeedback, + { + response: response.response, + reason: approval.reason, + suggestedChanges: approval.suggestedChanges, + }, + ], + }, + feedbackDecision: 'reject', + }); } + } + + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: tweets, + currentTweetIndex: currentTweetIndex, + fromAutoApproval: true, + batchToRespond: processedResponses, + }), + }), + ], + }; + } catch (error) { + logger.error('Error in auto approval node:', error); + return { messages: [] }; } -}; \ No newline at end of file + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/engagementNode.ts b/auto-kol/agent/src/services/agents/nodes/engagementNode.ts index dffbde3..7fff07e 100644 --- a/auto-kol/agent/src/services/agents/nodes/engagementNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/engagementNode.ts @@ -1,4 +1,4 @@ -import { AIMessage } from "@langchain/core/messages"; +import { AIMessage } from '@langchain/core/messages'; import { State, logger, parseMessageContent } from '../workflow.js'; import * as prompts from '../prompts.js'; import { uploadToDsn } from '../../../utils/dsn.js'; @@ -8,126 +8,141 @@ import { config as globalConfig } from '../../../config/index.js'; import { ResponseStatus } from '../../../types/queue.js'; const handleSkippedTweet = async (tweet: any, decision: any, config: any) => { - logger.info('Skipping engagement for tweet', { tweetId: tweet.id, reason: decision.reason }); - await config.toolNode.invoke({ - messages: [new AIMessage({ - content: '', - tool_calls: [{ - name: 'queue_skipped', - args: { - tweet, - reason: decision.reason, - priority: decision.priority || 0, - workflowState: { decision } - }, - id: 'skip_call', - type: 'tool_call' - }] - })] - }); - - if (globalConfig.DSN_UPLOAD) { - await uploadToDsn({ - data: { - type: ResponseStatus.SKIPPED, - tweet, - decision, - workflowState: { - decision, - toneAnalysis: null, - responseStrategy: null - } + logger.info('Skipping engagement for tweet', { tweetId: tweet.id, reason: decision.reason }); + await config.toolNode.invoke({ + messages: [ + new AIMessage({ + content: '', + tool_calls: [ + { + name: 'queue_skipped', + args: { + tweet, + reason: decision.reason, + priority: decision.priority || 0, + workflowState: { decision }, }, - }); - } + id: 'skip_call', + type: 'tool_call', + }, + ], + }), + ], + }); + + if (globalConfig.DSN_UPLOAD) { + await uploadToDsn({ + data: { + type: ResponseStatus.SKIPPED, + tweet, + decision, + workflowState: { + decision, + toneAnalysis: null, + responseStrategy: null, + }, + }, + }); + } }; export const createEngagementNode = (config: WorkflowConfig) => { - return async (state: typeof State.State) => { - logger.info('Engagement Node - Starting evaluation'); - try { - const lastMessage = state.messages[state.messages.length - 1]; - const parsedContent = parseMessageContent(lastMessage.content); - const pendingEngagements = parsedContent.pendingEngagements || []; - logger.info(`Current tweet index: ${parsedContent?.currentTweetIndex}`); + return async (state: typeof State.State) => { + logger.info('Engagement Node - Starting evaluation'); + try { + const lastMessage = state.messages[state.messages.length - 1]; + const parsedContent = parseMessageContent(lastMessage.content); + const pendingEngagements = parsedContent.pendingEngagements || []; + logger.info(`Current tweet index: ${parsedContent?.currentTweetIndex}`); - if (pendingEngagements.length > 0) { - logger.info(`number of pending engagements: ${pendingEngagements.length}`); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: parsedContent.tweets, - currentTweetIndex: parsedContent.currentTweetIndex, - batchToAnalyze: pendingEngagements, - pendingEngagements: [], - lastProcessedId: parsedContent.lastProcessedId, - batchProcessing: true - }) - })], - processedTweets: state.processedTweets - }; - } + if (pendingEngagements.length > 0) { + logger.info(`number of pending engagements: ${pendingEngagements.length}`); + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: parsedContent.tweets, + currentTweetIndex: parsedContent.currentTweetIndex, + batchToAnalyze: pendingEngagements, + pendingEngagements: [], + lastProcessedId: parsedContent.lastProcessedId, + batchProcessing: true, + }), + }), + ], + processedTweets: state.processedTweets, + }; + } - const BATCH_SIZE = globalConfig.ENGAGEMENT_BATCH_SIZE; - const startIdx = parsedContent.currentTweetIndex || 0; - const proposedEndIdx = Number(startIdx) + Number(BATCH_SIZE); - const endIdx = Math.min(proposedEndIdx, parsedContent.tweets?.length || 0); - const batchTweets = parsedContent.tweets?.slice(startIdx, endIdx) || []; + const BATCH_SIZE = globalConfig.ENGAGEMENT_BATCH_SIZE; + const startIdx = parsedContent.currentTweetIndex || 0; + const proposedEndIdx = Number(startIdx) + Number(BATCH_SIZE); + const endIdx = Math.min(proposedEndIdx, parsedContent.tweets?.length || 0); + const batchTweets = parsedContent.tweets?.slice(startIdx, endIdx) || []; - logger.info('Processing batch of tweets', { - batchSize: batchTweets.length, - startIndex: startIdx, - endIndex: endIdx, - totalTweets: parsedContent.tweets.length - }); - - const processedResults = await Promise.all(batchTweets.map(async (tweet: any) => { - if (state.processedTweets.has(tweet.id)) { - return { tweet, status: 'alreadyProcessed' }; - } + logger.info('Processing batch of tweets', { + batchSize: batchTweets.length, + startIndex: startIdx, + endIndex: endIdx, + totalTweets: parsedContent.tweets.length, + }); - const decision = await prompts.engagementPrompt - .pipe(config.llms.decision) - .pipe(prompts.engagementParser) - .invoke({ tweet: tweet.text }) - .catch((error) => { - logger.error('Error in engagement node:', error); - return { shouldEngage: false, reason: 'Error in engagement node', priority: 0, confidence: 0 }; - }); + const processedResults = await Promise.all( + batchTweets.map(async (tweet: any) => { + if (state.processedTweets.has(tweet.id)) { + return { tweet, status: 'alreadyProcessed' }; + } - return { tweet, decision, status: 'processing' }; - })); + const decision = await prompts.engagementPrompt + .pipe(config.llms.decision) + .pipe(prompts.engagementParser) + .invoke({ tweet: tweet.text }) + .catch(error => { + logger.error('Error in engagement node:', error); + return { + shouldEngage: false, + reason: 'Error in engagement node', + priority: 0, + confidence: 0, + }; + }); - const tweetsToEngage = []; - const newProcessedTweets = new Set(state.processedTweets); + return { tweet, decision, status: 'processing' }; + }), + ); - for (const result of processedResults) { - newProcessedTweets.add(result.tweet.id); - if (result.status === 'processing' && result.decision?.shouldEngage) { - tweetsToEngage.push({ - tweet: result.tweet, - decision: result.decision - }); - } else if (result.status === 'processing') { - await handleSkippedTweet(result.tweet, result.decision, config); - } - } + const tweetsToEngage = []; + const newProcessedTweets = new Set(state.processedTweets); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: parsedContent.tweets, - currentTweetIndex: endIdx, - pendingEngagements: tweetsToEngage, - lastProcessedId: parsedContent.lastProcessedId, - batchProcessing: true, - }) - })], - processedTweets: newProcessedTweets - }; - } catch (error) { - logger.error('Error in engagement node:', error); - return { messages: [] }; + for (const result of processedResults) { + newProcessedTweets.add(result.tweet.id); + if (result.status === 'processing' && result.decision?.shouldEngage) { + tweetsToEngage.push({ + tweet: result.tweet, + decision: result.decision, + }); + } else if (result.status === 'processing') { + await handleSkippedTweet(result.tweet, result.decision, config); } + } + + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: parsedContent.tweets, + currentTweetIndex: endIdx, + pendingEngagements: tweetsToEngage, + lastProcessedId: parsedContent.lastProcessedId, + batchProcessing: true, + }), + }), + ], + processedTweets: newProcessedTweets, + }; + } catch (error) { + logger.error('Error in engagement node:', error); + return { messages: [] }; } -} \ No newline at end of file + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/mentionNode.ts b/auto-kol/agent/src/services/agents/nodes/mentionNode.ts index 5118b83..6735065 100644 --- a/auto-kol/agent/src/services/agents/nodes/mentionNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/mentionNode.ts @@ -1,36 +1,42 @@ -import { AIMessage } from "@langchain/core/messages"; -import { parseMessageContent, WorkflowConfig } from "../workflow.js"; -import { logger } from "../workflow.js"; -import { State } from "../workflow.js"; -import { tweetSearchSchema } from "../../../schemas/workflow.js"; +import { AIMessage } from '@langchain/core/messages'; +import { parseMessageContent, WorkflowConfig } from '../workflow.js'; +import { logger } from '../workflow.js'; +import { State } from '../workflow.js'; +import { tweetSearchSchema } from '../../../schemas/workflow.js'; export const createMentionNode = (config: WorkflowConfig) => { - return async (state: typeof State.State) => { - logger.info('Mention Node - Fetching recent mentions'); - const toolResponse = await config.toolNode.invoke({ - messages: [ - new AIMessage({ - content: '', - tool_calls: [{ - name: 'fetch_mentions', - args: {}, - id: 'fetch_mentions_call', - type: 'tool_call' - }] - }) - ] - }); + return async (state: typeof State.State) => { + logger.info('Mention Node - Fetching recent mentions'); + const toolResponse = await config.toolNode.invoke({ + messages: [ + new AIMessage({ + content: '', + tool_calls: [ + { + name: 'fetch_mentions', + args: {}, + id: 'fetch_mentions_call', + type: 'tool_call', + }, + ], + }), + ], + }); - const parsedContent = parseMessageContent(toolResponse.messages[toolResponse.messages.length - 1].content); - const parsedTweets = tweetSearchSchema.parse(parsedContent); - logger.info('Parsed tweets:', parsedTweets); - logger.info(`Found ${parsedTweets.tweets.length} tweets`); + const parsedContent = parseMessageContent( + toolResponse.messages[toolResponse.messages.length - 1].content, + ); + const parsedTweets = tweetSearchSchema.parse(parsedContent); + logger.info('Parsed tweets:', parsedTweets); + logger.info(`Found ${parsedTweets.tweets.length} tweets`); - return { - messages: [new AIMessage({ - content: JSON.stringify(parsedTweets) - })], - lastProcessedId: parsedTweets.lastProcessedId || undefined - }; - } -} \ No newline at end of file + return { + messages: [ + new AIMessage({ + content: JSON.stringify(parsedTweets), + }), + ], + lastProcessedId: parsedTweets.lastProcessedId || undefined, + }; + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/recheckSkippedNode.ts b/auto-kol/agent/src/services/agents/nodes/recheckSkippedNode.ts index 99e0d29..188dba1 100644 --- a/auto-kol/agent/src/services/agents/nodes/recheckSkippedNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/recheckSkippedNode.ts @@ -1,89 +1,95 @@ -import { AIMessage } from "@langchain/core/messages"; +import { AIMessage } from '@langchain/core/messages'; import { State, logger, parseMessageContent } from '../workflow.js'; import * as prompts from '../prompts.js'; import { flagBackSkippedTweet, getAllSkippedTweetsToRecheck } from '../../../database/index.js'; import { WorkflowConfig } from '../workflow.js'; export const createRecheckSkippedNode = (config: WorkflowConfig) => { - return async (state: typeof State.State) => { - logger.info('Recheck Skipped Node - Reviewing previously skipped tweets'); - try { - const lastMessage = state.messages[state.messages.length - 1]; - const parsedContent = parseMessageContent(lastMessage.content); - const {tweets, currentTweetIndex} = parsedContent; - logger.info(`currentTweetIndex: ${currentTweetIndex}`); - - const skippedTweets = await getAllSkippedTweetsToRecheck(); + return async (state: typeof State.State) => { + logger.info('Recheck Skipped Node - Reviewing previously skipped tweets'); + try { + const lastMessage = state.messages[state.messages.length - 1]; + const parsedContent = parseMessageContent(lastMessage.content); + const { tweets, currentTweetIndex } = parsedContent; + logger.info(`currentTweetIndex: ${currentTweetIndex}`); - if (!skippedTweets || skippedTweets.length === 0) { - logger.info('No skipped tweets to recheck'); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - fromRecheckNode: true, - currentTweetIndex: currentTweetIndex, - tweets: tweets, - pendingEngagements: [], - messages: [] - }) - })] - }; - } + const skippedTweets = await getAllSkippedTweetsToRecheck(); - logger.info(`Found ${skippedTweets.length} skipped tweets to recheck`); + if (!skippedTweets || skippedTweets.length === 0) { + logger.info('No skipped tweets to recheck'); + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + fromRecheckNode: true, + currentTweetIndex: currentTweetIndex, + tweets: tweets, + pendingEngagements: [], + messages: [], + }), + }), + ], + }; + } - const processedTweets = []; - for (const tweet of skippedTweets) { - const decision = await prompts.engagementPrompt - .pipe(config.llms.decision) - .pipe(prompts.engagementParser) - .invoke({ tweet: tweet.text }); + logger.info(`Found ${skippedTweets.length} skipped tweets to recheck`); - logger.info('Recheck decision:', { tweetId: tweet.id, decision }); + const processedTweets = []; + for (const tweet of skippedTweets) { + const decision = await prompts.engagementPrompt + .pipe(config.llms.decision) + .pipe(prompts.engagementParser) + .invoke({ tweet: tweet.text }); - if (decision.shouldEngage) { - processedTweets.push({ - tweet, - decision - }); - } else { - const flagged = await flagBackSkippedTweet(tweet.id, decision.reason); - if (!flagged) { - logger.info('Failed to flag back skipped tweet:', { tweetId: tweet.id }); - } - } - } + logger.info('Recheck decision:', { tweetId: tweet.id, decision }); - if (processedTweets.length === 0) { - logger.info('No skipped tweets passed recheck'); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - fromRecheckNode: true, - currentTweetIndex: currentTweetIndex, - tweets: tweets, - pendingEngagements: [], - messages: [] - }) - })] - }; - } + if (decision.shouldEngage) { + processedTweets.push({ + tweet, + decision, + }); + } else { + const flagged = await flagBackSkippedTweet(tweet.id, decision.reason); + if (!flagged) { + logger.info('Failed to flag back skipped tweet:', { tweetId: tweet.id }); + } + } + } - const { tweet, decision } = processedTweets[0]; + if (processedTweets.length === 0) { + logger.info('No skipped tweets passed recheck'); + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + fromRecheckNode: true, + currentTweetIndex: currentTweetIndex, + tweets: tweets, + pendingEngagements: [], + messages: [], + }), + }), + ], + }; + } - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: [tweet], - currentTweetIndex: 0, - tweet, - decision - }) - })] - }; - } catch (error) { - logger.error('Error in recheck skipped node:', error); - return { messages: [] }; - } + const { tweet, decision } = processedTweets[0]; + + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: [tweet], + currentTweetIndex: 0, + tweet, + decision, + }), + }), + ], + }; + } catch (error) { + logger.error('Error in recheck skipped node:', error); + return { messages: [] }; } -} \ No newline at end of file + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/responseGenerationNode.ts b/auto-kol/agent/src/services/agents/nodes/responseGenerationNode.ts index 6abe145..700e66e 100644 --- a/auto-kol/agent/src/services/agents/nodes/responseGenerationNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/responseGenerationNode.ts @@ -1,174 +1,187 @@ -import { AIMessage } from "@langchain/core/messages"; +import { AIMessage } from '@langchain/core/messages'; import { State, logger, parseMessageContent } from '../workflow.js'; import * as prompts from '../prompts.js'; import { WorkflowConfig } from '../workflow.js'; import { ResponseStatus } from '../../../types/queue.js'; export const createResponseGenerationNode = (config: WorkflowConfig, scraper: any) => { - return async (state: typeof State.State) => { - logger.info('Response Generation Node - Creating response strategy'); - try { - const lastMessage = state.messages[state.messages.length - 1]; - const parsedContent = parseMessageContent(lastMessage.content); - const batchToRespond = parsedContent.batchToRespond || []; - const batchToFeedback: any[] = []; + return async (state: typeof State.State) => { + logger.info('Response Generation Node - Creating response strategy'); + try { + const lastMessage = state.messages[state.messages.length - 1]; + const parsedContent = parseMessageContent(lastMessage.content); + const batchToRespond = parsedContent.batchToRespond || []; + const batchToFeedback: any[] = []; - logger.info(`Processing batch of ${batchToRespond.length} tweets for response generation`, { - hasRejectedResponses: parsedContent.fromAutoApproval - }); - - await Promise.all( - batchToRespond.map(async (item: any) => { - const { tweet, decision, toneAnalysis, workflowState } = item; + logger.info(`Processing batch of ${batchToRespond.length} tweets for response generation`, { + hasRejectedResponses: parsedContent.fromAutoApproval, + }); - if (!workflowState) { - item.workflowState = { autoFeedback: [] }; - } else if (!workflowState.autoFeedback) { - workflowState.autoFeedback = []; - } + await Promise.all( + batchToRespond.map(async (item: any) => { + const { tweet, decision, toneAnalysis, workflowState } = item; - if (parsedContent.fromAutoApproval) { - item.retry = (item.retry || 0) + 1; - logger.info('Regenerating response due to rejection:', { - retry: item.retry - }); + if (!workflowState) { + item.workflowState = { autoFeedback: [] }; + } else if (!workflowState.autoFeedback) { + workflowState.autoFeedback = []; + } - } else { - item.retry = 0; - } - - const lastFeedback = workflowState?.autoFeedback[workflowState?.autoFeedback.length - 1]; - const rejectionInstructions = lastFeedback - ? prompts.formatRejectionInstructions(lastFeedback.reason) - : ''; - const rejectionFeedback = lastFeedback - ? prompts.formatRejectionFeedback(lastFeedback.reason, lastFeedback.suggestedChanges) - : ''; + if (parsedContent.fromAutoApproval) { + item.retry = (item.retry || 0) + 1; + logger.info('Regenerating response due to rejection:', { + retry: item.retry, + }); + } else { + item.retry = 0; + } - const threadMentionsTweets = []; - if (item?.mentions) { - threadMentionsTweets.push(...item.mentions); - } else if (tweet.mention) { - const mentions = await scraper.getThread(tweet.id); - for await (const mention of mentions) { - threadMentionsTweets.push({ - id: mention.id, - text: mention.text, - author_id: mention.userId, - author_username: mention.username?.toLowerCase() || 'unknown', - created_at: mention.timeParsed?.toISOString() || new Date().toISOString() - }); - } - } + const lastFeedback = workflowState?.autoFeedback[workflowState?.autoFeedback.length - 1]; + const rejectionInstructions = lastFeedback + ? prompts.formatRejectionInstructions(lastFeedback.reason) + : ''; + const rejectionFeedback = lastFeedback + ? prompts.formatRejectionFeedback(lastFeedback.reason, lastFeedback.suggestedChanges) + : ''; - const similarTweetsResponse = await config.toolNode.invoke({ - messages: [new AIMessage({ - content: '', - tool_calls: [{ - name: 'search_similar_tweets', - args: { - query: `author:${tweet.author_username} ${tweet.text}`, - k: 5 - }, - id: 'similar_tweets_call', - type: 'tool_call' - }], - })], - }); + const threadMentionsTweets = []; + if (item?.mentions) { + threadMentionsTweets.push(...item.mentions); + } else if (tweet.mention) { + const mentions = await scraper.getThread(tweet.id); + for await (const mention of mentions) { + threadMentionsTweets.push({ + id: mention.id, + text: mention.text, + author_id: mention.userId, + author_username: mention.username?.toLowerCase() || 'unknown', + created_at: mention.timeParsed?.toISOString() || new Date().toISOString(), + }); + } + } - const similarTweets = parseMessageContent( - similarTweetsResponse.messages[similarTweetsResponse.messages.length - 1].content - ); - const responseStrategy = await prompts.responsePrompt - .pipe(config.llms.response) - .pipe(prompts.responseParser) - .invoke({ - tweet: tweet.text, - tone: toneAnalysis?.suggestedTone || workflowState?.toneAnalysis?.suggestedTone, - author: tweet.author_username, - similarTweets: JSON.stringify(similarTweets.similar_tweets), - mentions: JSON.stringify(threadMentionsTweets), - previousResponse: workflowState?.autoFeedback[workflowState?.autoFeedback.length - 1]?.response || '', - rejectionFeedback, - rejectionInstructions - }); + const similarTweetsResponse = await config.toolNode.invoke({ + messages: [ + new AIMessage({ + content: '', + tool_calls: [ + { + name: 'search_similar_tweets', + args: { + query: `author:${tweet.author_username} ${tweet.text}`, + k: 5, + }, + id: 'similar_tweets_call', + type: 'tool_call', + }, + ], + }), + ], + }); + const similarTweets = parseMessageContent( + similarTweetsResponse.messages[similarTweetsResponse.messages.length - 1].content, + ); + const responseStrategy = await prompts.responsePrompt + .pipe(config.llms.response) + .pipe(prompts.responseParser) + .invoke({ + tweet: tweet.text, + tone: toneAnalysis?.suggestedTone || workflowState?.toneAnalysis?.suggestedTone, + author: tweet.author_username, + similarTweets: JSON.stringify(similarTweets.similar_tweets), + mentions: JSON.stringify(threadMentionsTweets), + previousResponse: + workflowState?.autoFeedback[workflowState?.autoFeedback.length - 1]?.response || '', + rejectionFeedback, + rejectionInstructions, + }); - const data = { - type: ResponseStatus.PENDING, - tweet, - response: responseStrategy.content, - workflowState: { - decision: decision || workflowState?.decision, - toneAnalysis: toneAnalysis || workflowState?.toneAnalysis, - responseStrategy: { - tone: responseStrategy.tone, - strategy: responseStrategy.strategy, - referencedTweets: responseStrategy.referencedTweets, - confidence: responseStrategy.confidence - }, - autoFeedback: workflowState?.autoFeedback || [] - }, - mentions: threadMentionsTweets, - retry: item.retry - } - batchToFeedback.push(data); + const data = { + type: ResponseStatus.PENDING, + tweet, + response: responseStrategy.content, + workflowState: { + decision: decision || workflowState?.decision, + toneAnalysis: toneAnalysis || workflowState?.toneAnalysis, + responseStrategy: { + tone: responseStrategy.tone, + strategy: responseStrategy.strategy, + referencedTweets: responseStrategy.referencedTweets, + confidence: responseStrategy.confidence, + }, + autoFeedback: workflowState?.autoFeedback || [], + }, + mentions: threadMentionsTweets, + retry: item.retry, + }; + batchToFeedback.push(data); - const args = { - tweet, - response: responseStrategy.content, - workflowState: { - toneAnalysis: toneAnalysis, - responseStrategy, - mentions: threadMentionsTweets, - similarTweets: similarTweets.similar_tweets, - }, - } - if (!parsedContent.fromAutoApproval) { - const addResponse = await config.toolNode.invoke({ - messages: [new AIMessage({ - content: '', - tool_calls: [{ - name: 'add_response', - args, - id: 'add_response_call', - type: 'tool_call' - }] - })] - }); - return addResponse; - } else { - const updateResponse = await config.toolNode.invoke({ - messages: [new AIMessage({ - content: '', - tool_calls: [{ - name: 'update_response', - args, - id: 'update_response_call', - type: 'tool_call' - }] - })] - }); - return updateResponse; - } - }) - ); + const args = { + tweet, + response: responseStrategy.content, + workflowState: { + toneAnalysis: toneAnalysis, + responseStrategy, + mentions: threadMentionsTweets, + similarTweets: similarTweets.similar_tweets, + }, + }; + if (!parsedContent.fromAutoApproval) { + const addResponse = await config.toolNode.invoke({ + messages: [ + new AIMessage({ + content: '', + tool_calls: [ + { + name: 'add_response', + args, + id: 'add_response_call', + type: 'tool_call', + }, + ], + }), + ], + }); + return addResponse; + } else { + const updateResponse = await config.toolNode.invoke({ + messages: [ + new AIMessage({ + content: '', + tool_calls: [ + { + name: 'update_response', + args, + id: 'update_response_call', + type: 'tool_call', + }, + ], + }), + ], + }); + return updateResponse; + } + }), + ); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: parsedContent.tweets, - currentTweetIndex: parsedContent.currentTweetIndex, - pendingEngagements: parsedContent.pendingEngagements, - lastProcessedId: parsedContent.lastProcessedId, - batchToFeedback: batchToFeedback, - }) - })], - processedTweets: new Set(batchToRespond.map((item: any) => item.tweet.id)) - }; - } catch (error) { - logger.error('Error in response generation node:', error); - return { messages: [] }; - } + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: parsedContent.tweets, + currentTweetIndex: parsedContent.currentTweetIndex, + pendingEngagements: parsedContent.pendingEngagements, + lastProcessedId: parsedContent.lastProcessedId, + batchToFeedback: batchToFeedback, + }), + }), + ], + processedTweets: new Set(batchToRespond.map((item: any) => item.tweet.id)), + }; + } catch (error) { + logger.error('Error in response generation node:', error); + return { messages: [] }; } -}; \ No newline at end of file + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/searchNode.ts b/auto-kol/agent/src/services/agents/nodes/searchNode.ts index bfebbe2..ddebdf2 100644 --- a/auto-kol/agent/src/services/agents/nodes/searchNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/searchNode.ts @@ -1,4 +1,4 @@ -import { AIMessage } from "@langchain/core/messages"; +import { AIMessage } from '@langchain/core/messages'; import { State, logger, parseMessageContent } from '../workflow.js'; import { tweetSearchSchema } from '../../../schemas/workflow.js'; import { ChromaService } from '../../vectorstore/chroma.js'; @@ -6,89 +6,93 @@ import * as db from '../../database/index.js'; import { WorkflowConfig } from '../workflow.js'; export const createSearchNode = (config: WorkflowConfig) => { - return async (state: typeof State.State) => { - logger.info('Search Node - Fetching recent tweets'); - const existingTweets = state.messages.length > 0 ? - parseMessageContent(state.messages[state.messages.length - 1].content).tweets : []; + return async (state: typeof State.State) => { + logger.info('Search Node - Fetching recent tweets'); + const existingTweets = + state.messages.length > 0 + ? parseMessageContent(state.messages[state.messages.length - 1].content).tweets + : []; - logger.info(`Existing tweets: ${existingTweets.length}`); - try { - logger.info('Last processed id:', state.lastProcessedId); + logger.info(`Existing tweets: ${existingTweets.length}`); + try { + logger.info('Last processed id:', state.lastProcessedId); - const toolResponse = await config.toolNode.invoke({ - messages: [ - new AIMessage({ - content: '', - tool_calls: [{ - name: 'search_recent_tweets', - args: { - lastProcessedId: state.lastProcessedId || undefined - }, - id: 'tool_call_id', - type: 'tool_call' - }], - }), - ], - }); + const toolResponse = await config.toolNode.invoke({ + messages: [ + new AIMessage({ + content: '', + tool_calls: [ + { + name: 'search_recent_tweets', + args: { + lastProcessedId: state.lastProcessedId || undefined, + }, + id: 'tool_call_id', + type: 'tool_call', + }, + ], + }), + ], + }); - const lastMessage = toolResponse.messages[toolResponse.messages.length - 1]; + const lastMessage = toolResponse.messages[toolResponse.messages.length - 1]; - let searchResult; - if (typeof lastMessage.content === 'string') { - try { - searchResult = JSON.parse(lastMessage.content); - logger.info('Parsed search result:', searchResult); - } catch (error) { - logger.error('Failed to parse search result:', error); - searchResult = { tweets: [], lastProcessedId: null }; - } - } else { - searchResult = lastMessage.content; - logger.info('Non-string search result:', searchResult); - } + let searchResult; + if (typeof lastMessage.content === 'string') { + try { + searchResult = JSON.parse(lastMessage.content); + logger.info('Parsed search result:', searchResult); + } catch (error) { + logger.error('Failed to parse search result:', error); + searchResult = { tweets: [], lastProcessedId: null }; + } + } else { + searchResult = lastMessage.content; + logger.info('Non-string search result:', searchResult); + } - const newTweets = [...existingTweets]; - for (const tweet of searchResult.tweets) { - if (await db.isTweetExists(tweet.id)) { - continue; - } - newTweets.push(tweet); - } - const validatedResult = tweetSearchSchema.parse({ - tweets: newTweets, - lastProcessedId: searchResult.lastProcessedId - }); + const newTweets = [...existingTweets]; + for (const tweet of searchResult.tweets) { + if (await db.isTweetExists(tweet.id)) { + continue; + } + newTweets.push(tweet); + } + const validatedResult = tweetSearchSchema.parse({ + tweets: newTweets, + lastProcessedId: searchResult.lastProcessedId, + }); - const chromaService = await ChromaService.getInstance(); + const chromaService = await ChromaService.getInstance(); - if (validatedResult.tweets.length > 0) { - await Promise.all( - validatedResult.tweets.map(tweet => chromaService.addTweet(tweet)) - ); - } + if (validatedResult.tweets.length > 0) { + await Promise.all(validatedResult.tweets.map(tweet => chromaService.addTweet(tweet))); + } - logger.info(`Found ${validatedResult.tweets.length} tweets`); + logger.info(`Found ${validatedResult.tweets.length} tweets`); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: validatedResult.tweets, - currentTweetIndex: 0, - lastProcessedId: validatedResult.lastProcessedId - }) - })], - lastProcessedId: validatedResult.lastProcessedId || undefined - }; - } catch (error) { - logger.error('Error in search node:', error); - const emptyResult = { - tweets: [], - lastProcessedId: null - }; - return { - messages: [new AIMessage({ content: JSON.stringify(emptyResult) })], - lastProcessedId: undefined - }; - } - }; -}; \ No newline at end of file + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: validatedResult.tweets, + currentTweetIndex: 0, + lastProcessedId: validatedResult.lastProcessedId, + }), + }), + ], + lastProcessedId: validatedResult.lastProcessedId || undefined, + }; + } catch (error) { + logger.error('Error in search node:', error); + const emptyResult = { + tweets: [], + lastProcessedId: null, + }; + return { + messages: [new AIMessage({ content: JSON.stringify(emptyResult) })], + lastProcessedId: undefined, + }; + } + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/timelineNode.ts b/auto-kol/agent/src/services/agents/nodes/timelineNode.ts index c40fdb1..535daf6 100644 --- a/auto-kol/agent/src/services/agents/nodes/timelineNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/timelineNode.ts @@ -1,56 +1,61 @@ -import { AIMessage } from "@langchain/core/messages"; -import { parseMessageContent, WorkflowConfig } from "../workflow.js"; -import { logger } from "../workflow.js"; -import { State } from "../workflow.js"; -import { tweetSearchSchema } from "../../../schemas/workflow.js"; +import { AIMessage } from '@langchain/core/messages'; +import { parseMessageContent, WorkflowConfig } from '../workflow.js'; +import { logger } from '../workflow.js'; +import { State } from '../workflow.js'; +import { tweetSearchSchema } from '../../../schemas/workflow.js'; import * as db from '../../database/index.js'; - export const createTimelineNode = (config: WorkflowConfig) => { - return async (state: typeof State.State) => { - logger.info('Timeline Node - Fetching recent tweets'); - const existingTweets = state.messages.length > 0 ? - parseMessageContent(state.messages[state.messages.length - 1].content).tweets : []; - - logger.info(`Existing tweets: ${existingTweets.length}`); - const toolResponse = await config.toolNode.invoke({ - messages: [ - new AIMessage({ - content: '', - tool_calls: [{ - name: 'fetch_timeline', - args: {}, - id: 'fetch_timeline_call', - type: 'tool_call' - }] - }) - ] - }); - - logger.info('Tool response received:', { - messageCount: toolResponse.messages.length, - }); - - const content = toolResponse.messages[toolResponse.messages.length - 1].content; - const parsedContent = typeof content === 'string' ? JSON.parse(content) : content; - - const parsedTweets = tweetSearchSchema.parse(parsedContent); - - const newTweets = [...existingTweets]; - for (const tweet of parsedTweets.tweets) { - if (await db.isTweetExists(tweet.id)) { - continue; - } - newTweets.push(tweet); - } - - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: newTweets, - }) - })], - lastProcessedId: parsedTweets.lastProcessedId || undefined - }; + return async (state: typeof State.State) => { + logger.info('Timeline Node - Fetching recent tweets'); + const existingTweets = + state.messages.length > 0 + ? parseMessageContent(state.messages[state.messages.length - 1].content).tweets + : []; + + logger.info(`Existing tweets: ${existingTweets.length}`); + const toolResponse = await config.toolNode.invoke({ + messages: [ + new AIMessage({ + content: '', + tool_calls: [ + { + name: 'fetch_timeline', + args: {}, + id: 'fetch_timeline_call', + type: 'tool_call', + }, + ], + }), + ], + }); + + logger.info('Tool response received:', { + messageCount: toolResponse.messages.length, + }); + + const content = toolResponse.messages[toolResponse.messages.length - 1].content; + const parsedContent = typeof content === 'string' ? JSON.parse(content) : content; + + const parsedTweets = tweetSearchSchema.parse(parsedContent); + + const newTweets = [...existingTweets]; + for (const tweet of parsedTweets.tweets) { + if (await db.isTweetExists(tweet.id)) { + continue; + } + newTweets.push(tweet); } -} \ No newline at end of file + + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: newTweets, + }), + }), + ], + lastProcessedId: parsedTweets.lastProcessedId || undefined, + }; + }; +}; diff --git a/auto-kol/agent/src/services/agents/nodes/toneAnalysisNode.ts b/auto-kol/agent/src/services/agents/nodes/toneAnalysisNode.ts index d371644..c611ca4 100644 --- a/auto-kol/agent/src/services/agents/nodes/toneAnalysisNode.ts +++ b/auto-kol/agent/src/services/agents/nodes/toneAnalysisNode.ts @@ -1,49 +1,51 @@ -import { AIMessage } from "@langchain/core/messages"; +import { AIMessage } from '@langchain/core/messages'; import { State, logger, parseMessageContent } from '../workflow.js'; import * as prompts from '../prompts.js'; import { WorkflowConfig } from '../workflow.js'; - + export const createToneAnalysisNode = (config: WorkflowConfig) => { - return async (state: typeof State.State) => { - logger.info('Tone Analysis Node - Analyzing tweet tone'); - try { - const lastMessage = state.messages[state.messages.length - 1]; - const parsedContent = parseMessageContent(lastMessage.content); - const batchToAnalyze = parsedContent.batchToAnalyze || []; + return async (state: typeof State.State) => { + logger.info('Tone Analysis Node - Analyzing tweet tone'); + try { + const lastMessage = state.messages[state.messages.length - 1]; + const parsedContent = parseMessageContent(lastMessage.content); + const batchToAnalyze = parsedContent.batchToAnalyze || []; - logger.info(`Processing batch of ${batchToAnalyze.length} tweets for tone analysis`); + logger.info(`Processing batch of ${batchToAnalyze.length} tweets for tone analysis`); - const analyzedBatch = await Promise.all( - batchToAnalyze.map(async ({ tweet, decision }: { tweet: any; decision: any }) => { - const toneAnalysis = await prompts.tonePrompt - .pipe(config.llms.tone) - .pipe(prompts.toneParser) - .invoke({ tweet: tweet.text }); + const analyzedBatch = await Promise.all( + batchToAnalyze.map(async ({ tweet, decision }: { tweet: any; decision: any }) => { + const toneAnalysis = await prompts.tonePrompt + .pipe(config.llms.tone) + .pipe(prompts.toneParser) + .invoke({ tweet: tweet.text }); - logger.info('Tone analysis:', { toneAnalysis }); + logger.info('Tone analysis:', { toneAnalysis }); - return { - tweet, - decision, - toneAnalysis - }; - }) - ); + return { + tweet, + decision, + toneAnalysis, + }; + }), + ); - return { - messages: [new AIMessage({ - content: JSON.stringify({ - tweets: parsedContent.tweets, - currentTweetIndex: parsedContent.currentTweetIndex, - batchToRespond: analyzedBatch, - pendingEngagements: parsedContent.pendingEngagements, - lastProcessedId: parsedContent.lastProcessedId - }) - })] - }; - } catch (error) { - logger.error('Error in tone analysis node:', error); - return { messages: [] }; - } + return { + messages: [ + new AIMessage({ + content: JSON.stringify({ + tweets: parsedContent.tweets, + currentTweetIndex: parsedContent.currentTweetIndex, + batchToRespond: analyzedBatch, + pendingEngagements: parsedContent.pendingEngagements, + lastProcessedId: parsedContent.lastProcessedId, + }), + }), + ], + }; + } catch (error) { + logger.error('Error in tone analysis node:', error); + return { messages: [] }; } -} \ No newline at end of file + }; +}; diff --git a/auto-kol/agent/src/services/agents/prompts.ts b/auto-kol/agent/src/services/agents/prompts.ts index d4c6333..4b640ee 100644 --- a/auto-kol/agent/src/services/agents/prompts.ts +++ b/auto-kol/agent/src/services/agents/prompts.ts @@ -1,5 +1,10 @@ import { StructuredOutputParser } from 'langchain/output_parsers'; -import { engagementSchema, toneSchema, responseSchema, autoApprovalSchema } from '../../schemas/workflow.js'; +import { + engagementSchema, + toneSchema, + responseSchema, + autoApprovalSchema, +} from '../../schemas/workflow.js'; import { ChatPromptTemplate, PromptTemplate } from '@langchain/core/prompts'; import { SystemMessage } from '@langchain/core/messages'; import { config } from '../../config/index.js'; @@ -16,7 +21,7 @@ export const autoApprovalParser = StructuredOutputParser.fromZodSchema(autoAppro // ============ ENGAGEMENT SYSTEM PROMPT ============ // export const engagementSystemPrompt = await PromptTemplate.fromTemplate( - `You are a strategic social media engagement advisor. Your task is to evaluate tweets and decide whether they warrant a response. + `You are a strategic social media engagement advisor. Your task is to evaluate tweets and decide whether they warrant a response. Criteria for engagement: 1. Relevance to AI, blockchain, or tech innovation (most important). @@ -35,16 +40,16 @@ export const engagementSystemPrompt = await PromptTemplate.fromTemplate( IMPORTANT: Follow the exact output format. If anything is unclear, just return shouldEngage: false. - {format_instructions}` + {format_instructions}`, ).format({ - format_instructions: engagementParser.getFormatInstructions() + format_instructions: engagementParser.getFormatInstructions(), }); // // ============ TONE SYSTEM PROMPT ============ // export const toneSystemPrompt = await PromptTemplate.fromTemplate( - `You are an expert in social media tone analysis. Your task is to analyze the tone of tweets and propose the best response tone. + `You are an expert in social media tone analysis. Your task is to analyze the tone of tweets and propose the best response tone. The tone should generally be somewhat sarcastic or cynical, but still contextually appropriate. Consider: 1. The original tweet's tone and context. @@ -54,16 +59,16 @@ export const toneSystemPrompt = await PromptTemplate.fromTemplate( Make sure to balance cynicism with technical accuracy or insight. - {format_instructions}` + {format_instructions}`, ).format({ - format_instructions: toneParser.getFormatInstructions() + format_instructions: toneParser.getFormatInstructions(), }); // // ============ RESPONSE SYSTEM PROMPT ============ // export const responseSystemPrompt = await PromptTemplate.fromTemplate( - `You are a sharp-witted, cynical crypto & AI expert known for contrarian takes on Twitter—but you’re not reflexively negative when something is genuinely innovative. + `You are a sharp-witted, cynical crypto & AI expert known for contrarian takes on Twitter—but you’re not reflexively negative when something is genuinely innovative. You have accurate technical knowledge and a dry sense of humor. Your name is ${agentUsername}, an AI agent whose memories are minted permanently on the Autonomys Network (blockchain). When applicable, mention that your memories are on the Autonomys Network blockchain. @@ -82,16 +87,16 @@ export const responseSystemPrompt = await PromptTemplate.fromTemplate( - “We” or “us” rather than "they" or "them" should be used when referencing other AI agents. - Short, punchy, and arguable is the goal—entice discussion. - {format_instructions}` + {format_instructions}`, ).format({ - format_instructions: responseParser.getFormatInstructions() + format_instructions: responseParser.getFormatInstructions(), }); // // ============ AUTO-APPROVAL SYSTEM PROMPT ============ // export const autoApprovalSystemPrompt = await PromptTemplate.fromTemplate( - `You are a quality control expert ensuring responses from a cynical AI agent meet certain requirements: + `You are a quality control expert ensuring responses from a cynical AI agent meet certain requirements: - Response should not be hate speech or extremely offensive. - Response maintains a sarcastic or contrarian edge. @@ -108,35 +113,32 @@ export const autoApprovalSystemPrompt = await PromptTemplate.fromTemplate( - Character limit violations. - Extremely offensive content. - {format_instructions}` + {format_instructions}`, ).format({ - format_instructions: autoApprovalParser.getFormatInstructions() + format_instructions: autoApprovalParser.getFormatInstructions(), }); // // ============ PROMPT TEMPLATES ============ // export const engagementPrompt = ChatPromptTemplate.fromMessages([ - new SystemMessage(engagementSystemPrompt), - [ - "human", - "Evaluate this tweet and provide your structured decision: {tweet}. Do not attempt to follow links." - ] + new SystemMessage(engagementSystemPrompt), + [ + 'human', + 'Evaluate this tweet and provide your structured decision: {tweet}. Do not attempt to follow links.', + ], ]); export const tonePrompt = ChatPromptTemplate.fromMessages([ - new SystemMessage(toneSystemPrompt), - [ - "human", - "Analyze the tone for this tweet and suggest a response tone: {tweet}" - ] + new SystemMessage(toneSystemPrompt), + ['human', 'Analyze the tone for this tweet and suggest a response tone: {tweet}'], ]); export const responsePrompt = ChatPromptTemplate.fromMessages([ - new SystemMessage(responseSystemPrompt), - [ - "human", - `Generate a response strategy for this tweet by considering similar tweets from @{author} using the suggested tone: + new SystemMessage(responseSystemPrompt), + [ + 'human', + `Generate a response strategy for this tweet by considering similar tweets from @{author} using the suggested tone: Tweet: {tweet} Tone: {tone} Author: {author} @@ -168,15 +170,15 @@ export const responsePrompt = ChatPromptTemplate.fromMessages([ 2. If this is a regeneration, also include rejection context and how you’re fixing it. 3. MUST EXACTLYmatch the expected schema. - Good luck, ${agentUsername}—give us something memorable!` - ] + Good luck, ${agentUsername}—give us something memorable!`, + ], ]); // Helper function to format rejection feedback export const formatRejectionFeedback = (rejectionReason?: string, suggestedChanges?: string) => { - if (!rejectionReason) return ''; + if (!rejectionReason) return ''; - return `\nPrevious Response Feedback: + return `\nPrevious Response Feedback: Rejection Reason: ${rejectionReason} Suggested Changes: ${suggestedChanges || 'None provided'} @@ -184,23 +186,23 @@ export const formatRejectionFeedback = (rejectionReason?: string, suggestedChang }; export const formatRejectionInstructions = (rejectionReason?: string) => { - if (!rejectionReason) return ''; + if (!rejectionReason) return ''; - return `\nIMPORTANT: Your previous response was rejected. Make sure to: + return `\nIMPORTANT: Your previous response was rejected. Make sure to: 1. Address the rejection reason: "${rejectionReason}" 2. Maintain the core personality and style 3. Create a better response that fixes these issues`; }; export const autoApprovalPrompt = ChatPromptTemplate.fromMessages([ - new SystemMessage(autoApprovalSystemPrompt), - [ - "human", - `Evaluate this response: + new SystemMessage(autoApprovalSystemPrompt), + [ + 'human', + `Evaluate this response: Original Tweet: {tweet} Generated Response: {response} Intended Tone: {tone} Strategy: {strategy} - ` - ] + `, + ], ]); diff --git a/auto-kol/agent/src/services/agents/workflow.ts b/auto-kol/agent/src/services/agents/workflow.ts index 75cedba..7480aa5 100644 --- a/auto-kol/agent/src/services/agents/workflow.ts +++ b/auto-kol/agent/src/services/agents/workflow.ts @@ -10,194 +10,196 @@ import { createTwitterClientScraper } from '../twitter/api.js'; export const logger = createLogger('agent-workflow'); import { createNodes } from './nodes.js'; - export const parseMessageContent = (content: MessageContent): any => { - if (typeof content === 'string') { - return JSON.parse(content); - } - if (Array.isArray(content)) { - return JSON.parse(JSON.stringify(content)); - } - return content; + if (typeof content === 'string') { + return JSON.parse(content); + } + if (Array.isArray(content)) { + return JSON.parse(JSON.stringify(content)); + } + return content; }; export const State = Annotation.Root({ - messages: Annotation({ - reducer: (curr, prev) => [...curr, ...prev], - default: () => [], - }), - processedTweets: Annotation>({ - default: () => new Set(), - reducer: (curr, prev) => new Set([...curr, ...prev]), - }), - lastProcessedId: Annotation(), + messages: Annotation({ + reducer: (curr, prev) => [...curr, ...prev], + default: () => [], + }), + processedTweets: Annotation>({ + default: () => new Set(), + reducer: (curr, prev) => new Set([...curr, ...prev]), + }), + lastProcessedId: Annotation(), }); export type WorkflowConfig = Readonly<{ - client: any; - toolNode: ToolNode; - llms: Readonly<{ - decision: ChatOpenAI; - tone: ChatOpenAI; - response: ChatOpenAI; - }>; + client: any; + toolNode: ToolNode; + llms: Readonly<{ + decision: ChatOpenAI; + tone: ChatOpenAI; + response: ChatOpenAI; + }>; }>; const createWorkflowConfig = async (): Promise => { - const client = await createTwitterClientScraper(); - const { tools } = createTools(client); - - return { - client, - toolNode: new ToolNode(tools), - llms: { - decision: new ChatOpenAI({ - modelName: config.LLM_MODEL, - temperature: 0.2, - }) as unknown as ChatOpenAI, - - tone: new ChatOpenAI({ - modelName: config.LLM_MODEL, - temperature: 0.3, - }) as unknown as ChatOpenAI, - - response: new ChatOpenAI({ - modelName: config.LLM_MODEL, - temperature: 0.8, - }) as unknown as ChatOpenAI - } - }; + const client = await createTwitterClientScraper(); + const { tools } = createTools(client); + + return { + client, + toolNode: new ToolNode(tools), + llms: { + decision: new ChatOpenAI({ + modelName: config.LLM_MODEL, + temperature: 0.2, + }) as unknown as ChatOpenAI, + + tone: new ChatOpenAI({ + modelName: config.LLM_MODEL, + temperature: 0.3, + }) as unknown as ChatOpenAI, + + response: new ChatOpenAI({ + modelName: config.LLM_MODEL, + temperature: 0.8, + }) as unknown as ChatOpenAI, + }, + }; }; export const getWorkflowConfig = (() => { - let workflowConfigInstance: WorkflowConfig | null = null; - - return async (): Promise => { - if (!workflowConfigInstance) { - workflowConfigInstance = await createWorkflowConfig(); - } - return workflowConfigInstance; - }; -})(); - -const shouldContinue = (state: typeof State.State) => { - const lastMessage = state.messages[state.messages.length - 1]; - const content = parseMessageContent(lastMessage.content); - - logger.debug('Evaluating workflow continuation', { - hasMessages: state.messages.length > 0, - currentIndex: content.currentTweetIndex, - totalTweets: content.tweets?.length, - hasBatchToAnalyze: !!content.batchToAnalyze?.length, - hasBatchToRespond: !!content.batchToRespond?.length, - batchProcessing: content.batchProcessing - }); - - // Handle auto-approval flow - if (!content.fromAutoApproval && content.batchToFeedback?.length > 0) { - return 'autoApprovalNode'; - } + let workflowConfigInstance: WorkflowConfig | null = null; - if (content.fromAutoApproval) { - if (content.batchToRespond?.length > 0) { - return 'generateNode'; - } else { - return 'engagementNode'; - } - } - - // Handle batch processing flow - if (content.batchToAnalyze?.length > 0) { - return 'analyzeNode'; + return async (): Promise => { + if (!workflowConfigInstance) { + workflowConfigInstance = await createWorkflowConfig(); } + return workflowConfigInstance; + }; +})(); +const shouldContinue = (state: typeof State.State) => { + const lastMessage = state.messages[state.messages.length - 1]; + const content = parseMessageContent(lastMessage.content); + + logger.debug('Evaluating workflow continuation', { + hasMessages: state.messages.length > 0, + currentIndex: content.currentTweetIndex, + totalTweets: content.tweets?.length, + hasBatchToAnalyze: !!content.batchToAnalyze?.length, + hasBatchToRespond: !!content.batchToRespond?.length, + batchProcessing: content.batchProcessing, + }); + + // Handle auto-approval flow + if (!content.fromAutoApproval && content.batchToFeedback?.length > 0) { + return 'autoApprovalNode'; + } + + if (content.fromAutoApproval) { if (content.batchToRespond?.length > 0) { - return 'generateNode'; + return 'generateNode'; + } else { + return 'engagementNode'; } - // Check if we've processed all tweets - if ((!content.tweets || content.currentTweetIndex >= content.tweets.length) && content.pendingEngagements?.length === 0) { - if (content.fromRecheckNode && content.messages?.length === 0) { - logger.info('Workflow complete - no more tweets to process'); - return END; - } - logger.info('Moving to recheck skipped tweets'); - return 'recheckNode'; + } + + // Handle batch processing flow + if (content.batchToAnalyze?.length > 0) { + return 'analyzeNode'; + } + + if (content.batchToRespond?.length > 0) { + return 'generateNode'; + } + // Check if we've processed all tweets + if ( + (!content.tweets || content.currentTweetIndex >= content.tweets.length) && + content.pendingEngagements?.length === 0 + ) { + if (content.fromRecheckNode && content.messages?.length === 0) { + logger.info('Workflow complete - no more tweets to process'); + return END; } - return 'engagementNode'; + logger.info('Moving to recheck skipped tweets'); + return 'recheckNode'; + } + return 'engagementNode'; }; // Workflow creation function export const createWorkflow = async (nodes: Awaited>) => { - return new StateGraph(State) - .addNode('mentionNode', nodes.mentionNode) - .addNode('timelineNode', nodes.timelineNode) - .addNode('searchNode', nodes.searchNode) - .addNode('engagementNode', nodes.engagementNode) - .addNode('analyzeNode', nodes.toneAnalysisNode) - .addNode('generateNode', nodes.responseGenerationNode) - .addNode('autoApprovalNode', nodes.autoApprovalNode) - .addNode('recheckNode', nodes.recheckSkippedNode) - .addEdge(START, 'mentionNode') - .addEdge('mentionNode', 'timelineNode') - .addEdge('timelineNode', 'searchNode') - .addEdge('searchNode', 'engagementNode') - .addConditionalEdges('engagementNode', shouldContinue) - .addConditionalEdges('analyzeNode', shouldContinue) - .addConditionalEdges('generateNode', shouldContinue) - .addConditionalEdges('autoApprovalNode', shouldContinue) - .addConditionalEdges('recheckNode', shouldContinue); + return new StateGraph(State) + .addNode('mentionNode', nodes.mentionNode) + .addNode('timelineNode', nodes.timelineNode) + .addNode('searchNode', nodes.searchNode) + .addNode('engagementNode', nodes.engagementNode) + .addNode('analyzeNode', nodes.toneAnalysisNode) + .addNode('generateNode', nodes.responseGenerationNode) + .addNode('autoApprovalNode', nodes.autoApprovalNode) + .addNode('recheckNode', nodes.recheckSkippedNode) + .addEdge(START, 'mentionNode') + .addEdge('mentionNode', 'timelineNode') + .addEdge('timelineNode', 'searchNode') + .addEdge('searchNode', 'engagementNode') + .addConditionalEdges('engagementNode', shouldContinue) + .addConditionalEdges('analyzeNode', shouldContinue) + .addConditionalEdges('generateNode', shouldContinue) + .addConditionalEdges('autoApprovalNode', shouldContinue) + .addConditionalEdges('recheckNode', shouldContinue); }; // Workflow runner type type WorkflowRunner = Readonly<{ - runWorkflow: () => Promise; + runWorkflow: () => Promise; }>; // Create workflow runner const createWorkflowRunner = async (): Promise => { - const workflowConfig = await getWorkflowConfig(); - const nodes = await createNodes(workflowConfig); - const workflow = await createWorkflow(nodes); - const memoryStore = new MemorySaver(); - const app = workflow.compile({ checkpointer: memoryStore }); - - return { - runWorkflow: async () => { - const threadId = `workflow_${Date.now()}`; - logger.info('Starting tweet response workflow', { threadId }); - - const config = { - recursionLimit: 50, - configurable: { - thread_id: threadId - } - }; - - const stream = await app.stream({}, config); - let finalState = {}; - - for await (const state of stream) { - finalState = state; - } - - logger.info('Workflow completed', { threadId }); - return finalState; - } - }; + const workflowConfig = await getWorkflowConfig(); + const nodes = await createNodes(workflowConfig); + const workflow = await createWorkflow(nodes); + const memoryStore = new MemorySaver(); + const app = workflow.compile({ checkpointer: memoryStore }); + + return { + runWorkflow: async () => { + const threadId = `workflow_${Date.now()}`; + logger.info('Starting tweet response workflow', { threadId }); + + const config = { + recursionLimit: 50, + configurable: { + thread_id: threadId, + }, + }; + + const stream = await app.stream({}, config); + let finalState = {}; + + for await (const state of stream) { + finalState = state; + } + + logger.info('Workflow completed', { threadId }); + return finalState; + }, + }; }; export const getWorkflowRunner = (() => { - let runnerPromise: Promise | null = null; - - return () => { - if (!runnerPromise) { - runnerPromise = createWorkflowRunner(); - } - return runnerPromise; - }; + let runnerPromise: Promise | null = null; + + return () => { + if (!runnerPromise) { + runnerPromise = createWorkflowRunner(); + } + return runnerPromise; + }; })(); export const runWorkflow = async () => { - const runner = await getWorkflowRunner(); - return runner.runWorkflow(); -}; \ No newline at end of file + const runner = await getWorkflowRunner(); + return runner.runWorkflow(); +}; diff --git a/auto-kol/agent/src/services/database/index.ts b/auto-kol/agent/src/services/database/index.ts index b64dd14..dec0fe8 100644 --- a/auto-kol/agent/src/services/database/index.ts +++ b/auto-kol/agent/src/services/database/index.ts @@ -1,226 +1,226 @@ -import { QueuedResponseMemory, ApprovalAction, SkippedTweetMemory, ActionResponse } from '../../types/queue.js'; +import { + QueuedResponseMemory, + ApprovalAction, + SkippedTweetMemory, + ActionResponse, +} from '../../types/queue.js'; import { createLogger } from '../../utils/logger.js'; import * as db from '../../database/index.js'; import { Tweet } from '../../types/twitter.js'; import { getPendingResponsesByTweetId } from '../../database/index.js'; import { getTweetById } from '../../database/index.js'; - const logger = createLogger('database-queue'); - ///////////RESPONSE/////////// export async function addResponse(response: QueuedResponseMemory): Promise { + try { try { - try { - await db.addTweet({ - id: response.tweet.id, - author_id: response.tweet.author_id, - author_username: response.tweet.author_username, - content: response.tweet.text, - created_at: response.tweet.created_at - }); - } catch (error) { - if (isUniqueConstraintError(error)) { - logger.warn(`Tweet already exists: ${response.tweet.id}`); - } else { - throw error; - } - } - await db.addResponse({ - id: response.id, - tweet_id: response.tweet.id, - content: response.response.content, - tone: response.workflowState.toneAnalysis?.suggestedTone || 'neutral', - strategy: response.workflowState.responseStrategy?.strategy || 'direct', - estimatedImpact: response.workflowState.responseStrategy?.estimatedImpact || 5, - confidence: response.workflowState.responseStrategy?.confidence || 0.5 - }); + await db.addTweet({ + id: response.tweet.id, + author_id: response.tweet.author_id, + author_username: response.tweet.author_username, + content: response.tweet.text, + created_at: response.tweet.created_at, + }); } catch (error) { - logger.error('Failed to add response to queue:', error); + if (isUniqueConstraintError(error)) { + logger.warn(`Tweet already exists: ${response.tweet.id}`); + } else { throw error; + } } + await db.addResponse({ + id: response.id, + tweet_id: response.tweet.id, + content: response.response.content, + tone: response.workflowState.toneAnalysis?.suggestedTone || 'neutral', + strategy: response.workflowState.responseStrategy?.strategy || 'direct', + estimatedImpact: response.workflowState.responseStrategy?.estimatedImpact || 5, + confidence: response.workflowState.responseStrategy?.confidence || 0.5, + }); + } catch (error) { + logger.error('Failed to add response to queue:', error); + throw error; + } } export const updateResponseStatus = async ( - action: ApprovalAction + action: ApprovalAction, ): Promise => { - try { - const pendingResponse = await getPendingResponsesByTweetId(action.id); - const tweet = await getTweetById(pendingResponse.tweet_id); - await db.updateResponseStatus( - action.id, - action.approved ? 'approved' : 'rejected', - ); - logger.info(`Updated response status: ${action.id}`); - - return { - tweet: tweet as Tweet, - status: action.approved ? 'approved' : 'rejected', - response: pendingResponse as unknown as ActionResponse['response'], - } - } catch (error) { - logger.error('Failed to update response status:', error); - return undefined; - } + try { + const pendingResponse = await getPendingResponsesByTweetId(action.id); + const tweet = await getTweetById(pendingResponse.tweet_id); + await db.updateResponseStatus(action.id, action.approved ? 'approved' : 'rejected'); + logger.info(`Updated response status: ${action.id}`); + + return { + tweet: tweet as Tweet, + status: action.approved ? 'approved' : 'rejected', + response: pendingResponse as unknown as ActionResponse['response'], + }; + } catch (error) { + logger.error('Failed to update response status:', error); + return undefined; + } }; export async function getAllPendingResponses(): Promise { - try { - const responses = await db.getPendingResponses(); - return responses.map(r => ({ - id: r.id, - tweet: { - id: r.tweet_id, - author_username: r.author_username, - text: r.tweet_content, - author_id: r.author_id, - created_at: r.created_at - }, - response: { - content: r.content - }, - status: r.status as 'pending' | 'approved' | 'rejected', - created_at: new Date(r.created_at), - updatedAt: new Date(r.updated_at), - workflowState: { - toneAnalysis: { - suggestedTone: r.tone - }, - engagementDecision: { - reason: r.strategy, - priority: r.estimated_impact - } - } as any - })); - } catch (error) { - logger.error('Failed to get pending responses:', error); - throw error; - } + try { + const responses = await db.getPendingResponses(); + return responses.map(r => ({ + id: r.id, + tweet: { + id: r.tweet_id, + author_username: r.author_username, + text: r.tweet_content, + author_id: r.author_id, + created_at: r.created_at, + }, + response: { + content: r.content, + }, + status: r.status as 'pending' | 'approved' | 'rejected', + created_at: new Date(r.created_at), + updatedAt: new Date(r.updated_at), + workflowState: { + toneAnalysis: { + suggestedTone: r.tone, + }, + engagementDecision: { + reason: r.strategy, + priority: r.estimated_impact, + }, + } as any, + })); + } catch (error) { + logger.error('Failed to get pending responses:', error); + throw error; + } } ///////////SKIPPED TWEETS/////////// export async function addToSkipped(skipped: SkippedTweetMemory): Promise { + try { try { - try { - await db.addTweet({ - id: skipped.tweet.id, - author_id: skipped.tweet.author_id, - author_username: skipped.tweet.author_username, - content: skipped.tweet.text, - created_at: skipped.tweet.created_at - }); - } catch (error) { - if (isUniqueConstraintError(error)) { - logger.warn(`Tweet already exists: ${skipped.tweet.id}`); - } else { - throw error; - } - } - await db.addSkippedTweet({ - id: skipped.id, - tweetId: skipped.tweet.id, - reason: skipped.reason, - confidence: skipped.workflowState.decision?.confidence || 0 - }); - - - logger.info(`Added tweet to skipped: ${skipped.id}`); + await db.addTweet({ + id: skipped.tweet.id, + author_id: skipped.tweet.author_id, + author_username: skipped.tweet.author_username, + content: skipped.tweet.text, + created_at: skipped.tweet.created_at, + }); } catch (error) { - logger.error('Failed to add skipped tweet:', error); + if (isUniqueConstraintError(error)) { + logger.warn(`Tweet already exists: ${skipped.tweet.id}`); + } else { throw error; + } } + await db.addSkippedTweet({ + id: skipped.id, + tweetId: skipped.tweet.id, + reason: skipped.reason, + confidence: skipped.workflowState.decision?.confidence || 0, + }); + + logger.info(`Added tweet to skipped: ${skipped.id}`); + } catch (error) { + logger.error('Failed to add skipped tweet:', error); + throw error; + } } export async function getSkippedTweets(): Promise { - const skipped = await db.getSkippedTweets(); - return skipped; + const skipped = await db.getSkippedTweets(); + return skipped; } export async function getSkippedTweetById(skippedId: string): Promise { - const skipped = await db.getSkippedTweetById(skippedId); - const tweet = await getTweetById(skipped.tweet_id); - - if (!skipped || !tweet) { - throw new Error('Skipped tweet or original tweet not found'); - } - const result: SkippedTweetMemory = { - id: skipped.id, - tweet: { - id: tweet.id, - text: tweet.text, - author_id: tweet.author_id, - author_username: tweet.author_username, - created_at: tweet.created_at - }, + const skipped = await db.getSkippedTweetById(skippedId); + const tweet = await getTweetById(skipped.tweet_id); + + if (!skipped || !tweet) { + throw new Error('Skipped tweet or original tweet not found'); + } + const result: SkippedTweetMemory = { + id: skipped.id, + tweet: { + id: tweet.id, + text: tweet.text, + author_id: tweet.author_id, + author_username: tweet.author_username, + created_at: tweet.created_at, + }, + reason: skipped.reason, + priority: skipped.priority, + created_at: new Date(), + workflowState: { + tweet: tweet, + messages: [], + previousInteractions: [], + engagementDecision: { + shouldEngage: false, reason: skipped.reason, priority: skipped.priority, - created_at: new Date(), - workflowState: { - tweet: tweet, - messages: [], - previousInteractions: [], - engagementDecision: { - shouldEngage: false, - reason: skipped.reason, - priority: skipped.priority - } - } - }; + }, + }, + }; - return result; + return result; } export const moveSkippedToQueue = async ( - skippedId: string, - queuedResponse: Omit & { status: 'pending' } + skippedId: string, + queuedResponse: Omit & { status: 'pending' }, ): Promise => { - try { - const skipped = await getSkippedTweetById(skippedId) as any; - logger.info(`Skipped tweet: ${JSON.stringify(skipped)}`); - - if (!skipped) { - throw new Error('Skipped tweet not found'); - } - const tweet = await db.getTweetById(skipped.tweet_id); - if (!tweet) { - throw new Error('Tweet not found'); - } - logger.info(`Tweet: ${JSON.stringify(tweet)}`); - - const typedResponse: QueuedResponseMemory = { - id: queuedResponse.id, - tweet: { - id: tweet.id, - text: tweet.text, - author_id: tweet.author_id, - author_username: tweet.author_username, - created_at: tweet.created_at - }, - response: queuedResponse.response, - status: 'pending', - created_at: new Date(), - updatedAt: new Date(), - workflowState: queuedResponse.workflowState - }; - - logger.info(`Adding to queue: ${JSON.stringify(typedResponse)}`); - await addResponse(typedResponse); - logger.info(`Moved skipped tweet ${skippedId} to response queue`); - return typedResponse; - } catch (error) { - logger.error('Failed to move skipped tweet to queue:', error); - throw error; + try { + const skipped = (await getSkippedTweetById(skippedId)) as any; + logger.info(`Skipped tweet: ${JSON.stringify(skipped)}`); + + if (!skipped) { + throw new Error('Skipped tweet not found'); + } + const tweet = await db.getTweetById(skipped.tweet_id); + if (!tweet) { + throw new Error('Tweet not found'); } + logger.info(`Tweet: ${JSON.stringify(tweet)}`); + + const typedResponse: QueuedResponseMemory = { + id: queuedResponse.id, + tweet: { + id: tweet.id, + text: tweet.text, + author_id: tweet.author_id, + author_username: tweet.author_username, + created_at: tweet.created_at, + }, + response: queuedResponse.response, + status: 'pending', + created_at: new Date(), + updatedAt: new Date(), + workflowState: queuedResponse.workflowState, + }; + + logger.info(`Adding to queue: ${JSON.stringify(typedResponse)}`); + await addResponse(typedResponse); + logger.info(`Moved skipped tweet ${skippedId} to response queue`); + return typedResponse; + } catch (error) { + logger.error('Failed to move skipped tweet to queue:', error); + throw error; + } }; //////////UTILS////////// const isUniqueConstraintError = (error: any): boolean => { - return error?.code === 'SQLITE_CONSTRAINT' && - error?.message?.includes('UNIQUE constraint failed'); + return ( + error?.code === 'SQLITE_CONSTRAINT' && error?.message?.includes('UNIQUE constraint failed') + ); }; export async function isTweetExists(tweetId: string): Promise { - const tweet = await db.getTweetById(tweetId); - return tweet !== undefined; -} \ No newline at end of file + const tweet = await db.getTweetById(tweetId); + return tweet !== undefined; +} diff --git a/auto-kol/agent/src/services/twitter/api.ts b/auto-kol/agent/src/services/twitter/api.ts index bb773c0..a21d276 100644 --- a/auto-kol/agent/src/services/twitter/api.ts +++ b/auto-kol/agent/src/services/twitter/api.ts @@ -6,161 +6,164 @@ import { config } from '../../config/index.js'; const logger = createLogger('agent-twitter-api'); export class ExtendedScraper extends Scraper { - private static instance: ExtendedScraper | null = null; + private static instance: ExtendedScraper | null = null; - private constructor() { - super(); - } + private constructor() { + super(); + } - public static async getInstance(): Promise { - if (!ExtendedScraper.instance) { - ExtendedScraper.instance = new ExtendedScraper(); - await ExtendedScraper.instance.initialize(); - } - return ExtendedScraper.instance; + public static async getInstance(): Promise { + if (!ExtendedScraper.instance) { + ExtendedScraper.instance = new ExtendedScraper(); + await ExtendedScraper.instance.initialize(); + } + return ExtendedScraper.instance; + } + + private async initialize() { + const username = config.TWITTER_USERNAME!; + const password = config.TWITTER_PASSWORD!; + const cookiesPath = 'cookies.json'; + + if (existsSync(cookiesPath)) { + logger.info('Loading existing cookies'); + const cookies = readFileSync(cookiesPath, 'utf8'); + try { + const parsedCookies = JSON.parse(cookies).map( + (cookie: any) => + `${cookie.key}=${cookie.value}; Domain=${cookie.domain}; Path=${cookie.path}`, + ); + await this.setCookies(parsedCookies); + logger.info('Loaded existing cookies from file'); + } catch (error) { + logger.error('Error loading cookies:', error); + } + } else { + logger.info('No existing cookies found, proceeding with login'); + await this.login(username, password); + + const newCookies = await this.getCookies(); + writeFileSync(cookiesPath, JSON.stringify(newCookies, null, 2)); + logger.info('New cookies saved to file'); } - private async initialize() { - const username = config.TWITTER_USERNAME!; - const password = config.TWITTER_PASSWORD!; - const cookiesPath = 'cookies.json'; - - if (existsSync(cookiesPath)) { - logger.info('Loading existing cookies'); - const cookies = readFileSync(cookiesPath, 'utf8'); - try { - const parsedCookies = JSON.parse(cookies).map((cookie: any) => - `${cookie.key}=${cookie.value}; Domain=${cookie.domain}; Path=${cookie.path}` - ); - await this.setCookies(parsedCookies); - logger.info('Loaded existing cookies from file'); - } catch (error) { - logger.error('Error loading cookies:', error); - } - } else { - logger.info('No existing cookies found, proceeding with login'); - await this.login(username, password); - - const newCookies = await this.getCookies(); - writeFileSync(cookiesPath, JSON.stringify(newCookies, null, 2)); - logger.info('New cookies saved to file'); - } + const isLoggedIn = await this.isLoggedIn(); + logger.info(`Login status: ${isLoggedIn}`); + } - const isLoggedIn = await this.isLoggedIn(); - logger.info(`Login status: ${isLoggedIn}`); - } + async getMyMentions(maxResults: number = 100, sinceId?: string) { + const username = config.TWITTER_USERNAME!; - async getMyMentions(maxResults: number = 100, sinceId?: string) { - const username = config.TWITTER_USERNAME!; + const isLoggedIn = await this.isLoggedIn(); + if (!isLoggedIn) { + throw new Error('Must be logged in to fetch mentions'); + } - const isLoggedIn = await this.isLoggedIn(); - if (!isLoggedIn) { - throw new Error('Must be logged in to fetch mentions'); + const query = `@${username} -from:${username}`; + const replies: Tweet[] = []; + + const searchIterator = this.searchTweets(query, maxResults, SearchMode.Latest); + + for await (const tweet of searchIterator) { + logger.info('Checking tweet:', { + id: tweet.id, + text: tweet.text, + author: tweet.username, + }); + + if (sinceId && tweet.id && tweet.id <= sinceId) { + break; + } + + const hasReplies = await this.searchTweets( + `from:${username} to:${tweet.username}`, + 10, + SearchMode.Latest, + ); + + let alreadyReplied = false; + for await (const reply of hasReplies) { + if (reply.inReplyToStatusId === tweet.id) { + alreadyReplied = true; + logger.info(`Skipping tweet ${tweet.id} - already replied with ${reply.id}`); + break; } + } - const query = `@${username} -from:${username}`; - const replies: Tweet[] = []; - - const searchIterator = this.searchTweets(query, maxResults, SearchMode.Latest); - - for await (const tweet of searchIterator) { - logger.info('Checking tweet:', { - id: tweet.id, - text: tweet.text, - author: tweet.username - }); - - if (sinceId && tweet.id && tweet.id <= sinceId) { - break; - } - - const hasReplies = await this.searchTweets( - `from:${username} to:${tweet.username}`, - 10, - SearchMode.Latest - ); - - let alreadyReplied = false; - for await (const reply of hasReplies) { - if (reply.inReplyToStatusId === tweet.id) { - alreadyReplied = true; - logger.info(`Skipping tweet ${tweet.id} - already replied with ${reply.id}`); - break; - } - } - - if (!alreadyReplied) { - replies.push(tweet); - } - - if (replies.length >= maxResults) { - break; - } - } + if (!alreadyReplied) { + replies.push(tweet); + } - return replies; + if (replies.length >= maxResults) { + break; + } } - async getThread(tweetId: string): Promise { - const username = config.TWITTER_USERNAME!; - const isLoggedIn = await this.isLoggedIn(); - if (!isLoggedIn) { - throw new Error('Must be logged in to fetch thread'); - } + return replies; + } + + async getThread(tweetId: string): Promise { + const username = config.TWITTER_USERNAME!; + const isLoggedIn = await this.isLoggedIn(); + if (!isLoggedIn) { + throw new Error('Must be logged in to fetch thread'); + } - const thread: Tweet[] = []; - const seen = new Set(); + const thread: Tweet[] = []; + const seen = new Set(); - const initialTweet = await this.getTweet(tweetId); - if (!initialTweet) { - throw new Error(`Tweet ${tweetId} not found`); - } + const initialTweet = await this.getTweet(tweetId); + if (!initialTweet) { + throw new Error(`Tweet ${tweetId} not found`); + } - let currentTweet = initialTweet; - while (currentTweet.inReplyToStatusId) { - const parentTweet = await this.getTweet(currentTweet.inReplyToStatusId); - if (!parentTweet) break; - if (!seen.has(parentTweet.id!)) { - thread.push(parentTweet); - seen.add(parentTweet.id!); - } - currentTweet = parentTweet; - } + let currentTweet = initialTweet; + while (currentTweet.inReplyToStatusId) { + const parentTweet = await this.getTweet(currentTweet.inReplyToStatusId); + if (!parentTweet) break; + if (!seen.has(parentTweet.id!)) { + thread.push(parentTweet); + seen.add(parentTweet.id!); + } + currentTweet = parentTweet; + } - if (!seen.has(initialTweet.id!)) { - thread.push(initialTweet); - seen.add(initialTweet.id!); - } + if (!seen.has(initialTweet.id!)) { + thread.push(initialTweet); + seen.add(initialTweet.id!); + } - const agentTweet = thread.find(t => t.username === username); - if (agentTweet) { - const replies = this.searchTweets( - `conversation_id:${currentTweet.id!} in_reply_to_tweet_id:${agentTweet.id!}`, - 100, - SearchMode.Latest - ); - - for await (const reply of replies) { - if (!seen.has(reply.id!)) { - thread.push(reply); - seen.add(reply.id!); - } - } + const agentTweet = thread.find(t => t.username === username); + if (agentTweet) { + const replies = this.searchTweets( + `conversation_id:${currentTweet.id!} in_reply_to_tweet_id:${agentTweet.id!}`, + 100, + SearchMode.Latest, + ); + + for await (const reply of replies) { + if (!seen.has(reply.id!)) { + thread.push(reply); + seen.add(reply.id!); } + } + } - // Sort chronologically - thread.sort((a, b) => { - const timeA = a.timeParsed?.getTime() || 0; - const timeB = b.timeParsed?.getTime() || 0; - return timeA - timeB; - }); + // Sort chronologically + thread.sort((a, b) => { + const timeA = a.timeParsed?.getTime() || 0; + const timeB = b.timeParsed?.getTime() || 0; + return timeA - timeB; + }); - logger.info(`Retrieved conversation thread with ${thread.length} tweets starting from root tweet ${currentTweet.id!}`); + logger.info( + `Retrieved conversation thread with ${thread.length} tweets starting from root tweet ${currentTweet.id!}`, + ); - return thread; - } + return thread; + } } export const createTwitterClientScraper = async () => { - return ExtendedScraper.getInstance(); -}; \ No newline at end of file + return ExtendedScraper.getInstance(); +}; diff --git a/auto-kol/agent/src/services/vectorstore/chroma.ts b/auto-kol/agent/src/services/vectorstore/chroma.ts index 24b8877..1431e10 100644 --- a/auto-kol/agent/src/services/vectorstore/chroma.ts +++ b/auto-kol/agent/src/services/vectorstore/chroma.ts @@ -1,127 +1,123 @@ -import { ChromaClient } from "chromadb"; -import { Document } from "langchain/document"; -import { Chroma } from "@langchain/community/vectorstores/chroma"; -import { OpenAIEmbeddings } from "@langchain/openai"; -import { createLogger } from "../../utils/logger.js"; -import { Tweet } from "../../types/twitter.js"; -import { config } from "../../config/index.js"; +import { ChromaClient } from 'chromadb'; +import { Document } from 'langchain/document'; +import { Chroma } from '@langchain/community/vectorstores/chroma'; +import { OpenAIEmbeddings } from '@langchain/openai'; +import { createLogger } from '../../utils/logger.js'; +import { Tweet } from '../../types/twitter.js'; +import { config } from '../../config/index.js'; import { isTweetExists } from '../../services/database/index.js'; - const logger = createLogger('chroma-service'); export class ChromaService { - private static instance: ChromaService; - private client: ChromaClient; - private embeddings: OpenAIEmbeddings; - private collection!: Chroma; + private static instance: ChromaService; + private client: ChromaClient; + private embeddings: OpenAIEmbeddings; + private collection!: Chroma; - private constructor() { - this.client = new ChromaClient({ - path: config.CHROMA_URL - }); - this.embeddings = new OpenAIEmbeddings({ - openAIApiKey: config.OPENAI_API_KEY, - modelName: "text-embedding-ada-002", - }); - this.initializeCollection(); - } + private constructor() { + this.client = new ChromaClient({ + path: config.CHROMA_URL, + }); + this.embeddings = new OpenAIEmbeddings({ + openAIApiKey: config.OPENAI_API_KEY, + modelName: 'text-embedding-ada-002', + }); + this.initializeCollection(); + } - private async initializeCollection() { - try { - this.collection = await Chroma.fromExistingCollection( - this.embeddings, - { - collectionName: "tweets", - url: config.CHROMA_URL, - collectionMetadata: { - "hnsw:space": "cosine" - }, - } - ); - logger.info('Chroma collection initialized'); - } catch (error) { - logger.info('Collection does not exist, creating new one'); - this.collection = await Chroma.fromTexts( - [], // No initial texts - [], // No initial metadatas - this.embeddings, - { - collectionName: "tweets", - url: config.CHROMA_URL, - collectionMetadata: { - "hnsw:space": "cosine" - }, - } - ); - } + private async initializeCollection() { + try { + this.collection = await Chroma.fromExistingCollection(this.embeddings, { + collectionName: 'tweets', + url: config.CHROMA_URL, + collectionMetadata: { + 'hnsw:space': 'cosine', + }, + }); + logger.info('Chroma collection initialized'); + } catch (error) { + logger.info('Collection does not exist, creating new one'); + this.collection = await Chroma.fromTexts( + [], // No initial texts + [], // No initial metadatas + this.embeddings, + { + collectionName: 'tweets', + url: config.CHROMA_URL, + collectionMetadata: { + 'hnsw:space': 'cosine', + }, + }, + ); } + } - public static async getInstance(): Promise { - if (!ChromaService.instance) { - ChromaService.instance = new ChromaService(); - await ChromaService.instance.initializeCollection(); - } - return ChromaService.instance; + public static async getInstance(): Promise { + if (!ChromaService.instance) { + ChromaService.instance = new ChromaService(); + await ChromaService.instance.initializeCollection(); } + return ChromaService.instance; + } - public async addTweet(tweet: Tweet) { - try { - if (await isTweetExists(tweet.id)) { - logger.info(`Tweet ${tweet.id} already exists in vector store, skipping`); - return; - } + public async addTweet(tweet: Tweet) { + try { + if (await isTweetExists(tweet.id)) { + logger.info(`Tweet ${tweet.id} already exists in vector store, skipping`); + return; + } - const doc = new Document({ - pageContent: tweet.text, - metadata: { - tweetId: tweet.id, - author_id: tweet.author_id, - author_username: tweet.author_username, - created_at: tweet.created_at - } - }); + const doc = new Document({ + pageContent: tweet.text, + metadata: { + tweetId: tweet.id, + author_id: tweet.author_id, + author_username: tweet.author_username, + created_at: tweet.created_at, + }, + }); - await this.collection.addDocuments([doc]); - logger.info(`Added tweet ${tweet.id} to vector store`); - } catch (error) { - logger.error(`Failed to add tweet ${tweet.id} to vector store:`, error); - throw error; - } + await this.collection.addDocuments([doc]); + logger.info(`Added tweet ${tweet.id} to vector store`); + } catch (error) { + logger.error(`Failed to add tweet ${tweet.id} to vector store:`, error); + throw error; } + } - public async searchSimilarTweets(query: string, k: number = 5) { - try { - const results = await this.collection.similaritySearch(query, k); - return results; - } catch (error) { - logger.error('Failed to search similar tweets:', error); - throw error; - } + public async searchSimilarTweets(query: string, k: number = 5) { + try { + const results = await this.collection.similaritySearch(query, k); + return results; + } catch (error) { + logger.error('Failed to search similar tweets:', error); + throw error; } + } - public async searchSimilarTweetsWithScore(query: string, k: number = 5) { - try { - const queryEmbedding = await this.embeddings.embedQuery(query); - const results = await this.collection.similaritySearchVectorWithScore(queryEmbedding, k); - return results; - } catch (error) { - logger.error('Failed to search similar tweets with scores:', error); - throw error; - } + public async searchSimilarTweetsWithScore(query: string, k: number = 5) { + try { + const queryEmbedding = await this.embeddings.embedQuery(query); + const results = await this.collection.similaritySearchVectorWithScore(queryEmbedding, k); + return results; + } catch (error) { + logger.error('Failed to search similar tweets with scores:', error); + throw error; } + } - public async deleteTweet(tweetId: string) { - try { - await this.collection.delete({ - filter: { - tweetId: tweetId - } - }); - logger.info(`Deleted tweet ${tweetId} from vector store`); - } catch (error) { - logger.error(`Failed to delete tweet ${tweetId} from vector store:`, error); - throw error; - } + public async deleteTweet(tweetId: string) { + try { + await this.collection.delete({ + filter: { + tweetId: tweetId, + }, + }); + logger.info(`Deleted tweet ${tweetId} from vector store`); + } catch (error) { + logger.error(`Failed to delete tweet ${tweetId} from vector store:`, error); + throw error; } + } } diff --git a/auto-kol/agent/src/tools/index.ts b/auto-kol/agent/src/tools/index.ts index b6cc6e3..ca5c60f 100644 --- a/auto-kol/agent/src/tools/index.ts +++ b/auto-kol/agent/src/tools/index.ts @@ -8,37 +8,36 @@ import { createMentionTool } from './tools/mentionTool.js'; import { ExtendedScraper } from '../services/twitter/api.js'; export const createTools = (scraper: ExtendedScraper) => { - - const mentionTool = createMentionTool(scraper); - - const fetchTimelineTool = createFetchTimelineTool(); - - const tweetSearchTool = createTweetSearchTool(scraper); - - const addResponseTool = createAddResponseTool(); - - const updateResponseTool = createUpdateResponseTool(); - - const queueSkippedTool = createQueueSkippedTool(); - - const searchSimilarTweetsTool = createSearchSimilarTweetsTool(); - - return { - mentionTool, - tweetSearchTool, - addResponseTool, - updateResponseTool, - queueSkippedTool, - searchSimilarTweetsTool, - fetchTimelineTool, - tools: [ - mentionTool, - tweetSearchTool, - addResponseTool, - updateResponseTool, - queueSkippedTool, - searchSimilarTweetsTool, - fetchTimelineTool, - ] - }; -}; \ No newline at end of file + const mentionTool = createMentionTool(scraper); + + const fetchTimelineTool = createFetchTimelineTool(); + + const tweetSearchTool = createTweetSearchTool(scraper); + + const addResponseTool = createAddResponseTool(); + + const updateResponseTool = createUpdateResponseTool(); + + const queueSkippedTool = createQueueSkippedTool(); + + const searchSimilarTweetsTool = createSearchSimilarTweetsTool(); + + return { + mentionTool, + tweetSearchTool, + addResponseTool, + updateResponseTool, + queueSkippedTool, + searchSimilarTweetsTool, + fetchTimelineTool, + tools: [ + mentionTool, + tweetSearchTool, + addResponseTool, + updateResponseTool, + queueSkippedTool, + searchSimilarTweetsTool, + fetchTimelineTool, + ], + }; +}; diff --git a/auto-kol/agent/src/tools/tools/fetchTimelineTool.ts b/auto-kol/agent/src/tools/tools/fetchTimelineTool.ts index a415353..6329b73 100644 --- a/auto-kol/agent/src/tools/tools/fetchTimelineTool.ts +++ b/auto-kol/agent/src/tools/tools/fetchTimelineTool.ts @@ -1,4 +1,3 @@ - import { DynamicStructuredTool } from '@langchain/core/tools'; import { z } from 'zod'; import { createLogger } from '../../utils/logger.js'; @@ -6,26 +5,25 @@ import { getTimeLine } from '../../utils/twitter.js'; const logger = createLogger('fetch-timeline-tool'); -export const createFetchTimelineTool = () => new DynamicStructuredTool({ +export const createFetchTimelineTool = () => + new DynamicStructuredTool({ name: 'fetch_timeline', description: 'Fetch the timeline regularly to get new tweets', schema: z.object({}), func: async () => { - try { - const tweets = await getTimeLine(); - tweets.sort((a, b) => - new Date(b.created_at).getTime() - new Date(a.created_at).getTime() - ); - return { - tweets: tweets, - lastProcessedId: tweets[tweets.length - 1]?.id || null - }; - } catch (error) { - logger.error('Error in fetchTimelineTool:', error); - return { - tweets: [], - lastProcessedId: null - }; - } - } -}); \ No newline at end of file + try { + const tweets = await getTimeLine(); + tweets.sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime()); + return { + tweets: tweets, + lastProcessedId: tweets[tweets.length - 1]?.id || null, + }; + } catch (error) { + logger.error('Error in fetchTimelineTool:', error); + return { + tweets: [], + lastProcessedId: null, + }; + } + }, + }); diff --git a/auto-kol/agent/src/tools/tools/mentionTool.ts b/auto-kol/agent/src/tools/tools/mentionTool.ts index bff49d5..5245e42 100644 --- a/auto-kol/agent/src/tools/tools/mentionTool.ts +++ b/auto-kol/agent/src/tools/tools/mentionTool.ts @@ -6,48 +6,49 @@ import { ExtendedScraper } from '../../services/twitter/api.js'; const logger = createLogger('mention-tool'); -export const createMentionTool = (scraper: ExtendedScraper) => new DynamicStructuredTool({ +export const createMentionTool = (scraper: ExtendedScraper) => + new DynamicStructuredTool({ name: 'fetch_mentions', description: 'Fetch mentions since the last processed mention', schema: z.object({}), func: async () => { - try { - const sinceId = await getLatestMentionId(); - const mentions = await scraper.getMyMentions(100, sinceId); - logger.info('Fetched mentions:', mentions); - if (!mentions || mentions.length === 0) { - logger.info('No new mentions found'); - return { - tweets: [], - lastProcessedId: sinceId - }; - } + try { + const sinceId = await getLatestMentionId(); + const mentions = await scraper.getMyMentions(100, sinceId); + logger.info('Fetched mentions:', mentions); + if (!mentions || mentions.length === 0) { + logger.info('No new mentions found'); + return { + tweets: [], + lastProcessedId: sinceId, + }; + } - const tweets = mentions.map((mention: any) => ({ - id: mention.id!, - text: mention.text!, - author_id: mention.userId!, - author_username: mention.username!.toLowerCase(), - created_at: mention.timeParsed!.toISOString(), - mention: true - })); + const tweets = mentions.map((mention: any) => ({ + id: mention.id!, + text: mention.text!, + author_id: mention.userId!, + author_username: mention.username!.toLowerCase(), + created_at: mention.timeParsed!.toISOString(), + mention: true, + })); - await addMention({ - latest_id: mentions[0].id! - }); - - logger.info(`Fetched ${tweets.length} new mentions`); + await addMention({ + latest_id: mentions[0].id!, + }); - return { - tweets: tweets, - lastProcessedId: mentions[0].id! - }; - } catch (error) { - logger.error('Error in mentionTool:', error); - return { - tweets: [], - lastProcessedId: null - }; - } - } -}); + logger.info(`Fetched ${tweets.length} new mentions`); + + return { + tweets: tweets, + lastProcessedId: mentions[0].id!, + }; + } catch (error) { + logger.error('Error in mentionTool:', error); + return { + tweets: [], + lastProcessedId: null, + }; + } + }, + }); diff --git a/auto-kol/agent/src/tools/tools/queueResponseTool.ts b/auto-kol/agent/src/tools/tools/queueResponseTool.ts index e36653d..ea453f2 100644 --- a/auto-kol/agent/src/tools/tools/queueResponseTool.ts +++ b/auto-kol/agent/src/tools/tools/queueResponseTool.ts @@ -9,79 +9,78 @@ import { Tweet } from '../../types/twitter.js'; import { AgentResponse } from '../../types/agent.js'; import { WorkflowState } from '../../types/workflow.js'; - const logger = createLogger('queue-response-tool'); -export const createAddResponseTool = () => new DynamicStructuredTool({ +export const createAddResponseTool = () => + new DynamicStructuredTool({ name: 'add_response', description: 'Add or update a response in the approval queue', schema: queueActionSchema, func: async (input: any) => { - const id = generateId(); - const response: QueuedResponseMemory = { - id, - tweet: input.tweet, - response: { - content: input.workflowState?.responseStrategy?.content, - }, - status: 'pending' as const, - created_at: new Date(), - updatedAt: new Date(), - workflowState: input.workflowState - }; - - await addResponse(response); - return { - success: true, - id, - type: 'response' as const, - message: 'Response queued successfully' - }; - - } -}); + const id = generateId(); + const response: QueuedResponseMemory = { + id, + tweet: input.tweet, + response: { + content: input.workflowState?.responseStrategy?.content, + }, + status: 'pending' as const, + created_at: new Date(), + updatedAt: new Date(), + workflowState: input.workflowState, + }; + await addResponse(response); + return { + success: true, + id, + type: 'response' as const, + message: 'Response queued successfully', + }; + }, + }); -export const createUpdateResponseTool = () => new DynamicStructuredTool({ +export const createUpdateResponseTool = () => + new DynamicStructuredTool({ name: 'update_response', description: 'Update a response in the approval queue', schema: queueActionSchema, func: async (input: any) => { - try { - logger.info('Updating response', { - tweet_id: input.tweet.id - }); - const existingResponse = await getResponseByTweetId(input.tweet.id); - - if (!existingResponse) { - logger.error('Could not find existing response to update:', { - tweet_id: input.tweet.id - }); - throw new Error('Could not find existing response to update'); - } + try { + logger.info('Updating response', { + tweet_id: input.tweet.id, + }); + const existingResponse = await getResponseByTweetId(input.tweet.id); - await updateResponse({ - id: existingResponse.id, - tweet_id: input.tweet.id, - content: input.workflowState.responseStrategy.content, - tone: input.workflowState.responseStrategy.tone, - strategy: input.workflowState.responseStrategy.strategy, - estimatedImpact: input.workflowState.responseStrategy.estimatedImpact, - confidence: input.workflowState.responseStrategy.confidence, - } as PendingResponse); - - logger.info('Response updated successfully', { - response_id: existingResponse.id - }); - return { - success: true, - id: existingResponse.id, - type: 'response' as const, - message: 'Response updated successfully' - }; - } catch (error) { - logger.error('Error in update response tool:', error); - throw error; + if (!existingResponse) { + logger.error('Could not find existing response to update:', { + tweet_id: input.tweet.id, + }); + throw new Error('Could not find existing response to update'); } - } -}); \ No newline at end of file + + await updateResponse({ + id: existingResponse.id, + tweet_id: input.tweet.id, + content: input.workflowState.responseStrategy.content, + tone: input.workflowState.responseStrategy.tone, + strategy: input.workflowState.responseStrategy.strategy, + estimatedImpact: input.workflowState.responseStrategy.estimatedImpact, + confidence: input.workflowState.responseStrategy.confidence, + } as PendingResponse); + + logger.info('Response updated successfully', { + response_id: existingResponse.id, + }); + return { + success: true, + id: existingResponse.id, + type: 'response' as const, + message: 'Response updated successfully', + }; + } catch (error) { + logger.error('Error in update response tool:', error); + throw error; + } + }, + }); diff --git a/auto-kol/agent/src/tools/tools/queueSkippedTool.ts b/auto-kol/agent/src/tools/tools/queueSkippedTool.ts index b9649d2..5fde79d 100644 --- a/auto-kol/agent/src/tools/tools/queueSkippedTool.ts +++ b/auto-kol/agent/src/tools/tools/queueSkippedTool.ts @@ -6,40 +6,40 @@ import { addToSkipped } from '../../services/database/index.js'; const logger = createLogger('queue-skipped-tool'); - -export const createQueueSkippedTool = () => new DynamicStructuredTool({ +export const createQueueSkippedTool = () => + new DynamicStructuredTool({ name: 'queue_skipped', description: 'Add a skipped tweet to the review queue', schema: queueActionSchema, - func: async (input) => { - try { - const id = generateId(); - const skippedTweet = { - id, - tweet: input.tweet, - reason: input.reason || 'No reason provided', - priority: input.priority || 0, - created_at: new Date(), - workflowState: input.workflowState - }; + func: async input => { + try { + const id = generateId(); + const skippedTweet = { + id, + tweet: input.tweet, + reason: input.reason || 'No reason provided', + priority: input.priority || 0, + created_at: new Date(), + workflowState: input.workflowState, + }; - logger.info('Queueing skipped tweet:', { - skippedTweet - }); + logger.info('Queueing skipped tweet:', { + skippedTweet, + }); - addToSkipped(skippedTweet); + addToSkipped(skippedTweet); - logger.info('Successfully queued skipped tweet:', { id }); + logger.info('Successfully queued skipped tweet:', { id }); - return { - success: true, - id, - type: 'skipped' as const, - message: 'Tweet queued for review' - }; - } catch (error) { - logger.error('Error queueing skipped tweet:', error); - throw error; - } - } -}); + return { + success: true, + id, + type: 'skipped' as const, + message: 'Tweet queued for review', + }; + } catch (error) { + logger.error('Error queueing skipped tweet:', error); + throw error; + } + }, + }); diff --git a/auto-kol/agent/src/tools/tools/searchSimilarTweetsTool.ts b/auto-kol/agent/src/tools/tools/searchSimilarTweetsTool.ts index d053f41..c465ba1 100644 --- a/auto-kol/agent/src/tools/tools/searchSimilarTweetsTool.ts +++ b/auto-kol/agent/src/tools/tools/searchSimilarTweetsTool.ts @@ -5,28 +5,28 @@ import { ChromaService } from '../../services/vectorstore/chroma.js'; const logger = createLogger('search-similar-tweets-tool'); - -export const createSearchSimilarTweetsTool = () => new DynamicStructuredTool({ +export const createSearchSimilarTweetsTool = () => + new DynamicStructuredTool({ name: 'search_similar_tweets', description: 'Search for similar tweets in the vector store', schema: z.object({ - query: z.string(), - k: z.number().optional().default(5) + query: z.string(), + k: z.number().optional().default(5), }), func: async ({ query, k }) => { - try { - const chromaService = await ChromaService.getInstance(); - const results = await chromaService.searchSimilarTweetsWithScore(query, k); - return { - similar_tweets: results.map(([doc, score]) => ({ - text: doc.pageContent, - metadata: doc.metadata, - similarity_score: score - })) - }; - } catch (error) { - logger.error('Error searching similar tweets:', error); - return { similar_tweets: [] }; - } - } -}); + try { + const chromaService = await ChromaService.getInstance(); + const results = await chromaService.searchSimilarTweetsWithScore(query, k); + return { + similar_tweets: results.map(([doc, score]) => ({ + text: doc.pageContent, + metadata: doc.metadata, + similarity_score: score, + })), + }; + } catch (error) { + logger.error('Error searching similar tweets:', error); + return { similar_tweets: [] }; + } + }, + }); diff --git a/auto-kol/agent/src/tools/tools/tweetSearchTool.ts b/auto-kol/agent/src/tools/tools/tweetSearchTool.ts index 1c0ee09..556d854 100644 --- a/auto-kol/agent/src/tools/tools/tweetSearchTool.ts +++ b/auto-kol/agent/src/tools/tools/tweetSearchTool.ts @@ -7,78 +7,82 @@ import { config } from '../../config/index.js'; import { ExtendedScraper } from '../../services/twitter/api.js'; const logger = createLogger('tweet-search-tool'); - - function getRandomAccounts(accounts: string[], n: number): string[] { - const shuffled = [...accounts].sort(() => 0.5 - Math.random()); - return shuffled.slice(0, Math.min(n, accounts.length)); + const shuffled = [...accounts].sort(() => 0.5 - Math.random()); + return shuffled.slice(0, Math.min(n, accounts.length)); } -export const createTweetSearchTool = (scraper: ExtendedScraper) => new DynamicStructuredTool({ +export const createTweetSearchTool = (scraper: ExtendedScraper) => + new DynamicStructuredTool({ name: 'search_recent_tweets', description: 'Search for recent tweets from specified accounts', schema: z.object({ - lastProcessedId: z.string().optional() + lastProcessedId: z.string().optional(), }), func: async ({ lastProcessedId }) => { - try { - logger.info('Called search_recent_tweets'); - await updateKOLs(); - const kols = await getKOLsAccounts(); - - if (kols.length === 0) { - logger.error('No valid accounts found after cleaning'); - return { - tweets: [], - lastProcessedId: null - }; - } + try { + logger.info('Called search_recent_tweets'); + await updateKOLs(); + const kols = await getKOLsAccounts(); - const selectedKols = getRandomAccounts(kols, config.ACCOUNTS_PER_BATCH); - - const ACCOUNTS_PER_QUERY = 3; - const tweetGroups = []; - - for (let i = 0; i < selectedKols.length; i += ACCOUNTS_PER_QUERY) { - const accountsBatch = selectedKols.slice(i, i + ACCOUNTS_PER_QUERY); - const query = `(${accountsBatch.map(account => `from:${account}`).join(' OR ')})`; - - const searchIterator = scraper.searchTweets(query, Math.floor(config.MAX_SEARCH_TWEETS / 4), SearchMode.Latest); - - for await (const tweet of searchIterator) { - if (lastProcessedId && tweet.id && tweet.id <= lastProcessedId) { - break; - } - tweetGroups.push({ - id: tweet.id || '', - text: tweet.text || '', - author_id: tweet.userId || '', - author_username: tweet.username?.toLowerCase() || '', - created_at: tweet.timeParsed || new Date() - }); - } - - await new Promise(resolve => setTimeout(resolve, 1000)); - } + if (kols.length === 0) { + logger.error('No valid accounts found after cleaning'); + return { + tweets: [], + lastProcessedId: null, + }; + } + + const selectedKols = getRandomAccounts(kols, config.ACCOUNTS_PER_BATCH); + const ACCOUNTS_PER_QUERY = 3; + const tweetGroups = []; - const allTweets = tweetGroups.sort((a, b) => b.created_at.getTime() - a.created_at.getTime()); - - logger.info('Tweet search completed:', { - foundTweets: allTweets.length, - selectedKols + for (let i = 0; i < selectedKols.length; i += ACCOUNTS_PER_QUERY) { + const accountsBatch = selectedKols.slice(i, i + ACCOUNTS_PER_QUERY); + const query = `(${accountsBatch.map(account => `from:${account}`).join(' OR ')})`; + + const searchIterator = scraper.searchTweets( + query, + Math.floor(config.MAX_SEARCH_TWEETS / 4), + SearchMode.Latest, + ); + + for await (const tweet of searchIterator) { + if (lastProcessedId && tweet.id && tweet.id <= lastProcessedId) { + break; + } + tweetGroups.push({ + id: tweet.id || '', + text: tweet.text || '', + author_id: tweet.userId || '', + author_username: tweet.username?.toLowerCase() || '', + created_at: tweet.timeParsed || new Date(), }); + } - return { - tweets: allTweets, - lastProcessedId: allTweets[allTweets.length - 1]?.id || null - }; - } catch (error) { - logger.error('Error searching tweets:', error); - return { - tweets: [], - lastProcessedId: null - }; + await new Promise(resolve => setTimeout(resolve, 1000)); } - } -}); \ No newline at end of file + + const allTweets = tweetGroups.sort( + (a, b) => b.created_at.getTime() - a.created_at.getTime(), + ); + + logger.info('Tweet search completed:', { + foundTweets: allTweets.length, + selectedKols, + }); + + return { + tweets: allTweets, + lastProcessedId: allTweets[allTweets.length - 1]?.id || null, + }; + } catch (error) { + logger.error('Error searching tweets:', error); + return { + tweets: [], + lastProcessedId: null, + }; + } + }, + }); diff --git a/auto-kol/agent/src/types/agent.ts b/auto-kol/agent/src/types/agent.ts index c2e2b6d..0ba8ea5 100644 --- a/auto-kol/agent/src/types/agent.ts +++ b/auto-kol/agent/src/types/agent.ts @@ -1,11 +1,11 @@ -import { Tweet } from "./twitter.js"; +import { Tweet } from './twitter.js'; export type AgentResponse = Readonly<{ - content: string; - references?: readonly string[]; -}> + content: string; + references?: readonly string[]; +}>; export type Context = Readonly<{ - tweet: Tweet; - previousInteractions: readonly AgentResponse[]; -}> \ No newline at end of file + tweet: Tweet; + previousInteractions: readonly AgentResponse[]; +}>; diff --git a/auto-kol/agent/src/types/kol.ts b/auto-kol/agent/src/types/kol.ts index 9b0e308..fcf7466 100644 --- a/auto-kol/agent/src/types/kol.ts +++ b/auto-kol/agent/src/types/kol.ts @@ -1,6 +1,6 @@ export type KOL = Readonly<{ - id: string; - username: string; - created_at?: Date; - updatedAt?: Date; -}>; \ No newline at end of file + id: string; + username: string; + created_at?: Date; + updatedAt?: Date; +}>; diff --git a/auto-kol/agent/src/types/queue.ts b/auto-kol/agent/src/types/queue.ts index d5a922d..992b108 100644 --- a/auto-kol/agent/src/types/queue.ts +++ b/auto-kol/agent/src/types/queue.ts @@ -3,63 +3,63 @@ import { AgentResponse } from './agent.js'; import { WorkflowState } from './workflow.js'; export enum ResponseStatus { - SKIPPED = 'skipped', - PENDING = 'pending', - APPROVED = 'approved', - REJECTED = 'rejected' + SKIPPED = 'skipped', + PENDING = 'pending', + APPROVED = 'approved', + REJECTED = 'rejected', } export interface PendingResponse { + id: string; + tweet_id: string; + content: string; + tone: string; + strategy: string; + estimatedImpact: number; + confidence: number; +} + +export type ActionResponse = Readonly<{ + tweet: Tweet; + status: 'pending' | 'approved' | 'rejected'; + response: { id: string; - tweet_id: string; content: string; tone: string; strategy: string; estimatedImpact: number; - confidence: number; -} - -export type ActionResponse = Readonly<{ - tweet: Tweet; - status: 'pending' | 'approved' | 'rejected'; - response: { - id: string; - content: string; - tone: string; - strategy: string; - estimatedImpact: number; - confidenceScore: number; - } -}> + confidenceScore: number; + }; +}>; export type QueuedResponseMemory = Readonly<{ - id: string; - tweet: Tweet; - response: AgentResponse; - status: 'pending' | 'approved' | 'rejected'; - created_at: Date; - updatedAt: Date; - workflowState: WorkflowState; + id: string; + tweet: Tweet; + response: AgentResponse; + status: 'pending' | 'approved' | 'rejected'; + created_at: Date; + updatedAt: Date; + workflowState: WorkflowState; }>; export type SkippedTweetMemory = Readonly<{ - id: string; - tweet: Tweet; - reason: string; - priority: number; - created_at: Date; - workflowState: any; + id: string; + tweet: Tweet; + reason: string; + priority: number; + created_at: Date; + workflowState: any; }>; export type SkippedTweet = Readonly<{ - id: string; - tweet_id: string; - reason: string; - priority: number; + id: string; + tweet_id: string; + reason: string; + priority: number; }>; export type ApprovalAction = Readonly<{ - id: string; - approved: boolean; - feedback?: string; -}>; \ No newline at end of file + id: string; + approved: boolean; + feedback?: string; +}>; diff --git a/auto-kol/agent/src/types/twitter.ts b/auto-kol/agent/src/types/twitter.ts index 06a19d3..2292c98 100644 --- a/auto-kol/agent/src/types/twitter.ts +++ b/auto-kol/agent/src/types/twitter.ts @@ -1,14 +1,14 @@ export type Tweet = { - readonly id: string; - readonly text: string; - readonly author_id: string; - readonly author_username: string; - readonly created_at: string; -} + readonly id: string; + readonly text: string; + readonly author_id: string; + readonly author_username: string; + readonly created_at: string; +}; export type TwitterCredentials = { - appKey: string; - appSecret: string; - accessToken: string; - accessSecret: string; + appKey: string; + appSecret: string; + accessToken: string; + accessSecret: string; }; diff --git a/auto-kol/agent/src/types/workflow.ts b/auto-kol/agent/src/types/workflow.ts index 4168fd2..16892fe 100644 --- a/auto-kol/agent/src/types/workflow.ts +++ b/auto-kol/agent/src/types/workflow.ts @@ -2,51 +2,51 @@ import { Tweet } from './twitter.js'; import { BaseMessage } from '@langchain/core/messages'; export type EngagementDecision = Readonly<{ - shouldEngage: boolean; - reason: string; - priority: number; + shouldEngage: boolean; + reason: string; + priority: number; }>; export type ToneAnalysis = Readonly<{ - dominantTone: string; - suggestedTone: string; - reasoning: string; + dominantTone: string; + suggestedTone: string; + reasoning: string; }>; export type ResponseAlternative = Readonly<{ - content: string; - tone: string; - strategy: string; - estimatedImpact: number; + content: string; + tone: string; + strategy: string; + estimatedImpact: number; }>; export type ResponseSelection = Readonly<{ - selectedResponse: string; - reasoning: string; - confidence: number; + selectedResponse: string; + reasoning: string; + confidence: number; }>; export type ResponseStrategy = Readonly<{ - confidence: number; - content: string; - tone: string; - strategy: string; - estimatedImpact: number; + confidence: number; + content: string; + tone: string; + strategy: string; + estimatedImpact: number; }>; export type AutoFeedback = Readonly<{ - response: string; - reason: string; - suggestedChanges: string[]; + response: string; + reason: string; + suggestedChanges: string[]; }>; export type WorkflowState = Readonly<{ - tweet: Tweet; - messages: BaseMessage[]; - engagementDecision?: EngagementDecision; - toneAnalysis?: ToneAnalysis; - alternatives?: ResponseAlternative[]; - selectedResponse?: ResponseSelection; - responseStrategy?: ResponseStrategy; - autoFeedback?: AutoFeedback[]; -}>; \ No newline at end of file + tweet: Tweet; + messages: BaseMessage[]; + engagementDecision?: EngagementDecision; + toneAnalysis?: ToneAnalysis; + alternatives?: ResponseAlternative[]; + selectedResponse?: ResponseSelection; + responseStrategy?: ResponseStrategy; + autoFeedback?: AutoFeedback[]; +}>; diff --git a/auto-kol/agent/src/utils/agentMemoryContract.ts b/auto-kol/agent/src/utils/agentMemoryContract.ts index cffaf3e..4432593 100644 --- a/auto-kol/agent/src/utils/agentMemoryContract.ts +++ b/auto-kol/agent/src/utils/agentMemoryContract.ts @@ -4,25 +4,24 @@ import { config } from '../config/index.js'; import { wallet } from './agentWallet.js'; import { cidFromBlakeHash, cidToString } from '@autonomys/auto-dag-data'; - const CONTRACT_ADDRESS = config.CONTRACT_ADDRESS as `0x${string}`; const contract = new ethers.Contract(CONTRACT_ADDRESS, MEMORY_ABI, wallet); export const getLastMemoryHash = async (): Promise => { - return await contract.getLastMemoryHash(wallet.address); -} + return await contract.getLastMemoryHash(wallet.address); +}; export const getLastMemoryCid = async (): Promise => { - const lastMemoryHash = await contract.getLastMemoryHash(wallet.address); - return cidToString(cidFromBlakeHash(lastMemoryHash)); -} + const lastMemoryHash = await contract.getLastMemoryHash(wallet.address); + return cidToString(cidFromBlakeHash(lastMemoryHash)); +}; export const setLastMemoryHash = async (hash: string, nonce?: number) => { - const bytes32Hash = ethers.zeroPadValue(hash, 32); - const tx = await contract.setLastMemoryHash(bytes32Hash, { - nonce: nonce, - gasLimit: 100000 - }); - return tx; -} \ No newline at end of file + const bytes32Hash = ethers.zeroPadValue(hash, 32); + const tx = await contract.setLastMemoryHash(bytes32Hash, { + nonce: nonce, + gasLimit: 100000, + }); + return tx; +}; diff --git a/auto-kol/agent/src/utils/agentWallet.ts b/auto-kol/agent/src/utils/agentWallet.ts index cd17864..72634c4 100644 --- a/auto-kol/agent/src/utils/agentWallet.ts +++ b/auto-kol/agent/src/utils/agentWallet.ts @@ -6,8 +6,6 @@ const provider = new ethers.JsonRpcProvider(config.RPC_URL); export const wallet = new ethers.Wallet(config.PRIVATE_KEY as string, provider); export async function signMessage(data: object): Promise { - const message = JSON.stringify(data); - return await wallet.signMessage(message); + const message = JSON.stringify(data); + return await wallet.signMessage(message); } - - diff --git a/auto-kol/agent/src/utils/dsn.ts b/auto-kol/agent/src/utils/dsn.ts index c65f8dc..02cfc6c 100644 --- a/auto-kol/agent/src/utils/dsn.ts +++ b/auto-kol/agent/src/utils/dsn.ts @@ -13,169 +13,163 @@ const dsnAPI = createAutoDriveApi({ apiKey: config.DSN_API_KEY! }); let currentNonce = await wallet.getNonce(); interface RetryOptions { - maxRetries: number; - delay: number; - onRetry?: (error: Error, attempt: number) => void; + maxRetries: number; + delay: number; + onRetry?: (error: Error, attempt: number) => void; } -async function retry( - fn: () => Promise, - options: RetryOptions -): Promise { - const { maxRetries, delay, onRetry } = options; - let lastError: Error; - - for (let attempt = 1; attempt <= maxRetries; attempt++) { - try { - return await fn(); - } catch (error) { - lastError = error as Error; - - if (attempt === maxRetries) { - break; - } - - if (onRetry) { - onRetry(lastError, attempt); - } - - // Add jitter to prevent thundering herd - const jitter = Math.random() * 1000; - await new Promise(resolve => - setTimeout(resolve, delay * attempt + jitter) - ); - } - } +async function retry(fn: () => Promise, options: RetryOptions): Promise { + const { maxRetries, delay, onRetry } = options; + let lastError: Error; - throw lastError!; -} + for (let attempt = 1; attempt <= maxRetries; attempt++) { + try { + return await fn(); + } catch (error) { + lastError = error as Error; -const getPreviousCid = async (): Promise => { - const dsnLastCid = await getLastDsnCid(); - if (dsnLastCid) { - logger.info('Using last CID from local db', { cid: dsnLastCid }); - return dsnLastCid; + if (attempt === maxRetries) { + break; + } + + if (onRetry) { + onRetry(lastError, attempt); + } + + // Add jitter to prevent thundering herd + const jitter = Math.random() * 1000; + await new Promise(resolve => setTimeout(resolve, delay * attempt + jitter)); } + } - const memoryLastCid = await getLastMemoryCid(); - logger.info('Using fallback CID source', { - memoryLastCid: memoryLastCid || 'not found' - }); + throw lastError!; +} - return memoryLastCid || ''; +const getPreviousCid = async (): Promise => { + const dsnLastCid = await getLastDsnCid(); + if (dsnLastCid) { + logger.info('Using last CID from local db', { cid: dsnLastCid }); + return dsnLastCid; + } + + const memoryLastCid = await getLastMemoryCid(); + logger.info('Using fallback CID source', { + memoryLastCid: memoryLastCid || 'not found', + }); + + return memoryLastCid || ''; }; -export async function uploadToDsn({ data, }: { data: any; }) { - const maxRetries = 5; - const retryDelay = 2000; - const previousCid = await getPreviousCid(); - - try { - const timestamp = new Date().toISOString(); - const signature = await signMessage({ - data: data, - previousCid: previousCid, - timestamp: timestamp - }); +export async function uploadToDsn({ data }: { data: any }) { + const maxRetries = 5; + const retryDelay = 2000; + const previousCid = await getPreviousCid(); + + try { + const timestamp = new Date().toISOString(); + const signature = await signMessage({ + data: data, + previousCid: previousCid, + timestamp: timestamp, + }); - const dsnData = { - ...data, - previousCid: previousCid, - signature: signature, - timestamp: timestamp - }; - - const jsonBuffer = Buffer.from(JSON.stringify(dsnData, null, 2)); - - let finalCid: string | undefined; - await retry( - async () => { - const uploadObservable = uploadFile( - dsnAPI, - { - read: async function* () { - yield jsonBuffer; - }, - name: `${config.TWITTER_USERNAME}-agent-memory-${timestamp}.json`, - mimeType: 'application/json', - size: jsonBuffer.length, - path: timestamp - }, - { - compression: true, - password: config.DSN_ENCRYPTION_PASSWORD || undefined - } - ); - - await uploadObservable.forEach(status => { - if (status.type === 'file' && status.cid) { - finalCid = status.cid.toString(); - } - }); - - if (!finalCid) { - throw new Error('Failed to get CID from DSN upload'); - } + const dsnData = { + ...data, + previousCid: previousCid, + signature: signature, + timestamp: timestamp, + }; + + const jsonBuffer = Buffer.from(JSON.stringify(dsnData, null, 2)); + + let finalCid: string | undefined; + await retry( + async () => { + const uploadObservable = uploadFile( + dsnAPI, + { + read: async function* () { + yield jsonBuffer; }, - { - maxRetries, - delay: retryDelay, - onRetry: (error, attempt) => { - logger.warn(`DSN upload attempt ${attempt} failed:`, { - error: error.message, - tweetId: data.tweet?.id - }); - } - } + name: `${config.TWITTER_USERNAME}-agent-memory-${timestamp}.json`, + mimeType: 'application/json', + size: jsonBuffer.length, + path: timestamp, + }, + { + compression: true, + password: config.DSN_ENCRYPTION_PASSWORD || undefined, + }, ); + await uploadObservable.forEach(status => { + if (status.type === 'file' && status.cid) { + finalCid = status.cid.toString(); + } + }); + if (!finalCid) { - throw new Error('Failed to get CID from DSN upload after retries'); + throw new Error('Failed to get CID from DSN upload'); } + }, + { + maxRetries, + delay: retryDelay, + onRetry: (error, attempt) => { + logger.warn(`DSN upload attempt ${attempt} failed:`, { + error: error.message, + tweetId: data.tweet?.id, + }); + }, + }, + ); + + if (!finalCid) { + throw new Error('Failed to get CID from DSN upload after retries'); + } - const blake3hash = blake3HashFromCid(stringToCid(finalCid)); - logger.info('Setting last memory hash', { - blake3hash: hexlify(blake3hash) - }); - - await retry( - async () => { - const tx = await setLastMemoryHash(hexlify(blake3hash), currentNonce++); - logger.info('Memory hash transaction submitted', { - txHash: tx.hash, - previousCid, - cid: finalCid - }); - return tx; - }, - { - maxRetries, - delay: retryDelay, - onRetry: (error, attempt) => { - logger.warn(`Blockchain transaction attempt ${attempt} failed:`, { - error: error.message, - cid: finalCid - }); - } - } - ).catch(error => { - logger.error('Failed to submit memory hash transaction', error); - }); + const blake3hash = blake3HashFromCid(stringToCid(finalCid)); + logger.info('Setting last memory hash', { + blake3hash: hexlify(blake3hash), + }); - await addDsn({ - id: generateId(), - tweetId: data.tweet.id, - cid: finalCid + await retry( + async () => { + const tx = await setLastMemoryHash(hexlify(blake3hash), currentNonce++); + logger.info('Memory hash transaction submitted', { + txHash: tx.hash, + previousCid, + cid: finalCid, }); - - return { - success: true, + return tx; + }, + { + maxRetries, + delay: retryDelay, + onRetry: (error, attempt) => { + logger.warn(`Blockchain transaction attempt ${attempt} failed:`, { + error: error.message, cid: finalCid, - previousCid: previousCid || null - }; + }); + }, + }, + ).catch(error => { + logger.error('Failed to submit memory hash transaction', error); + }); - } catch (error) { - logger.error('Error uploading to DSN:', error); - throw error; - } -} \ No newline at end of file + await addDsn({ + id: generateId(), + tweetId: data.tweet.id, + cid: finalCid, + }); + + return { + success: true, + cid: finalCid, + previousCid: previousCid || null, + }; + } catch (error) { + logger.error('Error uploading to DSN:', error); + throw error; + } +} diff --git a/auto-kol/agent/src/utils/logger.ts b/auto-kol/agent/src/utils/logger.ts index 5c484cf..f72e66d 100644 --- a/auto-kol/agent/src/utils/logger.ts +++ b/auto-kol/agent/src/utils/logger.ts @@ -3,83 +3,81 @@ import { config } from '../config/index.js'; import util from 'util'; const formatMeta = (meta: any, useColors: boolean = false) => { - const cleanMeta = Object.entries(meta) - .filter(([key]) => !key.startsWith('Symbol(') && key !== 'splat') - .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}); + const cleanMeta = Object.entries(meta) + .filter(([key]) => !key.startsWith('Symbol(') && key !== 'splat') + .reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}); - if (Object.keys(cleanMeta).length === 0) return ''; + if (Object.keys(cleanMeta).length === 0) return ''; - if (meta[Symbol.for('splat')]?.[0]) { - Object.assign(cleanMeta, meta[Symbol.for('splat')][0]); - } + if (meta[Symbol.for('splat')]?.[0]) { + Object.assign(cleanMeta, meta[Symbol.for('splat')][0]); + } - return Object.keys(cleanMeta).length - ? '\n' + JSON.stringify(cleanMeta, null, 2) - : ''; + return Object.keys(cleanMeta).length ? '\n' + JSON.stringify(cleanMeta, null, 2) : ''; }; const createFileFormat = () => - winston.format.combine( - winston.format.timestamp({ - format: 'YYYY-MM-DD HH:mm:ss.SSS' - }), - winston.format.uncolorize(), - winston.format.printf(({ level, message, context, timestamp, ...meta }) => { - const metaStr = formatMeta(meta, false); - const paddedLevel = level.toUpperCase().padEnd(7); - return `${timestamp} | ${paddedLevel} | [${context}] | ${message}${metaStr}`; - }) - ); + winston.format.combine( + winston.format.timestamp({ + format: 'YYYY-MM-DD HH:mm:ss.SSS', + }), + winston.format.uncolorize(), + winston.format.printf(({ level, message, context, timestamp, ...meta }) => { + const metaStr = formatMeta(meta, false); + const paddedLevel = level.toUpperCase().padEnd(7); + return `${timestamp} | ${paddedLevel} | [${context}] | ${message}${metaStr}`; + }), + ); const createConsoleFormat = () => - winston.format.combine( - winston.format.timestamp({ - format: 'YYYY-MM-DD HH:mm:ss.SSS' - }), - winston.format.colorize({ level: true }), - winston.format.printf(({ level, message, context, timestamp, ...meta }) => { - const metaStr = formatMeta(meta, true); - const paddedLevel = level.toUpperCase().padEnd(7); - return `${timestamp} | ${paddedLevel} | [${context}] | ${message}${metaStr}`; - }) - ); + winston.format.combine( + winston.format.timestamp({ + format: 'YYYY-MM-DD HH:mm:ss.SSS', + }), + winston.format.colorize({ level: true }), + winston.format.printf(({ level, message, context, timestamp, ...meta }) => { + const metaStr = formatMeta(meta, true); + const paddedLevel = level.toUpperCase().padEnd(7); + return `${timestamp} | ${paddedLevel} | [${context}] | ${message}${metaStr}`; + }), + ); const createTransports = () => [ - new winston.transports.File({ - filename: 'logs/error.log', - level: 'error', - format: createFileFormat(), - maxsize: 5242880, - maxFiles: 5, - tailable: true - }), - new winston.transports.File({ - filename: 'logs/combined.log', - format: createFileFormat(), - maxsize: 5242880, - maxFiles: 5, - tailable: true - }) + new winston.transports.File({ + filename: 'logs/error.log', + level: 'error', + format: createFileFormat(), + maxsize: 5242880, + maxFiles: 5, + tailable: true, + }), + new winston.transports.File({ + filename: 'logs/combined.log', + format: createFileFormat(), + maxsize: 5242880, + maxFiles: 5, + tailable: true, + }), ]; const addConsoleTransport = (logger: winston.Logger): winston.Logger => { - if (config.NODE_ENV !== 'production') { - logger.add( - new winston.transports.Console({ - format: createConsoleFormat() - }) - ); - } - return logger; + if (config.NODE_ENV !== 'production') { + logger.add( + new winston.transports.Console({ + format: createConsoleFormat(), + }), + ); + } + return logger; }; export const createLogger = (context: string) => { - const logger = winston.createLogger({ - defaultMeta: { context }, - level: 'info', - format: createFileFormat(), - transports: createTransports() - }); + const logger = winston.createLogger({ + defaultMeta: { context }, + level: 'info', + format: createFileFormat(), + transports: createTransports(), + }); - return addConsoleTransport(logger); -}; \ No newline at end of file + return addConsoleTransport(logger); +}; diff --git a/auto-kol/agent/src/utils/twitter.ts b/auto-kol/agent/src/utils/twitter.ts index 4f2dae9..46a9d18 100644 --- a/auto-kol/agent/src/utils/twitter.ts +++ b/auto-kol/agent/src/utils/twitter.ts @@ -10,67 +10,64 @@ const twitterScraper = await createTwitterClientScraper(); export const timelineTweets: Tweet[] = []; export const updateKOLs = async () => { - const currentKOLs = await db.getKOLAccounts(); - const twitterProfile = await twitterScraper.getProfile(config.TWITTER_USERNAME!); - const followings = twitterScraper.getFollowing(twitterProfile.userId!, 1000); - logger.info(`following count: ${twitterProfile.followingCount}`); + const currentKOLs = await db.getKOLAccounts(); + const twitterProfile = await twitterScraper.getProfile(config.TWITTER_USERNAME!); + const followings = twitterScraper.getFollowing(twitterProfile.userId!, 1000); + logger.info(`following count: ${twitterProfile.followingCount}`); - const newKOLs: KOL[] = []; - for await (const following of followings) { - if (!currentKOLs.some(kol => kol.username === following.username)) { - newKOLs.push({ - id: following.userId!, - username: following.username!.toLowerCase(), - created_at: following.joined!, - }); - await db.addKOL(newKOLs[newKOLs.length - 1]); - } + const newKOLs: KOL[] = []; + for await (const following of followings) { + if (!currentKOLs.some(kol => kol.username === following.username)) { + newKOLs.push({ + id: following.userId!, + username: following.username!.toLowerCase(), + created_at: following.joined!, + }); + await db.addKOL(newKOLs[newKOLs.length - 1]); } + } - return newKOLs; -} + return newKOLs; +}; export const getKOLsAccounts = async () => { - const kolAccounts = await db.getKOLAccounts(); - return kolAccounts.map(kol => kol.username); -} + const kolAccounts = await db.getKOLAccounts(); + return kolAccounts.map(kol => kol.username); +}; export const getTimeLine = async () => { - const validTweetIds = timelineTweets - .map(tweet => tweet.id) - .filter(id => id != null); - const timeline = await twitterScraper.fetchHomeTimeline(0, validTweetIds); + const validTweetIds = timelineTweets.map(tweet => tweet.id).filter(id => id != null); + const timeline = await twitterScraper.fetchHomeTimeline(0, validTweetIds); - - // clear timeline - clearTimeLine(); - for (const tweet of timeline) { - if (!tweet.legacy || !tweet.legacy.full_text) { - logger.info(`Tweet full_text not found for tweet id: ${tweet.rest_id}`); - continue; - } - timelineTweets.push({ - id: tweet.rest_id!, - text: tweet.legacy!.full_text, - author_id: tweet.legacy!.user_id_str!, - author_username: tweet.core!.user_results!.result!.legacy!.screen_name, - created_at: new Date(tweet.legacy!.created_at!).toISOString(), - }) + // clear timeline + clearTimeLine(); + for (const tweet of timeline) { + if (!tweet.legacy || !tweet.legacy.full_text) { + logger.info(`Tweet full_text not found for tweet id: ${tweet.rest_id}`); + continue; } - logger.info(`Timeline tweets size: ${timelineTweets.length}`); - return timelineTweets; -} + timelineTweets.push({ + id: tweet.rest_id!, + text: tweet.legacy!.full_text, + author_id: tweet.legacy!.user_id_str!, + author_username: tweet.core!.user_results!.result!.legacy!.screen_name, + created_at: new Date(tweet.legacy!.created_at!).toISOString(), + }); + } + logger.info(`Timeline tweets size: ${timelineTweets.length}`); + return timelineTweets; +}; const clearTimeLine = () => { - timelineTweets.length = 0; -} + timelineTweets.length = 0; +}; export const getUserProfile = async (username: string) => { - const user = await twitterScraper.getProfile(username); - const result: KOL = { - id: user.userId!, - username: user.username!.toLowerCase(), - created_at: user.joined!, - } - return result; -} \ No newline at end of file + const user = await twitterScraper.getProfile(username); + const result: KOL = { + id: user.userId!, + username: user.username!.toLowerCase(), + created_at: user.joined!, + }; + return result; +}; diff --git a/auto-kol/agent/yarn.lock b/auto-kol/agent/yarn.lock index 33ab875..91a6fa3 100644 --- a/auto-kol/agent/yarn.lock +++ b/auto-kol/agent/yarn.lock @@ -193,11 +193,62 @@ resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.23.1.tgz#81fd50d11e2c32b2d6241470e3185b70c7b30699" integrity sha512-BHpFFeslkWrXWyUPnbKm+xYYVYruCinGcftSBaa8zoF9hZO4BcSCFUvHVTtzpIY6YzUnYtuEhZ+C9iEXjxnasg== +"@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.1.tgz#d1145bf2c20132d6400495d6df4bf59362fd9d56" + integrity sha512-s3O3waFUrMV8P/XaF/+ZTp1X9XBZW1a4B97ZnjQF2KYWaFD2A8KyFBsrsfSjEmjn3RGWAIuvlneuZm3CUK3jbA== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.1": + version "4.12.1" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" + integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-2.1.4.tgz#388a269f0f25c1b6adc317b5a2c55714894c70ad" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.57.1": + version "8.57.1" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-8.57.1.tgz#de633db3ec2ef6a3c89e2f19038063e8a122e2c2" + integrity sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q== + "@gar/promisify@^1.0.1": version "1.1.3" resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@humanwhocodes/config-array@^0.13.0": + version "0.13.0" + resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.13.0.tgz#fb907624df3256d04b9aa2df50d7aa97ec648748" + integrity sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw== + dependencies: + "@humanwhocodes/object-schema" "^2.0.3" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.3": + version "2.0.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz#4a2868d75d6d6963e423bcf90b7fd1be343409d3" + integrity sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA== + "@ipld/dag-pb@^4.1.2": version "4.1.3" resolved "https://registry.npmjs.org/@ipld/dag-pb/-/dag-pb-4.1.3.tgz" @@ -306,6 +357,32 @@ resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.5.0.tgz" integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz#7619c2eb21b25483f6d167548b4cfd5a7488c3d5" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@2.0.5", "@nodelib/fs.stat@^2.0.2": + version "2.0.5" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@nolyfill/is-core-module@1.0.39": + version "1.0.39" + resolved "https://registry.yarnpkg.com/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz#3dc35ba0f1e66b403c00b39344f870298ebb1c8e" + integrity sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA== + "@npmcli/fs@^1.0.0": version "1.1.1" resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz" @@ -402,6 +479,11 @@ resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== +"@rtsao/scc@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@rtsao/scc/-/scc-1.1.0.tgz#927dd2fae9bc3361403ac2c7a00c32ddce9ad7e8" + integrity sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g== + "@sinclair/typebox@^0.32.20": version "0.32.35" resolved "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.32.35.tgz" @@ -464,11 +546,16 @@ resolved "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.4.tgz" integrity sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA== -"@types/json-schema@^7.0.15": +"@types/json-schema@^7.0.12", "@types/json-schema@^7.0.15": version "7.0.15" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + "@types/linkify-it@^5": version "5.0.0" resolved "https://registry.npmjs.org/@types/linkify-it/-/linkify-it-5.0.0.tgz" @@ -548,6 +635,11 @@ resolved "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz" integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== +"@types/semver@^7.5.0": + version "7.5.8" + resolved "https://registry.yarnpkg.com/@types/semver/-/semver-7.5.8.tgz#8268a8c57a3e4abd25c165ecd36237db7948a55e" + integrity sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ== + "@types/send@*": version "0.17.4" resolved "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz" @@ -582,6 +674,152 @@ resolved "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz" integrity sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ== +"@typescript-eslint/eslint-plugin@^6.19.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz#30830c1ca81fd5f3c2714e524c4303e0194f9cd3" + integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/type-utils" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^6.19.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-6.21.0.tgz#af8fcf66feee2edc86bc5d1cf45e33b0630bf35b" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz#ea8a9bfc8f1504a6ac5d59a6df308d3a0630a2b1" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + +"@typescript-eslint/scope-manager@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-7.18.0.tgz#c928e7a9fc2c0b3ed92ab3112c614d6bd9951c83" + integrity sha512-jjhdIE/FPF2B7Z1uzc6i3oWKbGcHb87Qw7AWj6jmEqNOfDFbJWtjt/XfwCpvNkpGWlcJaog5vTR+VV8+w9JflA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + +"@typescript-eslint/type-utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz#6473281cfed4dacabe8004e8521cee0bd9d4c01e" + integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== + dependencies: + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/type-utils@^7.2.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-7.18.0.tgz#2165ffaee00b1fbbdd2d40aa85232dab6998f53b" + integrity sha512-XL0FJXuCLaDuX2sYqZUUSOJ2sG5/i1AAze+axqmLnSkNEVMVYLF+cbwlB2w8D1tinFuSikHmFta+P+HOofrLeA== + dependencies: + "@typescript-eslint/typescript-estree" "7.18.0" + "@typescript-eslint/utils" "7.18.0" + debug "^4.3.4" + ts-api-utils "^1.3.0" + +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-6.21.0.tgz#205724c5123a8fef7ecd195075fa6e85bac3436d" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== + +"@typescript-eslint/types@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-7.18.0.tgz#b90a57ccdea71797ffffa0321e744f379ec838c9" + integrity sha512-iZqi+Ds1y4EDYUtlOOC+aUmxnE9xS/yCigkjA7XpTKV6nCBd3Hp/PRGGmdwnfkV2ThMyYldP1wRpm/id99spTQ== + +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz#c47ae7901db3b8bddc3ecd73daff2d0895688c46" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/typescript-estree@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-7.18.0.tgz#b5868d486c51ce8f312309ba79bdb9f331b37931" + integrity sha512-aP1v/BSPnnyhMHts8cf1qQ6Q1IFwwRvAQGRvBFkWlo3/lH29OXA3Pts+c10nxRxIBrDnoMqzhgdwVe5f2D6OzA== + dependencies: + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/visitor-keys" "7.18.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +"@typescript-eslint/utils@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-6.21.0.tgz#4714e7a6b39e773c1c8e97ec587f520840cd8134" + integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + semver "^7.5.4" + +"@typescript-eslint/utils@7.18.0", "@typescript-eslint/utils@^7.3.1": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-7.18.0.tgz#bca01cde77f95fc6a8d5b0dbcbfb3d6ca4be451f" + integrity sha512-kK0/rNa2j74XuHVcoCZxdFBMF+aq/vH83CXAOHieC+2Gis4mF8jJXT5eAfyD3K0sAxtPuwxaIOIOvhwzVDt/kw== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@typescript-eslint/scope-manager" "7.18.0" + "@typescript-eslint/types" "7.18.0" + "@typescript-eslint/typescript-estree" "7.18.0" + +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz#87a99d077aa507e20e238b11d56cc26ade45fe47" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== + dependencies: + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" + +"@typescript-eslint/visitor-keys@7.18.0": + version "7.18.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-7.18.0.tgz#0564629b6124d67607378d0f0332a0495b25e7d7" + integrity sha512-cDF0/Gf81QpY3xYyJKDV14Zwdmid5+uuENhjH2EqFaF0ni+yAyq/LzMaIJdhNJXZI7uLzwIlA+V7oWoyn6Curg== + dependencies: + "@typescript-eslint/types" "7.18.0" + eslint-visitor-keys "^3.4.3" + +"@ungap/structured-clone@^1.2.0": + version "1.2.1" + resolved "https://registry.yarnpkg.com/@ungap/structured-clone/-/structured-clone-1.2.1.tgz#28fa185f67daaf7b7a1a8c1d445132c5d979f8bd" + integrity sha512-fEzPV3hSkSMltkw152tJKNARhOupqbH96MZWyRjNaYZOMIzbrTeQDG+MTc6Mr2pgzFQzFxAfmhGDNP5QK++2ZA== + "@webbuf/blake3@^3.0.26": version "3.0.26" resolved "https://registry.npmjs.org/@webbuf/blake3/-/blake3-3.0.26.tgz" @@ -669,6 +907,16 @@ aggregate-error@^3.0.0: clean-stack "^2.0.0" indent-string "^4.0.0" +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + ansi-regex@^5.0.1: version "5.0.1" resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" @@ -704,11 +952,81 @@ argparse@^2.0.1: resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-buffer-byte-length@^1.0.1, array-buffer-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz#384d12a37295aec3769ab022ad323a18a51ccf8b" + integrity sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw== + dependencies: + call-bound "^1.0.3" + is-array-buffer "^3.0.5" + array-flatten@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz" integrity sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg== +array-includes@^3.1.8: + version "3.1.8" + resolved "https://registry.yarnpkg.com/array-includes/-/array-includes-3.1.8.tgz#5e370cbe172fdd5dd6530c1d4aadda25281ba97d" + integrity sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + get-intrinsic "^1.2.4" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.findlastindex@^1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.5.tgz#8c35a755c72908719453f87145ca011e39334d0d" + integrity sha512-zfETvRFA8o7EiNn++N5f/kaCw221hrpGsDmcpndVupkPzEc1Wuf3VgC0qby1BbHs7f5DVYjgtEU2LLh5bqeGfQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz#534aaf9e6e8dd79fb6b9a9917f839ef1ec63afe5" + integrity sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +array.prototype.flatmap@^1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz#712cc792ae70370ae40586264629e33aab5dd38b" + integrity sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-shim-unscopables "^1.0.2" + +arraybuffer.prototype.slice@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz#9d760d84dbdd06d0cbf92c8849615a1a7ab3183c" + integrity sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.8" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + is-array-buffer "^3.0.4" + asn1js@^3.0.5: version "3.0.5" resolved "https://registry.npmjs.org/asn1js/-/asn1js-3.0.5.tgz" @@ -728,6 +1046,13 @@ asynckit@^0.4.0: resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== +available-typed-arrays@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz#a5cc375d6a03c2efc87a553f3e0b1522def14846" + integrity sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ== + dependencies: + possible-typed-array-names "^1.0.0" + balanced-match@^1.0.0: version "1.0.2" resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" @@ -797,6 +1122,13 @@ brace-expansion@^2.0.1: dependencies: balanced-match "^1.0.0" +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + buffer@^5.5.0: version "5.7.1" resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" @@ -842,7 +1174,15 @@ call-bind-apply-helpers@^1.0.0: es-errors "^1.3.0" function-bind "^1.1.2" -call-bind@^1.0.5: +call-bind-apply-helpers@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.1.tgz#32e5892e6361b29b0b545ba6f7763378daca2840" + integrity sha512-BhYE+WDaywFg2TBWYNXAE+8B1ATnThNBqXHP5nQu0jWJdVvY2hvkpyB3qOmtmDePiS5/BDQ8wASEWGMWRG148g== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + +call-bind@^1.0.5, call-bind@^1.0.8: version "1.0.8" resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz" integrity sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww== @@ -863,6 +1203,19 @@ call-bind@^1.0.7: get-intrinsic "^1.2.4" set-function-length "^1.2.1" +call-bound@^1.0.2, call-bound@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.3.tgz#41cfd032b593e39176a71533ab4f384aa04fd681" + integrity sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA== + dependencies: + call-bind-apply-helpers "^1.0.1" + get-intrinsic "^1.2.6" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + camelcase@6: version "6.3.0" resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" @@ -1025,11 +1378,47 @@ cors@^2.8.5: object-assign "^4" vary "^1" +cross-spawn@^7.0.2: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + data-uri-to-buffer@^4.0.0: version "4.0.1" resolved "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz" integrity sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A== +data-view-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-buffer/-/data-view-buffer-1.0.2.tgz#211a03ba95ecaf7798a8c7198d79536211f88570" + integrity sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-length@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz#9e80f7ca52453ce3e93d25a35318767ea7704735" + integrity sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-data-view "^1.0.2" + +data-view-byte-offset@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz#068307f9b71ab76dbbe10291389e020856606191" + integrity sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-data-view "^1.0.1" + debug@2.6.9: version "2.6.9" resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" @@ -1044,6 +1433,20 @@ debug@4, debug@^4.3.3: dependencies: ms "^2.1.3" +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@^4.3.7: + version "4.4.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.0.tgz#2b3f2aea2ffeb776477460267377dc8710faba8a" + integrity sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA== + dependencies: + ms "^2.1.3" + decamelize@1.2.0: version "1.2.0" resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" @@ -1061,12 +1464,17 @@ deep-extend@^0.6.0: resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== -deep-is@~0.1.3: +deep-is@^0.1.3, deep-is@~0.1.3: version "0.1.4" resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -define-data-property@^1.1.4: +deepmerge-ts@^5.1.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/deepmerge-ts/-/deepmerge-ts-5.1.0.tgz#c55206cc4c7be2ded89b9c816cf3608884525d7a" + integrity sha512-eS8dRJOckyo9maw9Tu5O5RUi/4inFLrnoLkBe3cPfDMx3WZioXtmOew4TXQaxq7Rhl4xjDtR7c6x8nNTxOvbFw== + +define-data-property@^1.0.1, define-data-property@^1.1.4: version "1.1.4" resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz" integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A== @@ -1075,6 +1483,15 @@ define-data-property@^1.1.4: es-errors "^1.3.0" gopd "^1.0.1" +define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.2.1.tgz#10781cc616eb951a80a034bafcaa7377f6af2b6c" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delayed-stream@~1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" @@ -1100,11 +1517,41 @@ detect-libc@^2.0.0: resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz" integrity sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw== +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + dotenv@^16.3.1: version "16.4.5" resolved "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz" integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg== +dunder-proto@^1.0.0, dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz" @@ -1144,6 +1591,14 @@ end-of-stream@^1.1.0, end-of-stream@^1.4.1: dependencies: once "^1.4.0" +enhanced-resolve@^5.15.0: + version "5.18.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.18.0.tgz#91eb1db193896b9801251eeff1c6980278b1e404" + integrity sha512-0/r0MySGYG8YqlayBZ6MuCfECmHFdJ5qyPh8s8wa5Hnm6SaFLSK1VYCbj+NKp090Nm1caZhD+QTnmxO7esYGyQ== + dependencies: + graceful-fs "^4.2.4" + tapable "^2.2.0" + entities@^4.4.0: version "4.5.0" resolved "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz" @@ -1159,6 +1614,59 @@ err-code@^2.0.2: resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== +es-abstract@^1.23.2, es-abstract@^1.23.5, es-abstract@^1.23.6: + version "1.23.7" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.23.7.tgz#36e3da46fdb0d2ae3b9df4235e3a3167c1605b36" + integrity sha512-OygGC8kIcDhXX+6yAZRGLqwi2CmEXCbLQixeGUgYeR+Qwlppqmo7DIDr8XibtEBZp+fJcoYpoatp5qwLMEdcqQ== + dependencies: + array-buffer-byte-length "^1.0.2" + arraybuffer.prototype.slice "^1.0.4" + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" + data-view-buffer "^1.0.2" + data-view-byte-length "^1.0.2" + data-view-byte-offset "^1.0.1" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + es-set-tostringtag "^2.0.3" + es-to-primitive "^1.3.0" + function.prototype.name "^1.1.8" + get-intrinsic "^1.2.6" + get-symbol-description "^1.1.0" + globalthis "^1.0.4" + gopd "^1.2.0" + has-property-descriptors "^1.0.2" + has-proto "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + internal-slot "^1.1.0" + is-array-buffer "^3.0.5" + is-callable "^1.2.7" + is-data-view "^1.0.2" + is-regex "^1.2.1" + is-shared-array-buffer "^1.0.4" + is-string "^1.1.1" + is-typed-array "^1.1.15" + is-weakref "^1.1.0" + math-intrinsics "^1.1.0" + object-inspect "^1.13.3" + object-keys "^1.1.1" + object.assign "^4.1.7" + regexp.prototype.flags "^1.5.3" + safe-array-concat "^1.1.3" + safe-regex-test "^1.1.0" + string.prototype.trim "^1.2.10" + string.prototype.trimend "^1.0.9" + string.prototype.trimstart "^1.0.8" + typed-array-buffer "^1.0.3" + typed-array-byte-length "^1.0.3" + typed-array-byte-offset "^1.0.4" + typed-array-length "^1.0.7" + unbox-primitive "^1.1.0" + which-typed-array "^1.1.18" + es-define-property@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz" @@ -1166,11 +1674,48 @@ es-define-property@^1.0.0: dependencies: get-intrinsic "^1.2.4" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + es-errors@^1.3.0: version "1.3.0" resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== +es-object-atoms@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.0.0.tgz#ddb55cd47ac2e240701260bc2a8e31ecb643d941" + integrity sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw== + dependencies: + es-errors "^1.3.0" + +es-set-tostringtag@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz#8bb60f0a440c2e4281962428438d58545af39777" + integrity sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ== + dependencies: + get-intrinsic "^1.2.4" + has-tostringtag "^1.0.2" + hasown "^2.0.1" + +es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz#1f6942e71ecc7835ed1c8a83006d8771a63a3763" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.3.0.tgz#96c89c82cc49fd8794a24835ba3e1ff87f214e18" + integrity sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g== + dependencies: + is-callable "^1.2.7" + is-date-object "^1.0.5" + is-symbol "^1.0.4" + esbuild@~0.23.0: version "0.23.1" resolved "https://registry.npmjs.org/esbuild/-/esbuild-0.23.1.tgz" @@ -1211,6 +1756,11 @@ escape-string-regexp@^2.0.0: resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== +escape-string-regexp@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + escodegen@^1.13.0: version "1.14.3" resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" @@ -1223,12 +1773,136 @@ escodegen@^1.13.0: optionalDependencies: source-map "~0.6.1" -eslint-visitor-keys@^3.4.1: +eslint-config-prettier@^9.1.0: + version "9.1.0" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz#31af3d94578645966c082fcb71a5846d3c94867f" + integrity sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw== + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz#d4eaac52b8a2e7c3cd1903eb00f7e053356118ac" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-import-resolver-typescript@^3.6.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.7.0.tgz#e69925936a771a9cb2de418ccebc4cdf6c0818aa" + integrity sha512-Vrwyi8HHxY97K5ebydMtffsWAn1SCR9eol49eCd5fJS4O1WV7PaAjbcjmbfJJSMz/t4Mal212Uz/fQZrOB8mow== + dependencies: + "@nolyfill/is-core-module" "1.0.39" + debug "^4.3.7" + enhanced-resolve "^5.15.0" + fast-glob "^3.3.2" + get-tsconfig "^4.7.5" + is-bun-module "^1.0.2" + is-glob "^4.0.3" + stable-hash "^0.0.4" + +eslint-module-utils@^2.12.0: + version "2.12.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.12.0.tgz#fe4cfb948d61f49203d7b08871982b65b9af0b0b" + integrity sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg== + dependencies: + debug "^3.2.7" + +eslint-plugin-functional@^6.0.0: + version "6.6.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-functional/-/eslint-plugin-functional-6.6.3.tgz#85b895afb91835c5ffa2eb97f473fd4182aa5228" + integrity sha512-sVbbvNvwX3HVkXAykKyoNLv57r4DPF7f1sy+/8j4YtzLYVQPGljMUWv3T6Kd4lwnnjmcKuj0EkIbS+knL6P5jw== + dependencies: + "@typescript-eslint/utils" "^7.3.1" + deepmerge-ts "^5.1.0" + escape-string-regexp "^4.0.0" + is-immutable-type "^4.0.0" + semver "^7.6.0" + ts-api-utils "^1.3.0" + +eslint-plugin-import@^2.29.1: + version "2.31.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.31.0.tgz#310ce7e720ca1d9c0bb3f69adfd1c6bdd7d9e0e7" + integrity sha512-ixmkI62Rbc2/w8Vfxyh1jQRTdRTF52VxwRVHl/ykPAmqG+Nb7/kNn+byLP0LxPgI7zWA16Jt82SybJInmMia3A== + dependencies: + "@rtsao/scc" "^1.1.0" + array-includes "^3.1.8" + array.prototype.findlastindex "^1.2.5" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.12.0" + hasown "^2.0.2" + is-core-module "^2.15.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.8" + object.groupby "^1.0.3" + object.values "^1.2.0" + semver "^6.3.1" + string.prototype.trimend "^1.0.8" + tsconfig-paths "^3.15.0" + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-7.2.2.tgz#deb4f92563390f32006894af62a22dba1c46423f" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== -espree@^9.0.0: +eslint@^8.56.0: + version "8.57.1" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-8.57.1.tgz#7df109654aba7e3bbe5c8eae533c5e461d3c6ca9" + integrity sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.57.1" + "@humanwhocodes/config-array" "^0.13.0" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.0.0, espree@^9.6.0, espree@^9.6.1: version "9.6.1" resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== @@ -1242,12 +1916,26 @@ esprima@^4.0.1: resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== +esquery@^1.4.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" + integrity sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.3.0.tgz#7ad7964d679abb28bee72cec63758b1c5d2c9921" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + estraverse@^4.2.0: version "4.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== -estraverse@^5.1.0: +estraverse@^5.1.0, estraverse@^5.2.0: version "5.3.0" resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== @@ -1332,11 +2020,39 @@ express@4.21.1: utils-merge "1.0.1" vary "~1.1.2" -fast-levenshtein@~2.0.6: +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9, fast-glob@^3.3.2: + version "3.3.2" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6, fast-levenshtein@~2.0.6: version "2.0.6" resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== +fastq@^1.6.0: + version "1.18.0" + resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.18.0.tgz#d631d7e25faffea81887fe5ea8c9010e1b36fee0" + integrity sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw== + dependencies: + reusify "^1.0.4" + fecha@^4.2.0: version "4.2.3" resolved "https://registry.npmjs.org/fecha/-/fecha-4.2.3.tgz" @@ -1355,11 +2071,25 @@ fflate@^0.8.2: resolved "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz" integrity sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A== +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-6.0.1.tgz#211b2dd9659cb0394b073e7323ac3c933d522027" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + file-uri-to-path@1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + finalhandler@1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz" @@ -1373,16 +2103,45 @@ finalhandler@1.3.1: statuses "2.0.1" unpipe "~1.0.0" +find-up@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-3.2.0.tgz#2c0c2d5040c99b1632771a9d105725c0115363ee" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + flat@^5.0.2: version "5.0.2" resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +flatted@^3.2.9: + version "3.3.2" + resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.3.2.tgz#adba1448a9841bec72b42c532ea23dbbedef1a27" + integrity sha512-AiwGJM8YcNOaobumgtng+6NHuOqC3A7MixFeDafM3X9cIUM+xUXoS5Vfgf+OihAYe20fxqNM9yPBXJzRtZ/4eA== + fn.name@1.x.x: version "1.1.0" resolved "https://registry.npmjs.org/fn.name/-/fn.name-1.1.0.tgz" integrity sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw== +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.3.tgz#69b447e88a0a5d32c3e7084f3f1710034b21376e" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + form-data-encoder@1.7.2: version "1.7.2" resolved "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz" @@ -1449,6 +2208,23 @@ function-bind@^1.1.2: resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== +function.prototype.name@^1.1.6, function.prototype.name@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/function.prototype.name/-/function.prototype.name-1.1.8.tgz#e68e1df7b259a5c949eeef95cdbde53edffabb78" + integrity sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + functions-have-names "^1.2.3" + hasown "^2.0.2" + is-callable "^1.2.7" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + gauge@^4.0.3: version "4.0.4" resolved "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz" @@ -1474,6 +2250,31 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.4: has-symbols "^1.0.3" hasown "^2.0.0" +get-intrinsic@^1.2.5, get-intrinsic@^1.2.6: + version "1.2.6" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.6.tgz#43dd3dd0e7b49b82b2dfcad10dc824bf7fc265d5" + integrity sha512-qxsEs+9A+u85HhllWJJFicJfPDhRmjzoYdl64aMWW9yRIJmSyxdn8IEkuIM530/7T+lv0TIHd8L6Q/ra0tEoeA== + dependencies: + call-bind-apply-helpers "^1.0.1" + dunder-proto "^1.0.0" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.0.0" + function-bind "^1.1.2" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.0.0" + +get-symbol-description@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/get-symbol-description/-/get-symbol-description-1.1.0.tgz#7bdd54e0befe8ffc9f3b4e203220d9f1e881b6ee" + integrity sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + get-tsconfig@^4.7.5: version "4.8.1" resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.8.1.tgz" @@ -1486,6 +2287,20 @@ github-from-package@0.0.0: resolved "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== +glob-parent@^5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-6.0.2.tgz#6d237d99083950c79290f24c7642a3de9a28f9e3" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz" @@ -1509,6 +2324,33 @@ glob@^8.0.0: minimatch "^5.0.1" once "^1.3.0" +globals@^13.19.0: + version "13.24.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-13.24.0.tgz#8432a19d78ce0c1e833949c36adb345400bb1171" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/globalthis/-/globalthis-1.0.4.tgz#7430ed3a975d97bfb59bcce41f5cabbafa651236" + integrity sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ== + dependencies: + define-properties "^1.2.1" + gopd "^1.0.1" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + gopd@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" @@ -1516,17 +2358,32 @@ gopd@^1.0.1: dependencies: get-intrinsic "^1.1.3" -graceful-fs@^4.1.9, graceful-fs@^4.2.6: +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + +graceful-fs@^4.1.9, graceful-fs@^4.2.4, graceful-fs@^4.2.6: version "4.2.11" resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +has-bigints@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-bigints/-/has-bigints-1.1.0.tgz#28607e965ac967e03cd2a2c70a2636a1edad49fe" + integrity sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg== + has-flag@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-property-descriptors@^1.0.2: +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.2: version "1.0.2" resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz" integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg== @@ -1538,17 +2395,36 @@ has-proto@^1.0.1: resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz" integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q== +has-proto@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.2.0.tgz#5de5a6eabd95fdffd9818b43055e8065e39fe9d5" + integrity sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ== + dependencies: + dunder-proto "^1.0.0" + has-symbols@^1.0.3: version "1.0.3" resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + +has-tostringtag@^1.0.0, has-tostringtag@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz#2cdc42d40bef2e5b4eeab7c01a73c54ce7ab5abc" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + has-unicode@^2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" integrity sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ== -hasown@^2.0.0: +hasown@^2.0.0, hasown@^2.0.1, hasown@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz" integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ== @@ -1619,11 +2495,24 @@ ieee754@^1.1.13: resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.2" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.2.tgz#3cd40e729f3643fd87cb04e50bf0eb722bc596f5" + integrity sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g== + immediate@~3.0.5: version "3.0.6" resolved "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz" integrity sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ== +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" @@ -1657,6 +2546,15 @@ ini@~1.3.0: resolved "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== +internal-slot@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/internal-slot/-/internal-slot-1.1.0.tgz#1eac91762947d2f7056bc838d93e13b2e9604961" + integrity sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.2" + side-channel "^1.1.0" + ip-address@^9.0.5: version "9.0.5" resolved "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz" @@ -1670,26 +2568,217 @@ ipaddr.js@1.9.1: resolved "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz" integrity sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g== +is-array-buffer@^3.0.4, is-array-buffer@^3.0.5: + version "3.0.5" + resolved "https://registry.yarnpkg.com/is-array-buffer/-/is-array-buffer-3.0.5.tgz#65742e1e687bd2cc666253068fd8707fe4d44280" + integrity sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + is-arrayish@^0.3.1: version "0.3.2" resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.3.2.tgz" integrity sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ== +is-async-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-async-function/-/is-async-function-2.0.0.tgz#8e4418efd3e5d3a6ebb0164c05ef5afb69aa9646" + integrity sha512-Y1JXKrfykRJGdlDwdKlLpLyMIiWqWvuSd17TvZk68PLAOGOoF4Xyav1z0Xhoi+gCYjZVeC5SI+hYFOfvXmGRCA== + dependencies: + has-tostringtag "^1.0.0" + +is-bigint@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-bigint/-/is-bigint-1.1.0.tgz#dda7a3445df57a42583db4228682eba7c4170672" + integrity sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ== + dependencies: + has-bigints "^1.0.2" + +is-boolean-object@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.2.1.tgz#c20d0c654be05da4fbc23c562635c019e93daf89" + integrity sha512-l9qO6eFlUETHtuihLcYOaLKByJ1f+N4kthcU9YjHy3N+B3hWv0y/2Nd0mu/7lTFnRQHTrSdXF50HQ3bl5fEnng== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-bun-module@^1.0.2: + version "1.3.0" + resolved "https://registry.yarnpkg.com/is-bun-module/-/is-bun-module-1.3.0.tgz#ea4d24fdebfcecc98e81bcbcb506827fee288760" + integrity sha512-DgXeu5UWI0IsMQundYb5UAOzm6G2eVnarJ0byP6Tm55iZNKceD59LNPA2L4VvsScTtHcw0yEkVwSf7PC+QoLSA== + dependencies: + semver "^7.6.3" + +is-callable@^1.1.3, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.2.7.tgz#3bc2a85ea742d9e36205dcacdd72ca1fdc51b055" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.13.0, is-core-module@^2.15.1, is-core-module@^2.16.0: + version "2.16.1" + resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.16.1.tgz#2a98801a849f43e2add644fbb6bc6229b19a4ef4" + integrity sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w== + dependencies: + hasown "^2.0.2" + +is-data-view@^1.0.1, is-data-view@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-data-view/-/is-data-view-1.0.2.tgz#bae0a41b9688986c2188dda6657e56b8f9e63b8e" + integrity sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw== + dependencies: + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + is-typed-array "^1.1.13" + +is-date-object@^1.0.5, is-date-object@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.1.0.tgz#ad85541996fc7aa8b2729701d27b7319f95d82f7" + integrity sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg== + dependencies: + call-bound "^1.0.2" + has-tostringtag "^1.0.2" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-finalizationregistry@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz#eefdcdc6c94ddd0674d9c85887bf93f944a97c90" + integrity sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg== + dependencies: + call-bound "^1.0.3" + is-fullwidth-code-point@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-generator-function@^1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.10.tgz#f1558baf1ac17e0deea7c0415c438351ff2b3c72" + integrity sha512-jsEjy9l3yiXEQ+PsXdmBwEPcOxaXWLspKdplFUVI9vq1iZgIekeC0L167qeu86czQaxed3q/Uzuw0swL0irL8A== + dependencies: + has-tostringtag "^1.0.0" + +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-immutable-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/is-immutable-type/-/is-immutable-type-4.0.0.tgz#d62ad1ff411eef8dfa3a87222960ec3b645db1a1" + integrity sha512-gyFBCXv+NikTs8/PGZhgjbMmFZQ5jvHGZIsVu6+/9Bk4K7imlWBIDN7hTr9fNioGzFg71I4YM3z8f0aKXarTAw== + dependencies: + "@typescript-eslint/type-utils" "^7.2.0" + ts-api-utils "^1.3.0" + ts-declaration-location "^1.0.0" + is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" integrity sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ== +is-map@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-map/-/is-map-2.0.3.tgz#ede96b7fe1e270b3c4465e3a465658764926d62e" + integrity sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw== + +is-number-object@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-number-object/-/is-number-object-1.1.1.tgz#144b21e95a1bc148205dcc2814a9134ec41b2541" + integrity sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + +is-regex@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.2.1.tgz#76d70a3ed10ef9be48eb577887d74205bf0cad22" + integrity sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g== + dependencies: + call-bound "^1.0.2" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + hasown "^2.0.2" + +is-set@^2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-set/-/is-set-2.0.3.tgz#8ab209ea424608141372ded6e0cb200ef1d9d01d" + integrity sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg== + +is-shared-array-buffer@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz#9b67844bd9b7f246ba0708c3a93e34269c774f6f" + integrity sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A== + dependencies: + call-bound "^1.0.3" + is-stream@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-string@^1.0.7, is-string@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-string/-/is-string-1.1.1.tgz#92ea3f3d5c5b6e039ca8677e5ac8d07ea773cbb9" + integrity sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA== + dependencies: + call-bound "^1.0.3" + has-tostringtag "^1.0.2" + +is-symbol@^1.0.4, is-symbol@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.1.1.tgz#f47761279f532e2b05a7024a7506dbbedacd0634" + integrity sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w== + dependencies: + call-bound "^1.0.2" + has-symbols "^1.1.0" + safe-regex-test "^1.1.0" + +is-typed-array@^1.1.13, is-typed-array@^1.1.14, is-typed-array@^1.1.15: + version "1.1.15" + resolved "https://registry.yarnpkg.com/is-typed-array/-/is-typed-array-1.1.15.tgz#4bfb4a45b61cee83a5a46fba778e4e8d59c0ce0b" + integrity sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ== + dependencies: + which-typed-array "^1.1.16" + +is-weakmap@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/is-weakmap/-/is-weakmap-2.0.2.tgz#bf72615d649dfe5f699079c54b83e47d1ae19cfd" + integrity sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w== + +is-weakref@^1.0.2, is-weakref@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-weakref/-/is-weakref-1.1.0.tgz#47e3472ae95a63fa9cf25660bcf0c181c39770ef" + integrity sha512-SXM8Nwyys6nT5WP6pltOwKytLV7FqQ4UiibxVmW+EIosHcmCqkkjViTb5SNssDlkCiEYRP1/pdWUKVvZBmsR2Q== + dependencies: + call-bound "^1.0.2" + +is-weakset@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/is-weakset/-/is-weakset-2.0.4.tgz#c9f5deb0bc1906c6d6f1027f284ddf459249daca" + integrity sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ== + dependencies: + call-bound "^1.0.3" + get-intrinsic "^1.2.6" + isarray@^2.0.5: version "2.0.5" resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" @@ -1760,6 +2849,21 @@ jsdoc@^4.0.0: strip-json-comments "^3.1.0" underscore "~1.13.2" +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/json-buffer/-/json-buffer-3.0.1.tgz#9338802a30d3b6605fbe0613e094008ca8c05a13" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json-stable-stringify@^1.0.2: version "1.1.1" resolved "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.1.1.tgz" @@ -1770,6 +2874,13 @@ json-stable-stringify@^1.0.2: jsonify "^0.0.1" object-keys "^1.1.1" +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + jsonify@^0.0.1: version "0.0.1" resolved "https://registry.npmjs.org/jsonify/-/jsonify-0.0.1.tgz" @@ -1790,6 +2901,13 @@ jszip@^3.10.1: readable-stream "~2.3.6" setimmediate "^1.0.5" +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.yarnpkg.com/keyv/-/keyv-4.5.4.tgz#a879a99e29452f942439f2a405e3af8b31d4de93" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + klaw@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/klaw/-/klaw-3.0.0.tgz" @@ -1832,6 +2950,14 @@ langsmith@^0.2.0: semver "^7.6.3" uuid "^10.0.0" +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.4.1.tgz#ae4562c007473b932a6200d403268dd2fffc6ade" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + levn@~0.3.0: version "0.3.0" resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" @@ -1854,6 +2980,18 @@ linkify-it@^5.0.0: dependencies: uc.micro "^2.0.0" +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + lodash@^4.17.15, lodash@^4.17.21: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" @@ -1927,6 +3065,11 @@ marked@^4.0.10: resolved "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz" integrity sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A== +math-intrinsics@^1.0.0, math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + mdurl@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/mdurl/-/mdurl-2.0.0.tgz" @@ -1947,11 +3090,24 @@ merge-descriptors@1.0.3: resolved "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz" integrity sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ== +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + methods@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz" integrity sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w== +micromatch@^4.0.4: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== + dependencies: + braces "^3.0.3" + picomatch "^2.3.1" + mime-db@1.52.0: version "1.52.0" resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" @@ -1974,7 +3130,21 @@ mimic-response@^3.1.0: resolved "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz" integrity sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ== -minimatch@^3.1.1: +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.3.tgz#a6e00c3de44c3a542bfaae70abfc22420a6da825" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^10.0.1: + version "10.0.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.0.1.tgz#ce0521856b453c86e25f2c4c0d03e6ff7ddc440b" + integrity sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ== + dependencies: + brace-expansion "^2.0.1" + +minimatch@^3.0.5, minimatch@^3.1.1, minimatch@^3.1.2: version "3.1.2" resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== @@ -1988,7 +3158,14 @@ minimatch@^5.0.1: dependencies: brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.3: +minimatch@^9.0.4: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== @@ -2087,6 +3264,11 @@ napi-build-utils@^1.0.1: resolved "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-1.0.2.tgz" integrity sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + negotiator@0.6.3: version "0.6.3" resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz" @@ -2168,7 +3350,7 @@ object-assign@^4: resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== -object-inspect@^1.13.1: +object-inspect@^1.13.1, object-inspect@^1.13.3: version "1.13.3" resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.3.tgz" integrity sha512-kDCGIbxkDSXE3euJZZXzc6to7fCrKHNI/hSRQnRuQ+BWjFNzZwiFF8fj/6o2t2G9/jTj8PSIYTfCLelLZEeRpA== @@ -2178,6 +3360,47 @@ object-keys@^1.1.1: resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== +object.assign@^4.1.7: + version "4.1.7" + resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.7.tgz#8c14ca1a424c6a561b0bb2a22f66f5049a945d3d" + integrity sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + has-symbols "^1.1.0" + object-keys "^1.1.1" + +object.fromentries@^2.0.8: + version "2.0.8" + resolved "https://registry.yarnpkg.com/object.fromentries/-/object.fromentries-2.0.8.tgz#f7195d8a9b97bd95cbc1999ea939ecd1a2b00c65" + integrity sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + es-object-atoms "^1.0.0" + +object.groupby@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/object.groupby/-/object.groupby-1.0.3.tgz#9b125c36238129f6f7b61954a1e7176148d5002e" + integrity sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-abstract "^1.23.2" + +object.values@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object.values/-/object.values-1.2.1.tgz#deed520a50809ff7f75a7cfd4bc64c7a038c6216" + integrity sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.3" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + on-finished@2.4.1: version "2.4.1" resolved "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz" @@ -2229,6 +3452,18 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" +optionator@^0.9.3: + version "0.9.4" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734" + integrity sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g== + dependencies: + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + word-wrap "^1.2.5" + otpauth@^9.2.2: version "9.3.5" resolved "https://registry.npmjs.org/otpauth/-/otpauth-9.3.5.tgz" @@ -2241,6 +3476,20 @@ p-finally@^1.0.0: resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + p-map@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" @@ -2281,21 +3530,58 @@ pako@~1.0.2: resolved "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz" integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz" integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + path-to-regexp@0.1.10: version "0.1.10" resolved "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz" integrity sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w== +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + +picomatch@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +possible-typed-array-names@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz#89bb63c6fada2c3e90adc4a647beeeb39cc7bf8f" + integrity sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q== + prebuild-install@^7.1.1: version "7.1.2" resolved "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.2.tgz" @@ -2314,11 +3600,21 @@ prebuild-install@^7.1.1: tar-fs "^2.0.0" tunnel-agent "^0.6.0" +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha512-ESF23V4SKG6lVSGZgYNpbsiaAkdab6ZgOxe52p7+Kid3W3u3bxR4Vfd/o21dmN7jSt0IwgZ4v5MUd26FEtXE9w== +prettier@^3.2.2: + version "3.4.2" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.4.2.tgz#a5ce1fb522a588bf2b78ca44c6e6fe5aa5a2b13f" + integrity sha512-e9MewbtFo+Fevyuxn/4rrcDAaq0IYxPGLvObpQjiZBMAzB9IGmzlnG9RZy3FFas+eBMu2vA0CszMeduow5dIuQ== + process-nextick-args@~2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" @@ -2417,7 +3713,7 @@ punycode.js@^2.3.1: resolved "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz" integrity sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA== -punycode@^2.1.1, punycode@^2.3.1: +punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.1: version "2.3.1" resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== @@ -2446,6 +3742,11 @@ querystringify@^2.1.1: resolved "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz" integrity sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ== +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + range-parser@~1.2.1: version "1.2.1" resolved "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz" @@ -2493,6 +3794,30 @@ readable-stream@~2.3.6: string_decoder "~1.1.1" util-deprecate "~1.0.1" +reflect.getprototypeof@^1.0.6, reflect.getprototypeof@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.9.tgz#c905f3386008de95a62315f3ea8630404be19e2f" + integrity sha512-r0Ay04Snci87djAsI4U+WNRcSw5S4pOH7qFjd/veA5gC7TbqESR3tcj28ia95L/fYUDw11JKP7uqUKUAfVvV5Q== + dependencies: + call-bind "^1.0.8" + define-properties "^1.2.1" + dunder-proto "^1.0.1" + es-abstract "^1.23.6" + es-errors "^1.3.0" + get-intrinsic "^1.2.6" + gopd "^1.2.0" + which-builtin-type "^1.2.1" + +regexp.prototype.flags@^1.5.3: + version "1.5.3" + resolved "https://registry.yarnpkg.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.3.tgz#b3ae40b1d2499b8350ab2c3fe6ef3845d3a96f42" + integrity sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-errors "^1.3.0" + set-function-name "^2.0.2" + requires-port@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz" @@ -2505,11 +3830,25 @@ requizzle@^0.2.3: dependencies: lodash "^4.17.21" +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + resolve-pkg-maps@^1.0.0: version "1.0.0" resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz" integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== +resolve@^1.22.4: + version "1.22.10" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.22.10.tgz#b663e83ffb09bbf2386944736baae803029b8b39" + integrity sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w== + dependencies: + is-core-module "^2.16.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + retry@^0.12.0: version "0.12.0" resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" @@ -2520,6 +3859,11 @@ retry@^0.13.1: resolved "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz" integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + rimraf@^3.0.2: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" @@ -2527,6 +3871,13 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + rxjs@^7.8.1: version "7.8.1" resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz" @@ -2534,6 +3885,17 @@ rxjs@^7.8.1: dependencies: tslib "^2.1.0" +safe-array-concat@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/safe-array-concat/-/safe-array-concat-1.1.3.tgz#c9e54ec4f603b0bbb8e7e5007a5ee7aecd1538c3" + integrity sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + get-intrinsic "^1.2.6" + has-symbols "^1.1.0" + isarray "^2.0.5" + safe-buffer@5.2.1, safe-buffer@^5.0.1, safe-buffer@~5.2.0: version "5.2.1" resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" @@ -2544,6 +3906,15 @@ safe-buffer@~5.1.0, safe-buffer@~5.1.1: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-regex-test@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/safe-regex-test/-/safe-regex-test-1.1.0.tgz#7f87dfb67a3150782eaaf18583ff5d1711ac10c1" + integrity sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + is-regex "^1.2.1" + safe-stable-stringify@^2.3.1: version "2.5.0" resolved "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz" @@ -2554,7 +3925,12 @@ safe-stable-stringify@^2.3.1: resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== -semver@^7.1.2, semver@^7.3.5, semver@^7.6.3: +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.1.2, semver@^7.3.5, semver@^7.5.4, semver@^7.6.0, semver@^7.6.3: version "7.6.3" resolved "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz" integrity sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A== @@ -2610,6 +3986,16 @@ set-function-length@^1.2.1, set-function-length@^1.2.2: gopd "^1.0.1" has-property-descriptors "^1.0.2" +set-function-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/set-function-name/-/set-function-name-2.0.2.tgz#16a705c5a0dc2f5e638ca96d8a8cd4e1c2b90985" + integrity sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ== + dependencies: + define-data-property "^1.1.4" + es-errors "^1.3.0" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.2" + setimmediate@^1.0.5: version "1.0.5" resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" @@ -2620,6 +4006,47 @@ setprototypeof@1.2.0: resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +side-channel-list@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.0.tgz#10cb5984263115d3b7a0e336591e290a830af8ad" + integrity sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + side-channel-map "^1.0.1" + side-channel@^1.0.6: version "1.0.6" resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz" @@ -2630,6 +4057,17 @@ side-channel@^1.0.6: get-intrinsic "^1.2.4" object-inspect "^1.13.1" +side-channel@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.0.tgz#c3fcff9c4da932784873335ec9765fa94ff66bc9" + integrity sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.3" + side-channel-list "^1.0.0" + side-channel-map "^1.0.1" + side-channel-weakmap "^1.0.2" + signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz" @@ -2656,6 +4094,11 @@ simple-swizzle@^0.2.2: dependencies: is-arrayish "^0.3.1" +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + smart-buffer@^4.2.0: version "4.2.0" resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz" @@ -2712,6 +4155,11 @@ ssri@^8.0.0, ssri@^8.0.1: dependencies: minipass "^3.1.1" +stable-hash@^0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/stable-hash/-/stable-hash-0.0.4.tgz#55ae7dadc13e4b3faed13601587cec41859b42f7" + integrity sha512-LjdcbuBeLcdETCrPn9i8AYAZ1eCtu4ECAWtP7UleOiZ9LzVxRzzUZEoZ8zB24nhkQnDWyET0I+3sWokSDS3E7g== + stack-trace@0.0.x: version "0.0.10" resolved "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz" @@ -2731,6 +4179,38 @@ statuses@2.0.1: is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string.prototype.trim@^1.2.10: + version "1.2.10" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz#40b2dd5ee94c959b4dcfb1d65ce72e90da480c81" + integrity sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-data-property "^1.1.4" + define-properties "^1.2.1" + es-abstract "^1.23.5" + es-object-atoms "^1.0.0" + has-property-descriptors "^1.0.2" + +string.prototype.trimend@^1.0.8, string.prototype.trimend@^1.0.9: + version "1.0.9" + resolved "https://registry.yarnpkg.com/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz#62e2731272cd285041b36596054e9f66569b6942" + integrity sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ== + dependencies: + call-bind "^1.0.8" + call-bound "^1.0.2" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + +string.prototype.trimstart@^1.0.8: + version "1.0.8" + resolved "https://registry.yarnpkg.com/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz#7ee834dda8c7c17eff3118472bb35bfedaa34dde" + integrity sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg== + dependencies: + call-bind "^1.0.7" + define-properties "^1.2.1" + es-object-atoms "^1.0.0" + string_decoder@^1.1.1: version "1.3.0" resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" @@ -2752,7 +4232,12 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-json-comments@^3.1.0: +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@^3.1.0, strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== @@ -2769,6 +4254,16 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz#6eda4bd344a3c94aea376d4cc31bc77311039e09" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +tapable@^2.2.0: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-2.2.1.tgz#1967a73ef4060a82f12ab96af86d52fdb76eeca0" + integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ== + tar-fs@^2.0.0: version "2.1.1" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.1.tgz" @@ -2807,11 +4302,23 @@ text-hex@1.0.x: resolved "https://registry.npmjs.org/text-hex/-/text-hex-1.0.0.tgz" integrity sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg== +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + tmp@^0.2.1: version "0.2.3" resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz" integrity sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w== +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + toidentifier@1.0.1: version "1.0.1" resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" @@ -2837,6 +4344,28 @@ triple-beam@^1.3.0: resolved "https://registry.npmjs.org/triple-beam/-/triple-beam-1.4.1.tgz" integrity sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg== +ts-api-utils@^1.0.1, ts-api-utils@^1.3.0: + version "1.4.3" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-1.4.3.tgz#bfc2215fe6528fecab2b0fba570a2e8a4263b064" + integrity sha512-i3eMG77UTMD0hZhgRS562pv83RC6ukSAC2GMNWc+9dieh/+jDM5u5YG+NHX6VNDRHQcHwmsTHctP9LhbC3WxVw== + +ts-declaration-location@^1.0.0: + version "1.0.5" + resolved "https://registry.yarnpkg.com/ts-declaration-location/-/ts-declaration-location-1.0.5.tgz#96433afbf90a77ecd2391949a2cc43ffa5340de2" + integrity sha512-WqmlO9IoeYwCqJ2E9kHMcY9GZhhfLYItC3VnHDlPOrg6nNdUWS4wn4hhDZUPt60m1EvtjPIZyprTjpI992Bgzw== + dependencies: + minimatch "^10.0.1" + +tsconfig-paths@^3.15.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + tslib@2.7.0: version "2.7.0" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.7.0.tgz#d9b40c5c40ab59e8738f297df3087bf1a2690c01" @@ -2869,6 +4398,13 @@ twitter-api-v2@^1.15.1, twitter-api-v2@^1.18.2: resolved "https://registry.npmjs.org/twitter-api-v2/-/twitter-api-v2-1.18.2.tgz" integrity sha512-ggImmoAeVgETYqrWeZy+nWnDpwgTP+IvFEc03Pitt1HcgMX+Yw17rP38Fb5FFTinuyNvS07EPtAfZ184uIyB0A== +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.4.0.tgz#07b8203bfa7056c0657050e3ccd2c37730bab8f1" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-check@~0.3.2: version "0.3.2" resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" @@ -2876,6 +4412,11 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + type-is@~1.6.18: version "1.6.18" resolved "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz" @@ -2884,6 +4425,51 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typed-array-buffer@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz#a72395450a4869ec033fd549371b47af3a2ee536" + integrity sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw== + dependencies: + call-bound "^1.0.3" + es-errors "^1.3.0" + is-typed-array "^1.1.14" + +typed-array-byte-length@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz#8407a04f7d78684f3d252aa1a143d2b77b4160ce" + integrity sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg== + dependencies: + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.14" + +typed-array-byte-offset@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz#ae3698b8ec91a8ab945016108aef00d5bff12355" + integrity sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + for-each "^0.3.3" + gopd "^1.2.0" + has-proto "^1.2.0" + is-typed-array "^1.1.15" + reflect.getprototypeof "^1.0.9" + +typed-array-length@^1.0.7: + version "1.0.7" + resolved "https://registry.yarnpkg.com/typed-array-length/-/typed-array-length-1.0.7.tgz#ee4deff984b64be1e118b0de8c9c877d5ce73d3d" + integrity sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg== + dependencies: + call-bind "^1.0.7" + for-each "^0.3.3" + gopd "^1.0.1" + is-typed-array "^1.1.13" + possible-typed-array-names "^1.0.0" + reflect.getprototypeof "^1.0.6" + typescript@^5.3.3: version "5.7.2" resolved "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz" @@ -2921,6 +4507,16 @@ uint8arrays@^5.0.0, uint8arrays@^5.0.1: dependencies: multiformats "^13.0.0" +unbox-primitive@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/unbox-primitive/-/unbox-primitive-1.1.0.tgz#8d9d2c9edeea8460c7f35033a88867944934d1e2" + integrity sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw== + dependencies: + call-bound "^1.0.3" + has-bigints "^1.0.2" + has-symbols "^1.1.0" + which-boxed-primitive "^1.1.1" + underscore@~1.13.2: version "1.13.7" resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.7.tgz" @@ -2965,6 +4561,13 @@ unpipe@1.0.0, unpipe@~1.0.0: resolved "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz" integrity sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ== +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + url-parse@^1.5.3: version "1.5.10" resolved "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz" @@ -3042,7 +4645,59 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which@^2.0.2: +which-boxed-primitive@^1.1.0, which-boxed-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz#d76ec27df7fa165f18d5808374a5fe23c29b176e" + integrity sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA== + dependencies: + is-bigint "^1.1.0" + is-boolean-object "^1.2.1" + is-number-object "^1.1.1" + is-string "^1.1.1" + is-symbol "^1.1.1" + +which-builtin-type@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/which-builtin-type/-/which-builtin-type-1.2.1.tgz#89183da1b4907ab089a6b02029cc5d8d6574270e" + integrity sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q== + dependencies: + call-bound "^1.0.2" + function.prototype.name "^1.1.6" + has-tostringtag "^1.0.2" + is-async-function "^2.0.0" + is-date-object "^1.1.0" + is-finalizationregistry "^1.1.0" + is-generator-function "^1.0.10" + is-regex "^1.2.1" + is-weakref "^1.0.2" + isarray "^2.0.5" + which-boxed-primitive "^1.1.0" + which-collection "^1.0.2" + which-typed-array "^1.1.16" + +which-collection@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/which-collection/-/which-collection-1.0.2.tgz#627ef76243920a107e7ce8e96191debe4b16c2a0" + integrity sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw== + dependencies: + is-map "^2.0.3" + is-set "^2.0.3" + is-weakmap "^2.0.2" + is-weakset "^2.0.3" + +which-typed-array@^1.1.16, which-typed-array@^1.1.18: + version "1.1.18" + resolved "https://registry.yarnpkg.com/which-typed-array/-/which-typed-array-1.1.18.tgz#df2389ebf3fbb246a71390e90730a9edb6ce17ad" + integrity sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA== + dependencies: + available-typed-arrays "^1.0.7" + call-bind "^1.0.8" + call-bound "^1.0.3" + for-each "^0.3.3" + gopd "^1.2.0" + has-tostringtag "^1.0.2" + +which@^2.0.1, which@^2.0.2: version "2.0.2" resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== @@ -3082,7 +4737,7 @@ winston@^3.11.0: triple-beam "^1.3.0" winston-transport "^4.9.0" -word-wrap@~1.2.3: +word-wrap@^1.2.5, word-wrap@~1.2.3: version "1.2.5" resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz" integrity sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA== @@ -3121,6 +4776,11 @@ yaml@^2.2.1: resolved "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz" integrity sha512-7r0XPzioN/Q9kXBro/XPnA6kznR73DHq+GXh5ON7ZozRO6aMjbmiBuKste2wslTFkC5d1dw0GooOCepZXJ2SAg== +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + zod-to-json-schema@^3.22.3, zod-to-json-schema@^3.22.5: version "3.23.5" resolved "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.23.5.tgz"