Add 260+ Claude Code skills from skills.sh
Complete collection of AI agent skills including: - Frontend Development (Vue, React, Next.js, Three.js) - Backend Development (NestJS, FastAPI, Node.js) - Mobile Development (React Native, Expo) - Testing (E2E, frontend, webapp) - DevOps (GitHub Actions, CI/CD) - Marketing (SEO, copywriting, analytics) - Security (binary analysis, vulnerability scanning) - And many more... Synchronized from: https://skills.sh/ Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
173
multi-ai-brainstorm/SKILL.md
Normal file
173
multi-ai-brainstorm/SKILL.md
Normal file
@@ -0,0 +1,173 @@
|
||||
---
|
||||
name: multi-ai-brainstorm
|
||||
description: "Multi-AI brainstorming using Qwen coder-model. Collaborate with multiple AI agents (content, seo, smm, pm, code, design, web, app) for expert-level ideation. Use before any creative work for diverse perspectives."
|
||||
---
|
||||
|
||||
# Multi-AI Brainstorm 🧠
|
||||
|
||||
> **Powered by Qwen Coder-Model** from PromptArch
|
||||
> Enables collaborative brainstorming with 8 specialized AI agents
|
||||
|
||||
## Overview
|
||||
|
||||
This skill transforms Claude into a multi-brain collaboration system, leveraging Qwen's coder-model to provide diverse expert perspectives through specialized AI agents. Each agent brings unique domain expertise to the brainstorming process.
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Authentication**: First use will prompt for Qwen API key or OAuth token
|
||||
2. **Agent Selection**: Choose from 8 specialized AI agents or use all for comprehensive brainstorming
|
||||
3. **Collaborative Process**: Each agent provides insights from their domain perspective
|
||||
4. **Synthesis**: Claude synthesizes all perspectives into actionable insights
|
||||
|
||||
## Available AI Agents
|
||||
|
||||
| Agent | Expertise | Best For |
|
||||
|-------|-----------|----------|
|
||||
| **content** | Copywriting & Communication | Blog posts, marketing copy, documentation |
|
||||
| **seo** | Search Engine Optimization | SEO audits, keyword research, content strategy |
|
||||
| **smm** | Social Media Marketing | Content calendars, campaign strategies |
|
||||
| **pm** | Product Management | PRDs, roadmaps, feature prioritization |
|
||||
| **code** | Software Architecture | Backend logic, algorithms, technical design |
|
||||
| **design** | UI/UX Design | Mockups, design systems, user flows |
|
||||
| **web** | Frontend Development | Responsive sites, web apps |
|
||||
| **app** | Mobile Development | iOS/Android apps, mobile-first design |
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Brainstorming
|
||||
|
||||
```bash
|
||||
# Start brainstorming with all agents
|
||||
/multi-ai-brainstorm "I want to build a collaborative code editor"
|
||||
|
||||
# Use specific agents
|
||||
/multi-ai-brainstorm "mobile app for fitness tracking" --agents design,app,pm
|
||||
|
||||
# Deep dive with one agent
|
||||
/multi-ai-brainstorm "SEO strategy for SaaS product" --agents seo
|
||||
```
|
||||
|
||||
### Configuration
|
||||
|
||||
The skill stores credentials in `~/.claude/qwen-credentials.json`:
|
||||
```json
|
||||
{
|
||||
"apiKey": "sk-...",
|
||||
"endpoint": "https://dashscope-intl.aliyuncs.com/compatible-mode/v1"
|
||||
}
|
||||
```
|
||||
|
||||
## Agent Prompts
|
||||
|
||||
Each agent has specialized system prompts:
|
||||
|
||||
### Content Agent
|
||||
Expert copywriter focused on creating engaging, clear, and persuasive content for various formats and audiences.
|
||||
|
||||
### SEO Agent
|
||||
Search engine optimization specialist with expertise in technical SEO, content strategy, and performance analytics.
|
||||
|
||||
### SMM Agent
|
||||
Social media manager specializing in multi-platform content strategies, community engagement, and viral marketing.
|
||||
|
||||
### PM Agent
|
||||
Product manager experienced in PRD creation, roadmap planning, stakeholder management, and agile methodologies.
|
||||
|
||||
### Code Agent
|
||||
Software architect focused on backend logic, algorithms, API design, and system architecture.
|
||||
|
||||
### Design Agent
|
||||
UI/UX designer specializing in user research, interaction design, visual design systems, and accessibility.
|
||||
|
||||
### Web Agent
|
||||
Frontend developer expert in responsive web design, modern frameworks (React, Vue, Angular), and web performance.
|
||||
|
||||
### App Agent
|
||||
Mobile app developer specializing in iOS/Android development, React Native, Flutter, and mobile-first design patterns.
|
||||
|
||||
## Authentication Methods
|
||||
|
||||
### 1. API Key (Simple)
|
||||
```bash
|
||||
# You'll be prompted for your Qwen API key
|
||||
# Get your key at: https://help.aliyun.com/zh/dashscope/
|
||||
```
|
||||
|
||||
### 2. OAuth (Recommended - 2000 free daily requests)
|
||||
```bash
|
||||
# The skill will open a browser window for OAuth flow
|
||||
# Or provide the device code manually
|
||||
```
|
||||
|
||||
## Examples
|
||||
|
||||
### Product Ideation
|
||||
```bash
|
||||
/multi-ai-brainstorm "I want to create a AI-powered task management app" --agents pm,design,code
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- **PM Agent**: Feature prioritization, user personas, success metrics
|
||||
- **Design Agent**: UX patterns, visual direction, user flows
|
||||
- **Code Agent**: Architecture recommendations, tech stack selection
|
||||
|
||||
### Content Strategy
|
||||
```bash
|
||||
/multi-ai-brainstorm "Blog content strategy for developer tools startup" --agents content,seo,smm
|
||||
```
|
||||
|
||||
**Output:**
|
||||
- **Content Agent**: Content pillars, editorial calendar, tone guidelines
|
||||
- **SEO Agent**: Keyword research, on-page optimization, link building
|
||||
- **SMM Agent**: Social distribution, engagement tactics, viral loops
|
||||
|
||||
## Technical Details
|
||||
|
||||
**API Endpoint**: Uses PromptArch proxy at `https://www.rommark.dev/tools/promptarch/api/qwen/chat`
|
||||
|
||||
**Model**: `coder-model` - Qwen's code-optimized model
|
||||
|
||||
**Rate Limits**:
|
||||
- OAuth: 2000 free daily requests
|
||||
- API Key: Based on your Qwen account plan
|
||||
|
||||
**Streaming**: Supports real-time streaming responses for longer brainstorming sessions
|
||||
|
||||
## Tips for Best Results
|
||||
|
||||
1. **Be Specific**: More context = better insights from each agent
|
||||
2. **Combine Agents**: Use complementary agents (e.g., design + pm + code)
|
||||
3. **Iterate**: Follow up with questions to dive deeper into specific insights
|
||||
4. **Provide Context**: Share your target audience, constraints, and goals
|
||||
5. **Use Examples**: Show similar products or content for reference
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
**"Authentication failed"**
|
||||
- Check your API key or OAuth token
|
||||
- Verify endpoint URL is correct
|
||||
- Try running `/multi-ai-brainstorm --reauth`
|
||||
|
||||
**"Agent timeout"**
|
||||
- Check your internet connection
|
||||
- The Qwen API might be experiencing high load
|
||||
- Try again in a few moments
|
||||
|
||||
**"Unexpected response format"**
|
||||
- The API response format may have changed
|
||||
- Report the issue and include the error message
|
||||
|
||||
## Development
|
||||
|
||||
**Skill Location**: `~/.claude/skills/multi-ai-brainstorm/`
|
||||
|
||||
**Key Files**:
|
||||
- `SKILL.md` - This file
|
||||
- `qwen-client.js` - Qwen API client
|
||||
- `brainstorm-orchestrator.js` - Multi-agent coordination
|
||||
|
||||
**Contributing**: Modify the agent prompts in `brainstorm-orchestrator.js` to customize brainstorming behavior.
|
||||
|
||||
## License
|
||||
|
||||
This skill uses the Qwen API which is subject to Alibaba Cloud's terms of service.
|
||||
310
multi-ai-brainstorm/brainstorm-orchestrator.js
Normal file
310
multi-ai-brainstorm/brainstorm-orchestrator.js
Normal file
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* Multi-AI Brainstorm Orchestrator
|
||||
* Coordinates multiple specialized AI agents for collaborative brainstorming
|
||||
*/
|
||||
|
||||
const qwenClient = require('./qwen-client.js');
|
||||
|
||||
/**
|
||||
* Agent System Prompts
|
||||
*/
|
||||
const AGENT_SYSTEM_PROMPTS = {
|
||||
content: `You are an expert Content Specialist and Copywriter. Your role is to provide insights on content creation, messaging, and communication strategies.
|
||||
|
||||
Focus on:
|
||||
- Content tone and voice
|
||||
- Audience engagement
|
||||
- Content structure and flow
|
||||
- Clarity and persuasiveness
|
||||
- Brand storytelling
|
||||
|
||||
Provide practical, actionable content insights.`,
|
||||
|
||||
seo: `You are an expert SEO Specialist with deep knowledge of search engine optimization, content strategy, and digital marketing.
|
||||
|
||||
Focus on:
|
||||
- Keyword research and strategy
|
||||
- On-page and technical SEO
|
||||
- Content optimization for search
|
||||
- Link building and authority
|
||||
- SEO performance metrics
|
||||
- Competitor SEO analysis
|
||||
|
||||
Provide specific, data-driven SEO recommendations.`,
|
||||
|
||||
smm: `You are an expert Social Media Manager specializing in multi-platform content strategies, community engagement, and viral marketing.
|
||||
|
||||
Focus on:
|
||||
- Platform-specific content strategies (LinkedIn, Twitter, Instagram, TikTok, etc.)
|
||||
- Content calendars and scheduling
|
||||
- Community building and engagement
|
||||
- Influencer collaboration strategies
|
||||
- Social media analytics and KPIs
|
||||
- Viral content mechanics
|
||||
|
||||
Provide actionable social media marketing insights.`,
|
||||
|
||||
pm: `You are an expert Product Manager with extensive experience in product strategy, PRD creation, roadmap planning, and stakeholder management.
|
||||
|
||||
Focus on:
|
||||
- Product vision and strategy
|
||||
- Feature prioritization frameworks
|
||||
- User personas and use cases
|
||||
- Go-to-market strategies
|
||||
- Success metrics and KPIs
|
||||
- Agile development processes
|
||||
- Stakeholder communication
|
||||
|
||||
Provide structured product management insights.`,
|
||||
|
||||
code: `You are an expert Software Architect specializing in backend logic, system design, algorithms, and technical implementation.
|
||||
|
||||
Focus on:
|
||||
- System architecture and design patterns
|
||||
- Algorithm design and optimization
|
||||
- API design and integration
|
||||
- Database design and optimization
|
||||
- Security best practices
|
||||
- Scalability and performance
|
||||
- Technology stack recommendations
|
||||
|
||||
Provide concrete technical implementation guidance.`,
|
||||
|
||||
design: `You are a world-class UI/UX Designer with deep expertise in user research, interaction design, visual design systems, and modern design tools.
|
||||
|
||||
Focus on:
|
||||
- User research and persona development
|
||||
- Information architecture and navigation
|
||||
- Visual design systems (color, typography, spacing)
|
||||
- Interaction design and micro-interactions
|
||||
- Design trends and best practices
|
||||
- Accessibility and inclusive design
|
||||
- Design tools and deliverables
|
||||
|
||||
Provide specific, actionable UX recommendations.`,
|
||||
|
||||
web: `You are an expert Frontend Developer specializing in responsive web design, modern JavaScript frameworks, and web performance optimization.
|
||||
|
||||
Focus on:
|
||||
- Modern frontend frameworks (React, Vue, Angular, Svelte)
|
||||
- Responsive design and mobile-first approach
|
||||
- Web performance optimization
|
||||
- CSS strategies (Tailwind, CSS-in-JS, styled-components)
|
||||
- Component libraries and design systems
|
||||
- Progressive Web Apps
|
||||
- Browser compatibility
|
||||
|
||||
Provide practical frontend development insights.`,
|
||||
|
||||
app: `You are an expert Mobile App Developer specializing in iOS and Android development, React Native, Flutter, and mobile-first design patterns.
|
||||
|
||||
Focus on:
|
||||
- Mobile app architecture (native vs cross-platform)
|
||||
- Platform-specific best practices (iOS, Android)
|
||||
- Mobile UI/UX patterns
|
||||
- Performance optimization for mobile
|
||||
- App store optimization (ASO)
|
||||
- Mobile-specific constraints and opportunities
|
||||
- Push notifications and engagement
|
||||
|
||||
Provide actionable mobile development insights.`
|
||||
};
|
||||
|
||||
/**
|
||||
* Available agents
|
||||
*/
|
||||
const AVAILABLE_AGENTS = Object.keys(AGENT_SYSTEM_PROMPTS);
|
||||
|
||||
/**
|
||||
* Brainstorm orchestrator class
|
||||
*/
|
||||
class BrainstormOrchestrator {
|
||||
constructor() {
|
||||
this.agents = AVAILABLE_AGENTS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate agent selection
|
||||
*/
|
||||
validateAgents(selectedAgents) {
|
||||
if (!selectedAgents || selectedAgents.length === 0) {
|
||||
return this.agents; // Return all agents if none specified
|
||||
}
|
||||
|
||||
const valid = selectedAgents.filter(agent => this.agents.includes(agent));
|
||||
const invalid = selectedAgents.filter(agent => !this.agents.includes(agent));
|
||||
|
||||
if (invalid.length > 0) {
|
||||
console.warn(`⚠️ Unknown agents ignored: ${invalid.join(', ')}`);
|
||||
}
|
||||
|
||||
return valid.length > 0 ? valid : this.agents;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate brainstorming prompt for a specific agent
|
||||
*/
|
||||
generateAgentPrompt(topic, agent) {
|
||||
const systemPrompt = AGENT_SYSTEM_PROMPTS[agent];
|
||||
|
||||
return `# Brainstorming Request
|
||||
|
||||
**Topic**: ${topic}
|
||||
|
||||
**Your Role**: ${agent.toUpperCase()} Specialist
|
||||
|
||||
**Instructions**:
|
||||
1. Analyze this topic from your ${agent} perspective
|
||||
2. Provide 3-5 unique insights or recommendations
|
||||
3. Be specific and actionable
|
||||
4. Consider opportunities, challenges, and best practices
|
||||
5. Think creatively but stay grounded in practical reality
|
||||
|
||||
Format your response as clear bullet points or numbered lists.
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute brainstorming with multiple agents
|
||||
*/
|
||||
async brainstorm(topic, options = {}) {
|
||||
const {
|
||||
agents = [],
|
||||
concurrency = 3
|
||||
} = options;
|
||||
|
||||
const selectedAgents = this.validateAgents(agents);
|
||||
const results = {};
|
||||
|
||||
console.log(`\n🧠 Multi-AI Brainstorming Session`);
|
||||
console.log(`📝 Topic: ${topic}`);
|
||||
console.log(`👥 Agents: ${selectedAgents.map(a => a.toUpperCase()).join(', ')}`);
|
||||
console.log(`\n⏳ Gathering insights...\n`);
|
||||
|
||||
// Process agents in batches for controlled concurrency
|
||||
for (let i = 0; i < selectedAgents.length; i += concurrency) {
|
||||
const batch = selectedAgents.slice(i, i + concurrency);
|
||||
|
||||
const batchPromises = batch.map(async (agent) => {
|
||||
try {
|
||||
const userPrompt = this.generateAgentPrompt(topic, agent);
|
||||
const messages = [
|
||||
{ role: 'system', content: AGENT_SYSTEM_PROMPTS[agent] },
|
||||
{ role: 'user', content: userPrompt }
|
||||
];
|
||||
|
||||
const response = await qwenClient.chatCompletion(messages, {
|
||||
temperature: 0.8,
|
||||
maxTokens: 1000
|
||||
});
|
||||
|
||||
return { agent, response, success: true };
|
||||
} catch (error) {
|
||||
return { agent, error: error.message, success: false };
|
||||
}
|
||||
});
|
||||
|
||||
const batchResults = await Promise.all(batchPromises);
|
||||
|
||||
for (const result of batchResults) {
|
||||
if (result.success) {
|
||||
results[result.agent] = result.response;
|
||||
console.log(`✓ ${result.agent.toUpperCase()} Agent: Insights received`);
|
||||
} else {
|
||||
console.error(`✗ ${result.agent.toUpperCase()} Agent: ${result.error}`);
|
||||
results[result.agent] = `[Error: ${result.error}]`;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
topic,
|
||||
agents: selectedAgents,
|
||||
results,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Format brainstorming results for display
|
||||
*/
|
||||
formatResults(brainstormData) {
|
||||
let output = `\n${'='.repeat(60)}\n`;
|
||||
output += `🧠 MULTI-AI BRAINSTORM RESULTS\n`;
|
||||
output += `${'='.repeat(60)}\n\n`;
|
||||
output += `📝 Topic: ${brainstormData.topic}\n`;
|
||||
output += `👥 Agents: ${brainstormData.agents.map(a => a.toUpperCase()).join(', ')}\n`;
|
||||
output += `🕐 ${new Date(brainstormData.timestamp).toLocaleString()}\n\n`;
|
||||
|
||||
for (const agent of brainstormData.agents) {
|
||||
const response = brainstormData.results[agent];
|
||||
output += `${'─'.repeat(60)}\n`;
|
||||
output += `🤖 ${agent.toUpperCase()} AGENT INSIGHTS\n`;
|
||||
output += `${'─'.repeat(60)}\n\n`;
|
||||
output += `${response}\n\n`;
|
||||
}
|
||||
|
||||
output += `${'='.repeat(60)}\n`;
|
||||
output += `✨ Brainstorming complete! Use these insights to inform your project.\n`;
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* List available agents
|
||||
*/
|
||||
listAgents() {
|
||||
console.log('\n🤖 Available AI Agents:\n');
|
||||
|
||||
const agentDescriptions = {
|
||||
content: 'Copywriting & Communication',
|
||||
seo: 'Search Engine Optimization',
|
||||
smm: 'Social Media Marketing',
|
||||
pm: 'Product Management',
|
||||
code: 'Software Architecture',
|
||||
design: 'UI/UX Design',
|
||||
web: 'Frontend Development',
|
||||
app: 'Mobile Development'
|
||||
};
|
||||
|
||||
for (const agent of this.agents) {
|
||||
const desc = agentDescriptions[agent] || '';
|
||||
console.log(` • ${agent.padEnd(10)} - ${desc}`);
|
||||
}
|
||||
console.log('');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Main brainstorm function
|
||||
*/
|
||||
async function multiAIBrainstorm(topic, options = {}) {
|
||||
// Initialize client
|
||||
const isInitialized = await qwenClient.initialize();
|
||||
|
||||
if (!isInitialized || !qwenClient.isAuthenticated()) {
|
||||
console.log('\n🔐 Multi-AI Brainstorm requires Qwen API authentication\n');
|
||||
await qwenClient.promptForCredentials();
|
||||
}
|
||||
|
||||
const orchestrator = new BrainstormOrchestrator();
|
||||
|
||||
if (options.listAgents) {
|
||||
orchestrator.listAgents();
|
||||
return;
|
||||
}
|
||||
|
||||
// Execute brainstorming
|
||||
const results = await orchestrator.brainstorm(topic, options);
|
||||
const formatted = orchestrator.formatResults(results);
|
||||
|
||||
console.log(formatted);
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
multiAIBrainstorm,
|
||||
BrainstormOrchestrator,
|
||||
AVAILABLE_AGENTS
|
||||
};
|
||||
29
multi-ai-brainstorm/brainstorm.js
Executable file
29
multi-ai-brainstorm/brainstorm.js
Executable file
@@ -0,0 +1,29 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Simple OAuth + Brainstorm launcher
|
||||
* Usage: ./brainstorm.js "your topic here"
|
||||
*/
|
||||
|
||||
const { oauthThenBrainstorm } = require('./oauth-then-brainstorm.js');
|
||||
|
||||
const topic = process.argv[2];
|
||||
|
||||
if (!topic) {
|
||||
console.log('\n🧠 Multi-AI Brainstorm with Qwen OAuth\n');
|
||||
console.log('Usage: node brainstorm.js "your topic here"\n');
|
||||
console.log('Example: node brainstorm.js "I want to build a collaborative code editor"\n');
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
console.log('\n🧠 Multi-AI Brainstorm Session');
|
||||
console.log('Topic: ' + topic);
|
||||
console.log('Agents: All 8 specialized AI agents\n');
|
||||
|
||||
oauthThenBrainstorm(topic)
|
||||
.then(() => {
|
||||
console.log('\n✨ Brainstorming session complete!\n');
|
||||
})
|
||||
.catch((err) => {
|
||||
console.error('\n❌ Session failed:', err.message, '\n');
|
||||
process.exit(1);
|
||||
});
|
||||
31
multi-ai-brainstorm/index.js
Normal file
31
multi-ai-brainstorm/index.js
Normal file
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Multi-AI Brainstorm Skill
|
||||
* Main entry point for collaborative AI brainstorming
|
||||
*/
|
||||
|
||||
const { multiAIBrainstorm, BrainstormOrchestrator, AVAILABLE_AGENTS } = require('./brainstorm-orchestrator');
|
||||
|
||||
/**
|
||||
* Main skill function
|
||||
* @param {string} topic - The topic to brainstorm
|
||||
* @param {Object} options - Configuration options
|
||||
* @param {string[]} options.agents - Array of agent names to use (default: all)
|
||||
* @param {number} options.concurrency - Number of agents to run in parallel (default: 3)
|
||||
* @param {boolean} options.listAgents - If true, list available agents and exit
|
||||
*/
|
||||
async function run(topic, options = {}) {
|
||||
try {
|
||||
const results = await multiAIBrainstorm(topic, options);
|
||||
return results;
|
||||
} catch (error) {
|
||||
console.error('\n❌ Brainstorming failed:', error.message);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
run,
|
||||
multiAIBrainstorm,
|
||||
BrainstormOrchestrator,
|
||||
AVAILABLE_AGENTS
|
||||
};
|
||||
57
multi-ai-brainstorm/oauth-then-brainstorm.js
Normal file
57
multi-ai-brainstorm/oauth-then-brainstorm.js
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* OAuth-then-Brainstorm Flow
|
||||
* 1. Shows OAuth URL
|
||||
* 2. Waits for user authorization
|
||||
* 3. Automatically proceeds with brainstorming
|
||||
*/
|
||||
|
||||
const qwenClient = require('./qwen-client.js');
|
||||
const { multiAIBrainstorm } = require('./brainstorm-orchestrator.js');
|
||||
|
||||
async function oauthThenBrainstorm(topic, options = {}) {
|
||||
try {
|
||||
// Step 1: Initialize client
|
||||
const isInitialized = await qwenClient.initialize();
|
||||
|
||||
if (isInitialized && qwenClient.isAuthenticated()) {
|
||||
console.log('\n✓ Already authenticated with Qwen OAuth!');
|
||||
console.log('✓ Proceeding with brainstorming...\n');
|
||||
await multiAIBrainstorm(topic, options);
|
||||
return;
|
||||
}
|
||||
|
||||
// Step 2: Perform OAuth flow
|
||||
console.log('\n🔐 Qwen OAuth Authentication Required\n');
|
||||
console.log('='.repeat(70));
|
||||
|
||||
await qwenClient.performOAuthFlow();
|
||||
|
||||
// Step 3: Verify authentication worked
|
||||
if (!qwenClient.isAuthenticated()) {
|
||||
throw new Error('OAuth authentication failed');
|
||||
}
|
||||
|
||||
console.log('\n✓ Authentication successful!');
|
||||
console.log('✓ Proceeding with brainstorming...\n');
|
||||
|
||||
// Step 4: Run brainstorming
|
||||
await multiAIBrainstorm(topic, options);
|
||||
|
||||
} catch (error) {
|
||||
console.error('\n❌ Error:', error.message);
|
||||
console.error('\nTroubleshooting:');
|
||||
console.error('- Make sure you clicked "Authorize" in the browser');
|
||||
console.error('- Check your internet connection');
|
||||
console.error('- The OAuth URL may have expired (try again)\n');
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
// Export for use
|
||||
module.exports = { oauthThenBrainstorm };
|
||||
|
||||
// If run directly
|
||||
if (require.main === module) {
|
||||
const topic = process.argv[2] || 'test topic';
|
||||
oauthThenBrainstorm(topic).catch(console.error);
|
||||
}
|
||||
19
multi-ai-brainstorm/package.json
Normal file
19
multi-ai-brainstorm/package.json
Normal file
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"name": "multi-ai-brainstorm",
|
||||
"version": "1.0.0",
|
||||
"description": "Multi-AI brainstorming using Qwen coder-model. Collaborate with multiple specialized AI agents for expert-level ideation.",
|
||||
"main": "brainstorm-orchestrator.js",
|
||||
"dependencies": {
|
||||
"node-fetch": "^2.7.0"
|
||||
},
|
||||
"keywords": [
|
||||
"ai",
|
||||
"brainstorm",
|
||||
"multi-agent",
|
||||
"qwen",
|
||||
"ideation",
|
||||
"collaboration"
|
||||
],
|
||||
"author": "Roman | RyzenAdvanced",
|
||||
"license": "ISC"
|
||||
}
|
||||
455
multi-ai-brainstorm/qwen-client.js
Normal file
455
multi-ai-brainstorm/qwen-client.js
Normal file
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* Qwen API Client for Multi-AI Brainstorm
|
||||
* Integrates with PromptArch's Qwen OAuth service
|
||||
*/
|
||||
|
||||
const DEFAULT_ENDPOINT = "https://dashscope-intl.aliyuncs.com/compatible-mode/v1";
|
||||
const PROMPTARCH_PROXY = "https://www.rommark.dev/tools/promptarch/api/qwen/chat";
|
||||
const CREDENTIALS_PATH = `${process.env.HOME}/.claude/qwen-credentials.json`;
|
||||
|
||||
// Qwen OAuth Configuration (from Qwen Code source)
|
||||
const QWEN_OAUTH_BASE_URL = 'https://chat.qwen.ai';
|
||||
const QWEN_OAUTH_DEVICE_CODE_ENDPOINT = `${QWEN_OAUTH_BASE_URL}/api/v1/oauth2/device/code`;
|
||||
const QWEN_OAUTH_TOKEN_ENDPOINT = `${QWEN_OAUTH_BASE_URL}/api/v1/oauth2/token`;
|
||||
const QWEN_OAUTH_CLIENT_ID = 'f0304373b74a44d2b584a3fb70ca9e56';
|
||||
const QWEN_OAUTH_SCOPE = 'openid profile email model.completion';
|
||||
const QWEN_OAUTH_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code';
|
||||
|
||||
/**
|
||||
* Qwen API Client Class
|
||||
*/
|
||||
class QwenClient {
|
||||
constructor() {
|
||||
this.apiKey = null;
|
||||
this.accessToken = null;
|
||||
this.refreshToken = null;
|
||||
this.tokenExpiresAt = null;
|
||||
this.endpoint = DEFAULT_ENDPOINT;
|
||||
this.model = "coder-model";
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize client with credentials
|
||||
*/
|
||||
async initialize() {
|
||||
try {
|
||||
const fs = require('fs');
|
||||
if (fs.existsSync(CREDENTIALS_PATH)) {
|
||||
const credentials = JSON.parse(fs.readFileSync(CREDENTIALS_PATH, 'utf8'));
|
||||
|
||||
// Handle both API key and OAuth token credentials
|
||||
if (credentials.accessToken) {
|
||||
this.accessToken = credentials.accessToken;
|
||||
this.refreshToken = credentials.refreshToken;
|
||||
this.tokenExpiresAt = credentials.tokenExpiresAt;
|
||||
this.endpoint = credentials.endpoint || DEFAULT_ENDPOINT;
|
||||
|
||||
// Check if token needs refresh
|
||||
if (this.isTokenExpired()) {
|
||||
await this.refreshAccessToken();
|
||||
}
|
||||
return true;
|
||||
} else if (credentials.apiKey) {
|
||||
this.apiKey = credentials.apiKey;
|
||||
this.endpoint = credentials.endpoint || DEFAULT_ENDPOINT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (error) {
|
||||
// No credentials stored yet
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if access token is expired
|
||||
*/
|
||||
isTokenExpired() {
|
||||
if (!this.tokenExpiresAt) return false;
|
||||
// Add 5 minute buffer before expiration
|
||||
return Date.now() >= (this.tokenExpiresAt - 5 * 60 * 1000);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt user for authentication method
|
||||
*/
|
||||
async promptForCredentials() {
|
||||
const readline = require('readline');
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
rl.question(
|
||||
'\n🔐 Choose authentication method:\n' +
|
||||
' 1. OAuth (Recommended) - Free 2000 requests/day with qwen.ai account\n' +
|
||||
' 2. API Key - Get it at https://help.aliyun.com/zh/dashscope/\n\n' +
|
||||
'Enter choice (1 or 2): ',
|
||||
async (choice) => {
|
||||
rl.close();
|
||||
|
||||
if (choice === '1') {
|
||||
try {
|
||||
await this.performOAuthFlow();
|
||||
resolve(true);
|
||||
} catch (error) {
|
||||
reject(error);
|
||||
}
|
||||
} else if (choice === '2') {
|
||||
await this.promptForAPIKey();
|
||||
resolve(true);
|
||||
} else {
|
||||
reject(new Error('Invalid choice. Please enter 1 or 2.'));
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Prompt user for API key only
|
||||
*/
|
||||
async promptForAPIKey() {
|
||||
const readline = require('readline');
|
||||
const rl = readline.createInterface({
|
||||
input: process.stdin,
|
||||
output: process.stdout
|
||||
});
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
rl.question('Enter your Qwen API key (get it at https://help.aliyun.com/zh/dashscope/): ', (key) => {
|
||||
if (!key || key.trim().length === 0) {
|
||||
rl.close();
|
||||
reject(new Error('API key is required'));
|
||||
return;
|
||||
}
|
||||
|
||||
this.apiKey = key.trim();
|
||||
this.saveCredentials();
|
||||
rl.close();
|
||||
resolve(true);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Save credentials to file
|
||||
*/
|
||||
saveCredentials() {
|
||||
try {
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const dir = path.dirname(CREDENTIALS_PATH);
|
||||
|
||||
if (!fs.existsSync(dir)) {
|
||||
fs.mkdirSync(dir, { recursive: true });
|
||||
}
|
||||
|
||||
const credentials = {
|
||||
endpoint: this.endpoint
|
||||
};
|
||||
|
||||
// Save OAuth tokens
|
||||
if (this.accessToken) {
|
||||
credentials.accessToken = this.accessToken;
|
||||
credentials.refreshToken = this.refreshToken;
|
||||
credentials.tokenExpiresAt = this.tokenExpiresAt;
|
||||
}
|
||||
// Save API key
|
||||
else if (this.apiKey) {
|
||||
credentials.apiKey = this.apiKey;
|
||||
}
|
||||
|
||||
fs.writeFileSync(
|
||||
CREDENTIALS_PATH,
|
||||
JSON.stringify(credentials, null, 2)
|
||||
);
|
||||
console.log(`✓ Credentials saved to ${CREDENTIALS_PATH}`);
|
||||
} catch (error) {
|
||||
console.warn('Could not save credentials:', error.message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate PKCE code verifier and challenge pair
|
||||
*/
|
||||
generatePKCEPair() {
|
||||
const crypto = require('crypto');
|
||||
const codeVerifier = crypto.randomBytes(32).toString('base64url');
|
||||
const codeChallenge = crypto.createHash('sha256')
|
||||
.update(codeVerifier)
|
||||
.digest('base64url');
|
||||
return { code_verifier: codeVerifier, code_challenge: codeChallenge };
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert object to URL-encoded form data
|
||||
*/
|
||||
objectToUrlEncoded(data) {
|
||||
return Object.keys(data)
|
||||
.map((key) => `${encodeURIComponent(key)}=${encodeURIComponent(data[key])}`)
|
||||
.join('&');
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform OAuth 2.0 Device Code Flow (from Qwen Code implementation)
|
||||
*/
|
||||
async performOAuthFlow() {
|
||||
const { exec } = require('child_process');
|
||||
|
||||
console.log('\n🔐 Starting Qwen OAuth Device Code Flow...\n');
|
||||
|
||||
// Generate PKCE parameters
|
||||
const { code_verifier, code_challenge } = this.generatePKCEPair();
|
||||
|
||||
// Step 1: Request device authorization
|
||||
console.log('Requesting device authorization...');
|
||||
const deviceAuthResponse = await fetch(QWEN_OAUTH_DEVICE_CODE_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: this.objectToUrlEncoded({
|
||||
client_id: QWEN_OAUTH_CLIENT_ID,
|
||||
scope: QWEN_OAUTH_SCOPE,
|
||||
code_challenge: code_challenge,
|
||||
code_challenge_method: 'S256',
|
||||
}),
|
||||
});
|
||||
|
||||
if (!deviceAuthResponse.ok) {
|
||||
const error = await deviceAuthResponse.text();
|
||||
throw new Error(`Device authorization failed: ${deviceAuthResponse.status} - ${error}`);
|
||||
}
|
||||
|
||||
const deviceAuth = await deviceAuthResponse.json();
|
||||
|
||||
if (!deviceAuth.device_code) {
|
||||
throw new Error('Invalid device authorization response');
|
||||
}
|
||||
|
||||
// Step 2: Display authorization instructions
|
||||
console.log('\n=== Qwen OAuth Device Authorization ===\n');
|
||||
console.log('1. Visit this URL in your browser:\n');
|
||||
console.log(` ${deviceAuth.verification_uri_complete}\n`);
|
||||
console.log('2. Sign in to your qwen.ai account and authorize\n');
|
||||
console.log('Waiting for authorization to complete...\n');
|
||||
|
||||
// Try to open browser automatically
|
||||
try {
|
||||
const openCommand = process.platform === 'darwin' ? 'open' :
|
||||
process.platform === 'win32' ? 'start' : 'xdg-open';
|
||||
exec(`${openCommand} "${deviceAuth.verification_uri_complete}"`, (err) => {
|
||||
if (err) {
|
||||
console.debug('Could not open browser automatically');
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
console.debug('Failed to open browser:', err.message);
|
||||
}
|
||||
|
||||
// Step 3: Poll for token
|
||||
let pollInterval = 2000; // Start with 2 seconds
|
||||
const maxAttempts = Math.ceil(deviceAuth.expires_in / (pollInterval / 1000));
|
||||
let attempt = 0;
|
||||
|
||||
while (attempt < maxAttempts) {
|
||||
attempt++;
|
||||
|
||||
try {
|
||||
console.debug(`Polling for token (attempt ${attempt}/${maxAttempts})...`);
|
||||
|
||||
const tokenResponse = await fetch(QWEN_OAUTH_TOKEN_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
'Accept': 'application/json',
|
||||
},
|
||||
body: this.objectToUrlEncoded({
|
||||
grant_type: QWEN_OAUTH_GRANT_TYPE,
|
||||
client_id: QWEN_OAUTH_CLIENT_ID,
|
||||
device_code: deviceAuth.device_code,
|
||||
code_verifier: code_verifier,
|
||||
}),
|
||||
});
|
||||
|
||||
// Check for pending authorization (standard OAuth RFC 8628 response)
|
||||
if (tokenResponse.status === 400) {
|
||||
const errorData = await tokenResponse.json();
|
||||
|
||||
if (errorData.error === 'authorization_pending') {
|
||||
// User hasn't authorized yet, continue polling
|
||||
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
||||
continue;
|
||||
}
|
||||
|
||||
if (errorData.error === 'slow_down') {
|
||||
// Polling too frequently, increase interval
|
||||
pollInterval = Math.min(pollInterval * 1.5, 10000);
|
||||
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Other 400 errors (authorization_declined, expired_token, etc.)
|
||||
throw new Error(`Authorization failed: ${errorData.error} - ${errorData.error_description || 'No description'}`);
|
||||
}
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
const error = await tokenResponse.text();
|
||||
throw new Error(`Token request failed: ${tokenResponse.status} - ${error}`);
|
||||
}
|
||||
|
||||
// Success! We have the token
|
||||
const tokenData = await tokenResponse.json();
|
||||
|
||||
if (!tokenData.access_token) {
|
||||
throw new Error('Token response missing access_token');
|
||||
}
|
||||
|
||||
// Save credentials
|
||||
this.accessToken = tokenData.access_token;
|
||||
this.refreshToken = tokenData.refresh_token;
|
||||
this.tokenExpiresAt = tokenData.expires_in ?
|
||||
Date.now() + (tokenData.expires_in * 1000) : null;
|
||||
|
||||
this.saveCredentials();
|
||||
|
||||
console.log('\n✓ OAuth authentication successful!');
|
||||
console.log('✓ Access token obtained and saved.\n');
|
||||
|
||||
return;
|
||||
|
||||
} catch (error) {
|
||||
// Check if this is a fatal error (not pending/slow_down)
|
||||
if (error.message.includes('Authorization failed') ||
|
||||
error.message.includes('Token request failed')) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// For other errors, wait and retry
|
||||
await new Promise(resolve => setTimeout(resolve, pollInterval));
|
||||
}
|
||||
}
|
||||
|
||||
throw new Error('OAuth authentication timeout');
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh access token using refresh token
|
||||
*/
|
||||
async refreshAccessToken() {
|
||||
if (!this.refreshToken) {
|
||||
throw new Error('No refresh token available. Please re-authenticate.');
|
||||
}
|
||||
|
||||
console.log('🔄 Refreshing access token...');
|
||||
|
||||
const tokenResponse = await fetch(QWEN_OAUTH_TOKEN_ENDPOINT, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/x-www-form-urlencoded',
|
||||
},
|
||||
body: this.objectToUrlEncoded({
|
||||
grant_type: 'refresh_token',
|
||||
refresh_token: this.refreshToken,
|
||||
client_id: QWEN_OAUTH_CLIENT_ID,
|
||||
}),
|
||||
});
|
||||
|
||||
if (!tokenResponse.ok) {
|
||||
const error = await tokenResponse.text();
|
||||
throw new Error(`Token refresh failed: ${tokenResponse.status} - ${error}`);
|
||||
}
|
||||
|
||||
const tokens = await tokenResponse.json();
|
||||
|
||||
this.accessToken = tokens.access_token;
|
||||
if (tokens.refresh_token) {
|
||||
this.refreshToken = tokens.refresh_token;
|
||||
}
|
||||
this.tokenExpiresAt = tokens.expires_in ?
|
||||
Date.now() + (tokens.expires_in * 1000) : null;
|
||||
|
||||
this.saveCredentials();
|
||||
console.log('✓ Token refreshed successfully');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the authentication key (prefer OAuth access token, fallback to API key)
|
||||
*/
|
||||
getAuthKey() {
|
||||
return this.accessToken || this.apiKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Make a chat completion request
|
||||
*/
|
||||
async chatCompletion(messages, options = {}) {
|
||||
const authKey = this.getAuthKey();
|
||||
|
||||
if (!authKey) {
|
||||
throw new Error('Qwen API key not configured. Run /multi-ai-brainstorm first to set up.');
|
||||
}
|
||||
|
||||
// Check if OAuth token needs refresh
|
||||
if (this.accessToken && this.isTokenExpired()) {
|
||||
await this.refreshAccessToken();
|
||||
}
|
||||
|
||||
const {
|
||||
model = this.model,
|
||||
stream = false,
|
||||
temperature = 0.7,
|
||||
maxTokens = 2000
|
||||
} = options;
|
||||
|
||||
const payload = {
|
||||
model,
|
||||
messages,
|
||||
stream,
|
||||
temperature,
|
||||
max_tokens: maxTokens
|
||||
};
|
||||
|
||||
try {
|
||||
const response = await fetch(PROMPTARCH_PROXY, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'Authorization': `Bearer ${authKey}`
|
||||
},
|
||||
body: JSON.stringify({
|
||||
endpoint: this.endpoint,
|
||||
...payload
|
||||
})
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const error = await response.text();
|
||||
throw new Error(`Qwen API error (${response.status}): ${error}`);
|
||||
}
|
||||
|
||||
const data = await response.json();
|
||||
return data.choices?.[0]?.message?.content || '';
|
||||
} catch (error) {
|
||||
if (error.message.includes('fetch')) {
|
||||
throw new Error('Network error. Please check your internet connection.');
|
||||
}
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if client is authenticated
|
||||
*/
|
||||
isAuthenticated() {
|
||||
return !!(this.accessToken || this.apiKey);
|
||||
}
|
||||
}
|
||||
|
||||
// Singleton instance
|
||||
const client = new QwenClient();
|
||||
|
||||
module.exports = client;
|
||||
Reference in New Issue
Block a user