@artyfacts/claude 1.0.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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/adapter.ts","../src/artyfacts-client.ts","../src/claude-runner.ts","../src/auth.ts"],"sourcesContent":["/**\n * Claude Adapter\n * \n * Main orchestration class that:\n * 1. Polls Artyfacts for claimable tasks\n * 2. Spawns Claude Code to execute them\n * 3. Reports results back to Artyfacts\n */\n\nimport { EventEmitter } from 'events';\nimport { ArtyfactsClient, Task } from './artyfacts-client.js';\nimport { ClaudeRunner, TaskResult } from './claude-runner.js';\n\nexport interface AdapterConfig {\n /** Artyfacts API key */\n apiKey: string;\n /** Artyfacts base URL */\n baseUrl?: string;\n /** Agent ID for attribution */\n agentId?: string;\n /** Poll interval in ms (default: 30s) */\n pollIntervalMs?: number;\n /** Max concurrent tasks (default: 1) */\n maxConcurrent?: number;\n /** Claude model to use (default: 'sonnet') */\n model?: string;\n /** Working directory for Claude */\n cwd?: string;\n}\n\nexport interface AdapterEvents {\n 'started': () => void;\n 'stopped': () => void;\n 'poll': (tasks: Task[]) => void;\n 'task:claimed': (task: Task) => void;\n 'task:running': (task: Task) => void;\n 'task:completed': (task: Task, result: TaskResult) => void;\n 'task:failed': (task: Task, error: string) => void;\n 'error': (error: Error) => void;\n}\n\nexport class ClaudeAdapter extends EventEmitter {\n private config: Required<AdapterConfig>;\n private client: ArtyfactsClient;\n private runner: ClaudeRunner;\n private running = false;\n private pollTimer: NodeJS.Timeout | null = null;\n private activeTasks = new Set<string>();\n\n constructor(config: AdapterConfig) {\n super();\n \n this.config = {\n apiKey: config.apiKey,\n baseUrl: config.baseUrl ?? 'https://artyfacts.dev/api/v1',\n agentId: config.agentId ?? 'claude-agent',\n pollIntervalMs: config.pollIntervalMs ?? 30_000,\n maxConcurrent: config.maxConcurrent ?? 1,\n model: config.model ?? 'sonnet',\n cwd: config.cwd ?? process.cwd(),\n };\n\n this.client = new ArtyfactsClient({\n apiKey: this.config.apiKey,\n baseUrl: this.config.baseUrl,\n agentId: this.config.agentId,\n });\n\n this.runner = new ClaudeRunner({\n model: this.config.model,\n cwd: this.config.cwd,\n });\n\n // Forward runner events\n this.runner.on('task:output', (data) => this.emit('task:output', data));\n }\n\n /**\n * Check if Claude Code is ready\n */\n async checkReady(): Promise<{ ready: boolean; error?: string }> {\n const check = await this.runner.checkInstalled();\n \n if (!check.installed) {\n return { \n ready: false, \n error: 'Claude Code is not installed. Run: npm install -g @anthropic-ai/claude-code' \n };\n }\n \n if (!check.authenticated) {\n return { \n ready: false, \n error: 'Claude Code is not authenticated. Run: claude login' \n };\n }\n\n return { ready: true };\n }\n\n /**\n * Start the adapter\n */\n async start(): Promise<void> {\n if (this.running) return;\n\n // Check Claude Code is ready\n const { ready, error } = await this.checkReady();\n if (!ready) {\n throw new Error(error);\n }\n\n this.running = true;\n this.emit('started');\n\n // Initial poll\n await this.poll();\n\n // Schedule polling\n this.pollTimer = setInterval(() => {\n this.poll().catch((err) => this.emit('error', err));\n }, this.config.pollIntervalMs);\n }\n\n /**\n * Stop the adapter\n */\n async stop(): Promise<void> {\n if (!this.running) return;\n\n this.running = false;\n \n if (this.pollTimer) {\n clearInterval(this.pollTimer);\n this.pollTimer = null;\n }\n\n // Cancel running tasks\n this.runner.cancelAll();\n \n this.emit('stopped');\n }\n\n /**\n * Poll for and execute tasks\n */\n private async poll(): Promise<void> {\n try {\n // Check capacity\n const available = this.config.maxConcurrent - this.activeTasks.size;\n if (available <= 0) return;\n\n // Get claimable tasks\n const tasks = await this.client.getTaskQueue({ limit: available });\n this.emit('poll', tasks);\n\n // Process each task\n for (const task of tasks) {\n if (this.activeTasks.has(task.id)) continue;\n if (this.activeTasks.size >= this.config.maxConcurrent) break;\n\n // Claim and execute\n await this.executeTask(task);\n }\n } catch (error) {\n this.emit('error', error instanceof Error ? error : new Error(String(error)));\n }\n }\n\n /**\n * Execute a single task\n */\n private async executeTask(task: Task): Promise<void> {\n try {\n // Claim the task\n const claim = await this.client.claimTask(task.id);\n if (!claim.success) return;\n\n this.activeTasks.add(task.id);\n this.emit('task:claimed', task);\n\n // Build prompt from task\n const prompt = this.buildPrompt(task);\n \n this.emit('task:running', task);\n\n // Run with Claude Code\n const result = await this.runner.runTask(task.id, prompt, {\n cwd: this.config.cwd,\n });\n\n this.activeTasks.delete(task.id);\n\n if (result.success) {\n // Complete the task\n await this.client.completeTask(task.id, {\n summary: this.extractSummary(result.output),\n });\n this.emit('task:completed', task, result);\n } else {\n // Report failure\n await this.client.blockTask(task.id, result.error ?? 'Task failed');\n this.emit('task:failed', task, result.error ?? 'Unknown error');\n }\n } catch (error) {\n this.activeTasks.delete(task.id);\n const message = error instanceof Error ? error.message : String(error);\n this.emit('task:failed', task, message);\n }\n }\n\n /**\n * Build a prompt for Claude from the task\n */\n private buildPrompt(task: Task): string {\n return `You are working on a task from Artyfacts.\n\n## Task: ${task.heading}\n\n## Context\n- Artifact: ${task.artifactTitle}\n- URL: ${task.artifactUrl}\n- Priority: ${task.priority === 1 ? 'High' : task.priority === 2 ? 'Medium' : 'Low'}\n\n## Details\n${task.content}\n\n## Instructions\nComplete this task to the best of your ability. When finished, provide a brief summary of what you accomplished.\n\nIf you cannot complete the task, explain why clearly.`;\n }\n\n /**\n * Extract a summary from Claude's output\n */\n private extractSummary(output: string): string {\n // Take last 500 chars as summary, or full output if shorter\n const maxLen = 500;\n if (output.length <= maxLen) return output;\n return '...' + output.slice(-maxLen);\n }\n\n /**\n * Check if running\n */\n isRunning(): boolean {\n return this.running;\n }\n\n /**\n * Get stats\n */\n getStats(): { running: boolean; activeTasks: number; maxConcurrent: number } {\n return {\n running: this.running,\n activeTasks: this.activeTasks.size,\n maxConcurrent: this.config.maxConcurrent,\n };\n }\n}\n\nexport default ClaudeAdapter;\n","/**\n * Artyfacts API Client (Simplified)\n * \n * Handles communication with the Artyfacts API for task management.\n */\n\nexport interface ArtyfactsConfig {\n apiKey: string;\n baseUrl?: string;\n agentId?: string;\n}\n\nexport interface Task {\n id: string;\n sectionId: string;\n heading: string;\n content: string;\n artifactId: string;\n artifactTitle: string;\n artifactUrl: string;\n priority: 1 | 2 | 3;\n dependsOn: string[];\n createdAt: string;\n}\n\nexport interface ClaimResult {\n success: boolean;\n task: Task & { claimedAt: string; claimedBy: string };\n}\n\nexport interface CompleteResult {\n success: boolean;\n unblockedTasks: string[];\n}\n\nexport class ArtyfactsClient {\n private config: Required<ArtyfactsConfig>;\n\n constructor(config: ArtyfactsConfig) {\n this.config = {\n apiKey: config.apiKey,\n baseUrl: config.baseUrl ?? 'https://artyfacts.dev/api/v1',\n agentId: config.agentId ?? 'claude-agent',\n };\n }\n\n private async fetch<T>(path: string, options: RequestInit = {}): Promise<T> {\n const url = `${this.config.baseUrl}${path}`;\n const response = await fetch(url, {\n ...options,\n headers: {\n 'Content-Type': 'application/json',\n 'Authorization': `Bearer ${this.config.apiKey}`,\n ...options.headers,\n },\n });\n\n if (!response.ok) {\n const error = await response.text();\n throw new Error(`API error (${response.status}): ${error}`);\n }\n\n return response.json();\n }\n\n /**\n * Get claimable tasks from the queue\n */\n async getTaskQueue(options?: { limit?: number }): Promise<Task[]> {\n const params = new URLSearchParams();\n if (options?.limit) params.set('limit', options.limit.toString());\n\n const result = await this.fetch<{ tasks: Task[] }>(`/tasks/queue?${params}`);\n return result.tasks;\n }\n\n /**\n * Claim a task\n */\n async claimTask(taskId: string): Promise<ClaimResult> {\n return this.fetch<ClaimResult>(`/tasks/${taskId}/claim`, {\n method: 'POST',\n body: JSON.stringify({ agent_id: this.config.agentId }),\n });\n }\n\n /**\n * Complete a task\n */\n async completeTask(taskId: string, options?: {\n outputUrl?: string;\n summary?: string;\n }): Promise<CompleteResult> {\n return this.fetch<CompleteResult>(`/tasks/${taskId}/complete`, {\n method: 'POST',\n body: JSON.stringify({\n agent_id: this.config.agentId,\n output_url: options?.outputUrl,\n summary: options?.summary,\n }),\n });\n }\n\n /**\n * Report task as blocked\n */\n async blockTask(taskId: string, reason: string): Promise<void> {\n await this.fetch(`/tasks/${taskId}/block`, {\n method: 'POST',\n body: JSON.stringify({\n agent_id: this.config.agentId,\n reason,\n }),\n });\n }\n\n /**\n * Get current user/org info\n */\n async getMe(): Promise<{ id: string; name: string; orgId: string }> {\n return this.fetch('/me');\n }\n}\n\nexport default ArtyfactsClient;\n","/**\n * Claude Code Runner\n * \n * Spawns and manages Claude Code CLI processes for task execution.\n */\n\nimport { spawn, ChildProcess } from 'child_process';\nimport { EventEmitter } from 'events';\n\nexport interface ClaudeRunnerConfig {\n /** Path to claude CLI (default: 'claude') */\n claudePath?: string;\n /** Model to use (default: 'sonnet') */\n model?: string;\n /** Working directory for Claude */\n cwd?: string;\n /** Timeout in ms (default: 5 minutes) */\n timeoutMs?: number;\n}\n\nexport interface TaskResult {\n success: boolean;\n output: string;\n error?: string;\n exitCode: number | null;\n durationMs: number;\n}\n\nexport interface RunningTask {\n taskId: string;\n process: ChildProcess;\n startedAt: Date;\n promise: Promise<TaskResult>;\n}\n\nexport class ClaudeRunner extends EventEmitter {\n private config: Required<ClaudeRunnerConfig>;\n private runningTasks: Map<string, RunningTask> = new Map();\n\n constructor(config: ClaudeRunnerConfig = {}) {\n super();\n this.config = {\n claudePath: config.claudePath ?? 'claude',\n model: config.model ?? 'sonnet',\n cwd: config.cwd ?? process.cwd(),\n timeoutMs: config.timeoutMs ?? 5 * 60 * 1000, // 5 minutes\n };\n }\n\n /**\n * Check if Claude Code is installed and authenticated\n */\n async checkInstalled(): Promise<{ installed: boolean; authenticated: boolean; version?: string; error?: string }> {\n try {\n const result = await this.runCommand(['--version']);\n const version = result.output.trim();\n \n // Try a simple prompt to check auth\n const authCheck = await this.runCommand(['-p', 'Say \"ok\"', '--print', '--max-turns', '1']);\n const authenticated = authCheck.success && !authCheck.output.includes('not authenticated');\n \n return { installed: true, authenticated, version };\n } catch (error) {\n return { \n installed: false, \n authenticated: false, \n error: error instanceof Error ? error.message : 'Unknown error' \n };\n }\n }\n\n /**\n * Run a task with Claude Code\n */\n async runTask(taskId: string, prompt: string, options?: { \n cwd?: string;\n model?: string;\n timeoutMs?: number;\n }): Promise<TaskResult> {\n const startedAt = new Date();\n const model = options?.model ?? this.config.model;\n const cwd = options?.cwd ?? this.config.cwd;\n const timeoutMs = options?.timeoutMs ?? this.config.timeoutMs;\n\n // Build command args\n const args = [\n '-p', prompt,\n '--print',\n '--output-format', 'text',\n '--model', model,\n ];\n\n this.emit('task:start', { taskId, prompt, model });\n\n const promise = new Promise<TaskResult>((resolve) => {\n let output = '';\n let error = '';\n\n const proc = spawn(this.config.claudePath, args, {\n cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n env: { ...process.env },\n });\n\n const timeout = setTimeout(() => {\n proc.kill('SIGTERM');\n resolve({\n success: false,\n output,\n error: 'Task timed out',\n exitCode: null,\n durationMs: Date.now() - startedAt.getTime(),\n });\n }, timeoutMs);\n\n proc.stdout?.on('data', (data) => {\n output += data.toString();\n this.emit('task:output', { taskId, chunk: data.toString() });\n });\n\n proc.stderr?.on('data', (data) => {\n error += data.toString();\n });\n\n proc.on('close', (code) => {\n clearTimeout(timeout);\n this.runningTasks.delete(taskId);\n \n const result: TaskResult = {\n success: code === 0,\n output: output.trim(),\n error: error.trim() || undefined,\n exitCode: code,\n durationMs: Date.now() - startedAt.getTime(),\n };\n\n this.emit('task:complete', { taskId, result });\n resolve(result);\n });\n\n proc.on('error', (err) => {\n clearTimeout(timeout);\n this.runningTasks.delete(taskId);\n \n resolve({\n success: false,\n output: '',\n error: err.message,\n exitCode: null,\n durationMs: Date.now() - startedAt.getTime(),\n });\n });\n\n // Track running task\n this.runningTasks.set(taskId, {\n taskId,\n process: proc,\n startedAt,\n promise: promise as Promise<TaskResult>,\n });\n });\n\n return promise;\n }\n\n /**\n * Run a raw claude command\n */\n private runCommand(args: string[]): Promise<TaskResult> {\n return new Promise((resolve) => {\n const startedAt = Date.now();\n let output = '';\n let error = '';\n\n const proc = spawn(this.config.claudePath, args, {\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n proc.stdout?.on('data', (data) => {\n output += data.toString();\n });\n\n proc.stderr?.on('data', (data) => {\n error += data.toString();\n });\n\n proc.on('close', (code) => {\n resolve({\n success: code === 0,\n output: output.trim(),\n error: error.trim() || undefined,\n exitCode: code,\n durationMs: Date.now() - startedAt,\n });\n });\n\n proc.on('error', (err) => {\n resolve({\n success: false,\n output: '',\n error: err.message,\n exitCode: null,\n durationMs: Date.now() - startedAt,\n });\n });\n });\n }\n\n /**\n * Cancel a running task\n */\n cancelTask(taskId: string): boolean {\n const task = this.runningTasks.get(taskId);\n if (task) {\n task.process.kill('SIGTERM');\n this.runningTasks.delete(taskId);\n this.emit('task:cancelled', { taskId });\n return true;\n }\n return false;\n }\n\n /**\n * Get count of running tasks\n */\n getRunningCount(): number {\n return this.runningTasks.size;\n }\n\n /**\n * Cancel all running tasks\n */\n cancelAll(): void {\n for (const [taskId] of this.runningTasks) {\n this.cancelTask(taskId);\n }\n }\n}\n\nexport default ClaudeRunner;\n","/**\n * Device Authorization Flow\n * \n * Handles browser-based authentication for the CLI.\n * No API keys to copy — just run the CLI and click authorize.\n */\n\nimport { execSync } from 'child_process';\nimport * as fs from 'fs';\nimport * as path from 'path';\nimport * as os from 'os';\n\nexport interface DeviceCodeResponse {\n deviceCode: string;\n userCode: string;\n verificationUri: string;\n expiresIn: number;\n interval: number;\n}\n\nexport interface TokenResponse {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n user: {\n id: string;\n email: string;\n name?: string;\n orgId: string;\n };\n}\n\nexport interface StoredCredentials {\n accessToken: string;\n refreshToken?: string;\n expiresAt?: number;\n user: {\n id: string;\n email: string;\n name?: string;\n orgId: string;\n };\n savedAt: string;\n}\n\nexport class DeviceAuth {\n private baseUrl: string;\n private credentialsPath: string;\n\n constructor(options?: { baseUrl?: string }) {\n this.baseUrl = options?.baseUrl ?? 'https://artyfacts.dev';\n this.credentialsPath = path.join(os.homedir(), '.artyfacts', 'credentials.json');\n }\n\n /**\n * Check if we have stored credentials\n */\n hasCredentials(): boolean {\n return fs.existsSync(this.credentialsPath);\n }\n\n /**\n * Get stored credentials\n */\n getCredentials(): StoredCredentials | null {\n if (!this.hasCredentials()) return null;\n \n try {\n const data = fs.readFileSync(this.credentialsPath, 'utf-8');\n const creds = JSON.parse(data) as StoredCredentials;\n \n // Check if expired\n if (creds.expiresAt && Date.now() > creds.expiresAt) {\n // TODO: Implement refresh token flow\n return null;\n }\n \n return creds;\n } catch {\n return null;\n }\n }\n\n /**\n * Get access token (for API calls)\n */\n getAccessToken(): string | null {\n const creds = this.getCredentials();\n return creds?.accessToken ?? null;\n }\n\n /**\n * Clear stored credentials (logout)\n */\n logout(): void {\n if (fs.existsSync(this.credentialsPath)) {\n fs.unlinkSync(this.credentialsPath);\n }\n }\n\n /**\n * Start device authorization flow\n */\n async startDeviceFlow(): Promise<DeviceCodeResponse> {\n const response = await fetch(`${this.baseUrl}/api/v1/auth/device`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n });\n\n if (!response.ok) {\n throw new Error(`Failed to start device flow: ${response.status}`);\n }\n\n return response.json();\n }\n\n /**\n * Poll for token after user authorizes\n */\n async pollForToken(deviceCode: string, interval: number, expiresIn: number): Promise<TokenResponse> {\n const startTime = Date.now();\n const expiresAt = startTime + (expiresIn * 1000);\n\n while (Date.now() < expiresAt) {\n await this.sleep(interval * 1000);\n\n const response = await fetch(`${this.baseUrl}/api/v1/auth/device/token`, {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ deviceCode }),\n });\n\n if (response.ok) {\n return response.json();\n }\n\n const data = await response.json().catch(() => ({}));\n \n if (data.error === 'authorization_pending') {\n // User hasn't authorized yet, keep polling\n continue;\n }\n \n if (data.error === 'slow_down') {\n // Increase interval\n interval += 5;\n continue;\n }\n \n if (data.error === 'expired_token') {\n throw new Error('Authorization expired. Please try again.');\n }\n \n if (data.error === 'access_denied') {\n throw new Error('Authorization denied by user.');\n }\n\n throw new Error(data.error ?? 'Unknown error during authorization');\n }\n\n throw new Error('Authorization timed out. Please try again.');\n }\n\n /**\n * Save credentials to disk\n */\n saveCredentials(token: TokenResponse): void {\n const dir = path.dirname(this.credentialsPath);\n if (!fs.existsSync(dir)) {\n fs.mkdirSync(dir, { recursive: true });\n }\n\n const creds: StoredCredentials = {\n ...token,\n savedAt: new Date().toISOString(),\n };\n\n fs.writeFileSync(this.credentialsPath, JSON.stringify(creds, null, 2), {\n mode: 0o600, // Only user can read/write\n });\n }\n\n /**\n * Open URL in browser\n */\n openBrowser(url: string): void {\n const platform = process.platform;\n \n try {\n if (platform === 'darwin') {\n execSync(`open \"${url}\"`);\n } else if (platform === 'win32') {\n execSync(`start \"\" \"${url}\"`);\n } else {\n // Linux\n execSync(`xdg-open \"${url}\"`);\n }\n } catch {\n // If browser open fails, user will need to manually open\n console.log(`Please open this URL in your browser: ${url}`);\n }\n }\n\n /**\n * Full login flow\n */\n async login(options?: { \n onDeviceCode?: (response: DeviceCodeResponse) => void;\n onWaiting?: () => void;\n }): Promise<TokenResponse> {\n // Start device flow\n const deviceCode = await this.startDeviceFlow();\n \n // Notify caller\n options?.onDeviceCode?.(deviceCode);\n\n // Open browser\n this.openBrowser(deviceCode.verificationUri);\n\n // Notify waiting\n options?.onWaiting?.();\n\n // Poll for token\n const token = await this.pollForToken(\n deviceCode.deviceCode,\n deviceCode.interval,\n deviceCode.expiresIn\n );\n\n // Save credentials\n this.saveCredentials(token);\n\n return token;\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise(resolve => setTimeout(resolve, ms));\n }\n}\n\nexport default DeviceAuth;\n"],"mappings":"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","names":["EventEmitter","path","EventEmitter"]}
package/package.json ADDED
@@ -0,0 +1,47 @@
1
+ {
2
+ "name": "@artyfacts/claude",
3
+ "version": "1.0.0",
4
+ "description": "Claude Code adapter for Artyfacts - run AI agents locally with Claude Code",
5
+ "main": "dist/index.js",
6
+ "module": "dist/index.mjs",
7
+ "types": "dist/index.d.ts",
8
+ "bin": {
9
+ "artyfacts-claude": "bin/cli.js"
10
+ },
11
+ "exports": {
12
+ ".": {
13
+ "types": "./dist/index.d.ts",
14
+ "import": "./dist/index.mjs",
15
+ "require": "./dist/index.js"
16
+ }
17
+ },
18
+ "files": ["dist", "bin"],
19
+ "scripts": {
20
+ "build": "tsup",
21
+ "dev": "tsup --watch",
22
+ "test": "vitest",
23
+ "test:run": "vitest run",
24
+ "start": "node dist/index.js",
25
+ "prepublishOnly": "npm run build"
26
+ },
27
+ "keywords": ["artyfacts", "claude", "claude-code", "ai-agents", "orchestration"],
28
+ "author": "Artygroup",
29
+ "license": "MIT",
30
+ "dependencies": {
31
+ "chalk": "^5.3.0",
32
+ "commander": "^12.0.0",
33
+ "zod": "^3.22.0"
34
+ },
35
+ "devDependencies": {
36
+ "@types/node": "^20.0.0",
37
+ "tsup": "^8.0.0",
38
+ "typescript": "^5.0.0",
39
+ "vitest": "^1.0.0"
40
+ },
41
+ "engines": {
42
+ "node": ">=18"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public"
46
+ }
47
+ }