@skillrecordings/cli 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/skill.mjs +0 -5
- package/bin/skill.ts +0 -1
- package/dist/{chunk-TFLLCHUX.js → chunk-54VQQSWT.js} +13 -2
- package/dist/chunk-5ACOI6Z3.js +198 -0
- package/dist/chunk-5ACOI6Z3.js.map +1 -0
- package/dist/{chunk-HCFBOGCL.js → chunk-EGBS3VJI.js} +4 -5
- package/dist/{config-523F4OBH.js → config-HLXR42M4.js} +3 -3
- package/dist/duckdb-source-T7EJUOC7.js +353 -0
- package/dist/duckdb-source-T7EJUOC7.js.map +1 -0
- package/dist/index.js +9334 -7543
- package/dist/index.js.map +1 -1
- package/dist/{pipeline-DRKFIH73.js → pipeline-H52QEIFE.js} +2 -2
- package/package.json +8 -6
- package/plugin/.claude-plugin/plugin.json +9 -0
- package/plugin/skills/front-inbox/SKILL.md +360 -0
- package/plugin/skills/front-inbox/examples/bulk-archive.md +16 -0
- package/plugin/skills/front-inbox/examples/triage-tt.md +16 -0
- package/.env.encrypted +0 -0
- package/dist/preload.js +0 -112
- package/dist/preload.js.map +0 -1
- /package/dist/{chunk-TFLLCHUX.js.map → chunk-54VQQSWT.js.map} +0 -0
- /package/dist/{chunk-HCFBOGCL.js.map → chunk-EGBS3VJI.js.map} +0 -0
- /package/dist/{config-523F4OBH.js.map → config-HLXR42M4.js.map} +0 -0
- /package/dist/{pipeline-DRKFIH73.js.map → pipeline-H52QEIFE.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../core/src/faq/duckdb-source.ts"],"sourcesContent":["/**\n * DuckDB Data Source for FAQ Mining\n *\n * Provides access to the cached Front conversations in DuckDB\n * instead of live Front API. Enables fast, repeatable extraction\n * without API rate limits.\n *\n * @module faq/duckdb-source\n */\n\nimport type { Conversation, Message } from '@skillrecordings/front-sdk'\nimport { shouldFilter } from './filters'\nimport type { DataSource, QueryOptions, ResolvedConversation } from './types'\n\n/**\n * Configuration for the DuckDB data source.\n */\nexport interface DuckDBSourceConfig {\n /** Path to the DuckDB database file */\n dbPath: string\n /** Filter by specific inbox IDs */\n inboxIds?: string[]\n /** Minimum thread message count */\n minThreadLength?: number\n /** Maximum thread message count */\n maxThreadLength?: number\n /** Filter by conversation status (default: ['archived']) */\n statusFilter?: string[]\n}\n\n/**\n * Cache statistics from DuckDB.\n */\nexport interface CacheStats {\n /** Total conversations in cache */\n totalConversations: number\n /** Conversations matching filters */\n filteredConversations: number\n /** Total messages in cache */\n totalMessages: number\n /** Unique inboxes */\n inboxCount: number\n /** Date range of conversations */\n dateRange: {\n oldest: Date | null\n newest: Date | null\n }\n}\n\n/**\n * Row type from DuckDB conversations table.\n */\ninterface ConversationRow {\n id: string\n inbox_id: string\n subject: string | null\n status: string | null\n customer_email: string | null\n customer_name: string | null\n tags: string[] | null\n assignee_email: string | null\n created_at: Date | null\n last_message_at: Date | null\n synced_at: Date | null\n parent_id: string | null\n thread_depth: number | null\n}\n\n/**\n * Row type from DuckDB messages table.\n */\ninterface MessageRow {\n id: string\n conversation_id: string\n is_inbound: boolean\n author_email: string | null\n author_name: string | null\n body_text: string | null\n body_html: string | null\n created_at: Date | null\n}\n\n/**\n * Inbox ID to App slug mapping.\n * Derived from the DuckDB inboxes table and app registry.\n */\nconst INBOX_TO_APP: Record<string, string> = {\n inb_1bwzr: 'epic-react', // KCD Support (Epic React is the main product)\n inb_3srbb: 'total-typescript',\n inb_1c77r: 'egghead',\n inb_jqs11: 'epic-ai',\n inb_3pqh3: 'pro-tailwind',\n inb_2odqf: 'just-javascript',\n inb_4bj7r: 'ai-hero',\n inb_3bkef: 'testing-accessibility',\n inb_jqs2t: 'epic-web',\n inb_1zh3b: 'egghead',\n inb_43olj: 'pro-nextjs',\n}\n\n/**\n * App slug to inbox ID mapping (reverse of above).\n */\nconst APP_TO_INBOX: Record<string, string[]> = Object.entries(\n INBOX_TO_APP\n).reduce(\n (acc, [inboxId, appSlug]) => {\n if (!acc[appSlug]) {\n acc[appSlug] = []\n }\n acc[appSlug]!.push(inboxId)\n return acc\n },\n {} as Record<string, string[]>\n)\n\n/**\n * Convert a DuckDB message row to Front SDK Message format.\n */\nfunction toFrontMessage(row: MessageRow): Message {\n const createdAt = toJSDate(row.created_at)\n const createdAtTimestamp = createdAt\n ? Math.floor(createdAt.getTime() / 1000)\n : 0\n\n return {\n id: row.id,\n type: 'email',\n is_inbound: row.is_inbound,\n is_draft: false,\n error_type: null,\n version: null,\n created_at: createdAtTimestamp,\n subject: '',\n blurb: row.body_text?.slice(0, 100) ?? '',\n body: row.body_html ?? row.body_text ?? '',\n text: row.body_text ?? '',\n author: row.author_email\n ? {\n id: row.author_email,\n email: row.author_email,\n first_name: row.author_name?.split(' ')[0] ?? '',\n last_name: row.author_name?.split(' ').slice(1).join(' ') ?? '',\n is_admin: !row.is_inbound,\n is_available: true,\n is_blocked: false,\n }\n : null,\n recipients: [],\n attachments: [],\n metadata: {},\n _links: {\n self: `https://api.frontapp.com/messages/${row.id}`,\n related: {\n conversation: `https://api.frontapp.com/conversations/${row.conversation_id}`,\n },\n },\n }\n}\n\n/**\n * Convert a DuckDB conversation row to Front SDK Conversation format.\n */\nfunction toFrontConversation(row: ConversationRow): Conversation {\n const createdAt = toJSDate(row.created_at)\n const createdAtTimestamp = createdAt\n ? Math.floor(createdAt.getTime() / 1000)\n : 0\n\n return {\n id: row.id,\n subject: row.subject ?? '',\n status: row.status === 'archived' ? 'archived' : (row.status as any),\n assignee: row.assignee_email\n ? {\n id: row.assignee_email,\n email: row.assignee_email,\n first_name: '',\n last_name: '',\n }\n : null,\n recipient: row.customer_email\n ? {\n handle: row.customer_email,\n role: 'from',\n }\n : null,\n tags: (row.tags ?? []).map((tag) => ({\n id: tag,\n name: tag,\n })),\n links: [],\n created_at: createdAtTimestamp,\n is_private: false,\n scheduled_reminders: [],\n metadata: {},\n _links: {\n self: `https://api.frontapp.com/conversations/${row.id}`,\n related: {\n events: '',\n followers: '',\n messages: '',\n comments: '',\n inboxes: '',\n },\n },\n }\n}\n\n/**\n * Extract the customer's question from conversation messages.\n * Returns the first inbound message text.\n */\nfunction extractQuestion(messages: Message[]): string {\n // Sort by timestamp ascending\n const sorted = [...messages].sort((a, b) => a.created_at - b.created_at)\n\n // Find first inbound message\n const firstInbound = sorted.find((m) => m.is_inbound)\n if (!firstInbound) {\n return ''\n }\n\n // Prefer text, fall back to stripped HTML\n const text =\n firstInbound.text ??\n firstInbound.body\n ?.replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim() ??\n ''\n\n return text\n}\n\n/**\n * Extract the agent's answer from conversation messages.\n * Returns the last outbound message before resolution.\n */\nfunction extractAnswer(messages: Message[]): string {\n // Sort by timestamp descending\n const sorted = [...messages].sort((a, b) => b.created_at - a.created_at)\n\n // Find last outbound message\n const lastOutbound = sorted.find((m) => !m.is_inbound)\n if (!lastOutbound) {\n return ''\n }\n\n return (\n lastOutbound.text ??\n lastOutbound.body\n ?.replace(/<[^>]*>/g, ' ')\n .replace(/\\s+/g, ' ')\n .trim() ??\n ''\n )\n}\n\n/**\n * Check if a question looks like spam or noise.\n * Uses the comprehensive filter module for consistency.\n */\nfunction isSpamOrNoise(text: string, senderEmail?: string): boolean {\n // Too short\n if (text.trim().length < 20) return true\n\n // Use the comprehensive filter module\n const result = shouldFilter(text, senderEmail)\n return result.filtered\n}\n\n// DuckDB connection interface\ninterface DuckDBConnection {\n runAndReadAll(\n sql: string,\n values?: Record<string, any>\n ): Promise<{\n getRowObjects(): Record<string, any>[]\n getRowObjectsJS(): Record<string, any>[]\n }>\n closeSync(): void\n}\n\ninterface DuckDBInstanceType {\n connect(): Promise<DuckDBConnection>\n}\n\n/**\n * Convert a DuckDB value to a JS Date.\n * DuckDB returns custom DuckDBTimestampValue objects.\n */\nfunction toJSDate(value: any): Date | null {\n if (value === null || value === undefined) {\n return null\n }\n // If it's already a Date, return it\n if (value instanceof Date) {\n return value\n }\n // DuckDB timestamp values have a micros property (BigInt)\n if (typeof value === 'object' && 'micros' in value) {\n // Convert microseconds to milliseconds\n const ms = Number(value.micros) / 1000\n return new Date(ms)\n }\n // If it's a number (unix timestamp in seconds or ms)\n if (typeof value === 'number') {\n // Check if it's seconds (< 10 billion) or milliseconds\n if (value < 1000000000) {\n return new Date(value * 1000)\n }\n return new Date(value)\n }\n // If it's a string, try parsing\n if (typeof value === 'string') {\n return new Date(value)\n }\n return null\n}\n\n/**\n * Create a DuckDB data source for FAQ mining.\n *\n * @param config - DuckDB source configuration\n * @returns DataSource implementation\n *\n * @example\n * ```ts\n * const source = await createDuckDBSource({\n * dbPath: '~/skill/data/front-cache.db',\n * inboxIds: ['inb_3srbb'], // Total TypeScript\n * })\n *\n * const conversations = await source.getConversations({\n * appId: 'total-typescript',\n * since: new Date('2024-01-01'),\n * limit: 500,\n * })\n * ```\n */\nexport async function createDuckDBSource(\n config: DuckDBSourceConfig\n): Promise<DataSource> {\n // Dynamically import DuckDB to avoid bundling issues\n const { DuckDBInstance } = await import('@duckdb/node-api')\n\n const instance = (await DuckDBInstance.create(\n config.dbPath\n )) as unknown as DuckDBInstanceType\n const connection = await instance.connect()\n\n const statusFilter = config.statusFilter ?? ['archived']\n\n return {\n name: 'duckdb-cache',\n\n async getConversations(\n options: QueryOptions\n ): Promise<ResolvedConversation[]> {\n const { appId, since, limit = 500 } = options\n\n // Resolve inbox IDs from app slug\n let inboxIds = config.inboxIds\n if (!inboxIds && appId) {\n inboxIds = APP_TO_INBOX[appId]\n if (!inboxIds || inboxIds.length === 0) {\n console.warn(`No inbox mapping found for app: ${appId}`)\n return []\n }\n }\n\n // Build query with filters using named parameters\n const whereClauses: string[] = []\n const params: Record<string, any> = {}\n\n // Status filter\n if (statusFilter.length > 0) {\n whereClauses.push(\n `status IN (${statusFilter.map((_, i) => `$status_${i}`).join(', ')})`\n )\n statusFilter.forEach((s, i) => {\n params[`status_${i}`] = s\n })\n }\n\n // Inbox filter\n if (inboxIds && inboxIds.length > 0) {\n whereClauses.push(\n `inbox_id IN (${inboxIds.map((_, i) => `$inbox_${i}`).join(', ')})`\n )\n inboxIds.forEach((id, i) => {\n params[`inbox_${i}`] = id\n })\n }\n\n // Date filter - convert to ISO string for DuckDB\n if (since) {\n whereClauses.push(`last_message_at >= $since::TIMESTAMP`)\n params.since = since.toISOString()\n }\n\n // Thread length filters\n if (config.minThreadLength !== undefined) {\n whereClauses.push(`thread_depth >= $minThreadLength`)\n params.minThreadLength = config.minThreadLength\n }\n if (config.maxThreadLength !== undefined) {\n whereClauses.push(`thread_depth <= $maxThreadLength`)\n params.maxThreadLength = config.maxThreadLength\n }\n\n const whereClause =\n whereClauses.length > 0 ? `WHERE ${whereClauses.join(' AND ')}` : ''\n\n const query = `\n SELECT *\n FROM conversations\n ${whereClause}\n ORDER BY last_message_at DESC\n LIMIT $limit\n `\n params.limit = limit\n\n const reader = await connection.runAndReadAll(query, params)\n const rows = reader.getRowObjectsJS() as ConversationRow[]\n\n console.log(`DuckDB: Found ${rows.length} conversations matching filters`)\n\n // Fetch messages and convert to ResolvedConversation\n const results: ResolvedConversation[] = []\n let processed = 0\n\n for (const row of rows) {\n processed++\n if (processed % 100 === 0) {\n console.log(`Processing ${processed}/${rows.length}...`)\n }\n\n // Get messages for this conversation\n const messagesReader = await connection.runAndReadAll(\n `SELECT * FROM messages WHERE conversation_id = $convId ORDER BY created_at ASC`,\n { convId: row.id }\n )\n const messageRows = messagesReader.getRowObjectsJS() as MessageRow[]\n\n if (messageRows.length === 0) {\n continue // Skip conversations without messages\n }\n\n const messages = messageRows.map(toFrontMessage)\n const conversation = toFrontConversation(row)\n\n // Extract Q&A\n const question = extractQuestion(messages)\n const answer = extractAnswer(messages)\n\n if (!question || !answer) {\n continue // Skip if we can't extract Q&A\n }\n\n // Get sender email from first inbound message for filtering\n const firstInbound = messages.find((m) => m.is_inbound)\n const senderEmail = firstInbound?.author?.email\n\n // Filter spam using comprehensive filter module\n if (isSpamOrNoise(question, senderEmail)) {\n continue\n }\n\n // Also filter answers that are just auto-replies\n const answerFilter = shouldFilter(answer)\n if (answerFilter.filtered && answerFilter.reason === 'auto_reply') {\n continue\n }\n\n // Filter spam-tagged conversations\n const tagNames = (row.tags ?? []).map((t) => t.toLowerCase())\n if (tagNames.includes('spam') || tagNames.includes('collaboration')) {\n continue\n }\n\n // Determine appId from inbox\n const resolvedAppId = appId ?? INBOX_TO_APP[row.inbox_id] ?? 'unknown'\n\n results.push({\n conversationId: row.id,\n question,\n answer,\n subject: row.subject ?? '',\n resolvedAt: toJSDate(row.last_message_at) ?? new Date(),\n appId: resolvedAppId,\n wasUnchanged: false, // Unknown from cache\n draftSimilarity: undefined,\n tags: row.tags ?? [],\n _raw: {\n conversation,\n messages,\n },\n })\n }\n\n console.log(\n `DuckDB: Extracted ${results.length} conversations with Q&A pairs`\n )\n return results\n },\n\n async getMessages(conversationId: string): Promise<Message[]> {\n const reader = await connection.runAndReadAll(\n `SELECT * FROM messages WHERE conversation_id = $convId ORDER BY created_at ASC`,\n { convId: conversationId }\n )\n const rows = reader.getRowObjectsJS() as MessageRow[]\n return rows.map(toFrontMessage)\n },\n\n async getStats(): Promise<CacheStats> {\n // Total conversations\n const totalReader = await connection.runAndReadAll(\n `SELECT COUNT(*) as count FROM conversations`\n )\n const totalRows = totalReader.getRowObjectsJS() as Array<{\n count: bigint | number\n }>\n const totalConversations = Number(totalRows[0]?.count ?? 0)\n\n // Filtered conversations\n const filterClauses: string[] = []\n const filterParams: Record<string, any> = {}\n\n if (statusFilter.length > 0) {\n filterClauses.push(\n `status IN (${statusFilter.map((_, i) => `$status_${i}`).join(', ')})`\n )\n statusFilter.forEach((s, i) => {\n filterParams[`status_${i}`] = s\n })\n }\n if (config.inboxIds && config.inboxIds.length > 0) {\n filterClauses.push(\n `inbox_id IN (${config.inboxIds.map((_, i) => `$inbox_${i}`).join(', ')})`\n )\n config.inboxIds.forEach((id, i) => {\n filterParams[`inbox_${i}`] = id\n })\n }\n\n const filterWhere =\n filterClauses.length > 0 ? `WHERE ${filterClauses.join(' AND ')}` : ''\n\n const filteredReader = await connection.runAndReadAll(\n `SELECT COUNT(*) as count FROM conversations ${filterWhere}`,\n filterParams\n )\n const filteredRows = filteredReader.getRowObjectsJS() as Array<{\n count: bigint | number\n }>\n const filteredConversations = Number(filteredRows[0]?.count ?? 0)\n\n // Total messages\n const messagesReader = await connection.runAndReadAll(\n `SELECT COUNT(*) as count FROM messages`\n )\n const messagesRows = messagesReader.getRowObjectsJS() as Array<{\n count: bigint | number\n }>\n const totalMessages = Number(messagesRows[0]?.count ?? 0)\n\n // Inbox count\n const inboxReader = await connection.runAndReadAll(\n `SELECT COUNT(DISTINCT inbox_id) as count FROM conversations`\n )\n const inboxRows = inboxReader.getRowObjectsJS() as Array<{\n count: bigint | number\n }>\n const inboxCount = Number(inboxRows[0]?.count ?? 0)\n\n // Date range\n const dateReader = await connection.runAndReadAll(\n `SELECT MIN(last_message_at) as oldest, MAX(last_message_at) as newest FROM conversations`\n )\n const dateRows = dateReader.getRowObjectsJS() as Array<{\n oldest: Date | string | null\n newest: Date | string | null\n }>\n const dateRange = {\n oldest: toJSDate(dateRows[0]?.oldest),\n newest: toJSDate(dateRows[0]?.newest),\n }\n\n return {\n totalConversations,\n filteredConversations,\n totalMessages,\n inboxCount,\n dateRange,\n }\n },\n\n async close(): Promise<void> {\n connection.closeSync()\n },\n }\n}\n\n/**\n * Get inbox IDs for an app slug.\n * Returns undefined if no mapping exists.\n */\nexport function getInboxIdsForApp(appSlug: string): string[] | undefined {\n return APP_TO_INBOX[appSlug]\n}\n\n/**\n * Get app slug for an inbox ID.\n * Returns undefined if no mapping exists.\n */\nexport function getAppForInbox(inboxId: string): string | undefined {\n return INBOX_TO_APP[inboxId]\n}\n"],"mappings":"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","names":[]}
|