@datatamer.ai/agentdev 1.0.6 → 1.0.7
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/dist/agentdev.js +10 -10
- package/package.json +7 -6
- package/skills/agentdev-linkedin.md +425 -0
- package/skills/agentdev-twitter.md +430 -0
- package/skills/api-integration-guide.md +1382 -0
- package/skills/auto-ticket-workflow.md +118 -33
|
@@ -0,0 +1,1382 @@
|
|
|
1
|
+
# API Integration Guide — Step-by-Step Playbook
|
|
2
|
+
|
|
3
|
+
A comprehensive guide for integrating new APIs into the agentdev platform, based on the LinkedIn integration process.
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
This guide provides a proven, repeatable process for integrating third-party APIs into agentdev. Follow these steps to add support for any OAuth-based API (Twitter, GitHub, Slack, etc.) or API-key-based services.
|
|
8
|
+
|
|
9
|
+
**Time Estimate:** 20-40 hours depending on API complexity
|
|
10
|
+
**Difficulty:** Medium to Advanced
|
|
11
|
+
**Prerequisites:** Node.js, ES modules, OAuth 2.0 knowledge
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## Phase 1: Research & Planning (2-4 hours)
|
|
16
|
+
|
|
17
|
+
### Step 1.1: API Research
|
|
18
|
+
|
|
19
|
+
**Objective:** Understand the API capabilities, limitations, and requirements.
|
|
20
|
+
|
|
21
|
+
**Tasks:**
|
|
22
|
+
1. **Review API Documentation**
|
|
23
|
+
- Read official API docs thoroughly
|
|
24
|
+
- Identify API version (e.g., LinkedIn uses v2, Twitter uses v2)
|
|
25
|
+
- Note API base URL (e.g., `https://api.linkedin.com`)
|
|
26
|
+
- Document rate limits and quotas
|
|
27
|
+
- Understand authentication method (OAuth 2.0, API keys, etc.)
|
|
28
|
+
|
|
29
|
+
2. **Identify Core Endpoints**
|
|
30
|
+
- List all available endpoints
|
|
31
|
+
- Categorize by functionality (e.g., posts, analytics, users)
|
|
32
|
+
- Note request/response formats
|
|
33
|
+
- Document required vs. optional parameters
|
|
34
|
+
|
|
35
|
+
3. **Understand OAuth Scopes**
|
|
36
|
+
- List all available OAuth scopes
|
|
37
|
+
- Map scopes to features you want to implement
|
|
38
|
+
- Note scope dependencies (some scopes require others)
|
|
39
|
+
- Check for special permissions (e.g., LinkedIn org admin)
|
|
40
|
+
|
|
41
|
+
**Example (LinkedIn):**
|
|
42
|
+
```
|
|
43
|
+
API Base: https://api.linkedin.com
|
|
44
|
+
Version: 202501
|
|
45
|
+
Auth: OAuth 2.0
|
|
46
|
+
|
|
47
|
+
Core Endpoints:
|
|
48
|
+
- POST /rest/posts - Create posts (scope: w_member_social)
|
|
49
|
+
- GET /rest/posts - List posts (scope: r_member_social)
|
|
50
|
+
- GET /rest/socialMetadata/{urn} - Get analytics (scope: r_member_social)
|
|
51
|
+
- GET /v2/connections - List connections (scope: r_1st_connections)
|
|
52
|
+
|
|
53
|
+
Rate Limits:
|
|
54
|
+
- 150 posts/day per user
|
|
55
|
+
- 100,000 API requests/day per app
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Step 1.2: Feature Prioritization
|
|
59
|
+
|
|
60
|
+
**Objective:** Decide what features to implement first.
|
|
61
|
+
|
|
62
|
+
**Process:**
|
|
63
|
+
1. **List Potential Features**
|
|
64
|
+
- Write down all possible features
|
|
65
|
+
- Group by complexity (simple, medium, complex)
|
|
66
|
+
- Estimate implementation time for each
|
|
67
|
+
|
|
68
|
+
2. **Create Implementation Phases**
|
|
69
|
+
- Phase 1: Quick wins (basic functionality)
|
|
70
|
+
- Phase 2: Medium features (analytics, advanced reads)
|
|
71
|
+
- Phase 3: Complex features (video uploads, webhooks)
|
|
72
|
+
|
|
73
|
+
3. **Define MVP (Minimum Viable Product)**
|
|
74
|
+
- Choose 3-5 core features for initial release
|
|
75
|
+
- Ensure features provide immediate value
|
|
76
|
+
- Keep scope manageable (1-2 weeks max)
|
|
77
|
+
|
|
78
|
+
**Example (LinkedIn):**
|
|
79
|
+
```
|
|
80
|
+
MVP Features (Week 1):
|
|
81
|
+
✅ Create text posts
|
|
82
|
+
✅ Create article posts (with URL)
|
|
83
|
+
✅ Create image posts
|
|
84
|
+
✅ View user profile
|
|
85
|
+
✅ Check auth status
|
|
86
|
+
|
|
87
|
+
Phase 2 (Week 2):
|
|
88
|
+
✅ Post management (list, view, edit, delete)
|
|
89
|
+
✅ Analytics (stats, reactions, comments)
|
|
90
|
+
✅ Connections management
|
|
91
|
+
|
|
92
|
+
Phase 3 (Week 3):
|
|
93
|
+
✅ Organization pages
|
|
94
|
+
✅ Video uploads
|
|
95
|
+
❌ Messages API (requires special approval)
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Step 1.3: Create Implementation Plan
|
|
99
|
+
|
|
100
|
+
**Objective:** Document the implementation strategy.
|
|
101
|
+
|
|
102
|
+
**Create:** `IMPLEMENTATION_PLAN.md`
|
|
103
|
+
|
|
104
|
+
**Template:**
|
|
105
|
+
```markdown
|
|
106
|
+
# [API Name] Integration Plan
|
|
107
|
+
|
|
108
|
+
## Context
|
|
109
|
+
- Current state: [What exists now]
|
|
110
|
+
- Problem: [What's missing]
|
|
111
|
+
- Solution: [What we're building]
|
|
112
|
+
|
|
113
|
+
## Features
|
|
114
|
+
### Phase 1: MVP
|
|
115
|
+
- Feature 1: [Description]
|
|
116
|
+
- Feature 2: [Description]
|
|
117
|
+
|
|
118
|
+
### Phase 2: Advanced
|
|
119
|
+
- Feature 3: [Description]
|
|
120
|
+
|
|
121
|
+
## Technical Approach
|
|
122
|
+
- OAuth provider: [Name]
|
|
123
|
+
- Scopes needed: [List]
|
|
124
|
+
- API endpoints: [List]
|
|
125
|
+
|
|
126
|
+
## Files to Create/Modify
|
|
127
|
+
- `/agentdev-webui/lib/[api].js` - OAuth handler
|
|
128
|
+
- `/packages/agentdev-client/src/[api]/api.js` - API client
|
|
129
|
+
- `/packages/agentdev-client/src/cli/[api].js` - CLI commands
|
|
130
|
+
- `/packages/agentdev-client/skills/agentdev-[api].md` - Documentation
|
|
131
|
+
|
|
132
|
+
## Timeline
|
|
133
|
+
- Week 1: OAuth + Basic API
|
|
134
|
+
- Week 2: Advanced features
|
|
135
|
+
- Week 3: Testing + Documentation
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
---
|
|
139
|
+
|
|
140
|
+
## Phase 2: OAuth Setup (3-5 hours)
|
|
141
|
+
|
|
142
|
+
### Step 2.1: Register OAuth Application
|
|
143
|
+
|
|
144
|
+
**Objective:** Get OAuth credentials from the API provider.
|
|
145
|
+
|
|
146
|
+
**Tasks:**
|
|
147
|
+
1. **Create Developer Account**
|
|
148
|
+
- Sign up for developer access
|
|
149
|
+
- Verify email/identity if required
|
|
150
|
+
- Accept developer terms
|
|
151
|
+
|
|
152
|
+
2. **Create OAuth Application**
|
|
153
|
+
- Go to API provider's developer portal
|
|
154
|
+
- Create new app/project
|
|
155
|
+
- Fill in application details:
|
|
156
|
+
- Name: "AgentDev Integration"
|
|
157
|
+
- Description: "AI agent platform integration"
|
|
158
|
+
- Website: Your agentdev URL
|
|
159
|
+
- Redirect URI: `https://your-domain.com/api/auth/callback/[provider]`
|
|
160
|
+
|
|
161
|
+
3. **Save Credentials**
|
|
162
|
+
- Copy Client ID
|
|
163
|
+
- Copy Client Secret
|
|
164
|
+
- Store securely (never commit to git)
|
|
165
|
+
- Add to password manager
|
|
166
|
+
|
|
167
|
+
**Example (LinkedIn):**
|
|
168
|
+
```
|
|
169
|
+
Portal: https://www.linkedin.com/developers/apps
|
|
170
|
+
Redirect URI: https://agentdev.datatamer.ai/api/auth/callback/linkedin
|
|
171
|
+
Scopes: openid profile email w_member_social r_member_social...
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Step 2.2: Create Server-Side OAuth Handler
|
|
175
|
+
|
|
176
|
+
**Objective:** Implement OAuth flow in the backend.
|
|
177
|
+
|
|
178
|
+
**File:** `/agentdev-webui/lib/[api-name].js`
|
|
179
|
+
|
|
180
|
+
**Template:**
|
|
181
|
+
```javascript
|
|
182
|
+
const db = require('./database');
|
|
183
|
+
const encryption = require('./encryption');
|
|
184
|
+
|
|
185
|
+
const AUTH_URL = 'https://provider.com/oauth/authorize';
|
|
186
|
+
const TOKEN_URL = 'https://provider.com/oauth/token';
|
|
187
|
+
const API_BASE = 'https://api.provider.com';
|
|
188
|
+
const SCOPES = 'scope1 scope2 scope3';
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* Build authorization URL
|
|
192
|
+
*/
|
|
193
|
+
async function getAuthorizationUrl(state, redirectUri) {
|
|
194
|
+
const config = await db.getOAuthProviderConfig('[provider]');
|
|
195
|
+
if (!config || !config.client_id) {
|
|
196
|
+
throw new Error('[Provider] OAuth not configured');
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const clientId = encryption.decrypt(config.client_id);
|
|
200
|
+
const params = new URLSearchParams({
|
|
201
|
+
response_type: 'code',
|
|
202
|
+
client_id: clientId,
|
|
203
|
+
redirect_uri: redirectUri,
|
|
204
|
+
state: state,
|
|
205
|
+
scope: SCOPES
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
return `${AUTH_URL}?${params.toString()}`;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
/**
|
|
212
|
+
* Exchange authorization code for access token
|
|
213
|
+
*/
|
|
214
|
+
async function exchangeCodeForToken(code, redirectUri) {
|
|
215
|
+
const config = await db.getOAuthProviderConfig('[provider]');
|
|
216
|
+
const clientId = encryption.decrypt(config.client_id);
|
|
217
|
+
const clientSecret = encryption.decrypt(config.client_secret);
|
|
218
|
+
|
|
219
|
+
const res = await fetch(TOKEN_URL, {
|
|
220
|
+
method: 'POST',
|
|
221
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
222
|
+
body: new URLSearchParams({
|
|
223
|
+
grant_type: 'authorization_code',
|
|
224
|
+
code,
|
|
225
|
+
redirect_uri: redirectUri,
|
|
226
|
+
client_id: clientId,
|
|
227
|
+
client_secret: clientSecret
|
|
228
|
+
}).toString()
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
if (!res.ok) {
|
|
232
|
+
const text = await res.text();
|
|
233
|
+
throw new Error(`Token exchange failed (${res.status}): ${text}`);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
const data = await res.json();
|
|
237
|
+
return {
|
|
238
|
+
accessToken: data.access_token,
|
|
239
|
+
refreshToken: data.refresh_token || null,
|
|
240
|
+
expiresIn: data.expires_in
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Refresh an expired access token
|
|
246
|
+
*/
|
|
247
|
+
async function refreshAccessToken(refreshToken) {
|
|
248
|
+
const config = await db.getOAuthProviderConfig('[provider]');
|
|
249
|
+
const clientId = encryption.decrypt(config.client_id);
|
|
250
|
+
const clientSecret = encryption.decrypt(config.client_secret);
|
|
251
|
+
|
|
252
|
+
const res = await fetch(TOKEN_URL, {
|
|
253
|
+
method: 'POST',
|
|
254
|
+
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
|
|
255
|
+
body: new URLSearchParams({
|
|
256
|
+
grant_type: 'refresh_token',
|
|
257
|
+
refresh_token: refreshToken,
|
|
258
|
+
client_id: clientId,
|
|
259
|
+
client_secret: clientSecret
|
|
260
|
+
}).toString()
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
if (!res.ok) {
|
|
264
|
+
const text = await res.text();
|
|
265
|
+
throw new Error(`Token refresh failed (${res.status}): ${text}`);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
const data = await res.json();
|
|
269
|
+
return {
|
|
270
|
+
accessToken: data.access_token,
|
|
271
|
+
refreshToken: data.refresh_token || refreshToken,
|
|
272
|
+
expiresIn: data.expires_in
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/**
|
|
277
|
+
* Fetch user profile
|
|
278
|
+
*/
|
|
279
|
+
async function fetchProfile(accessToken) {
|
|
280
|
+
const res = await fetch(`${API_BASE}/v1/user`, {
|
|
281
|
+
headers: {
|
|
282
|
+
'Authorization': `Bearer ${accessToken}`
|
|
283
|
+
}
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
if (!res.ok) {
|
|
287
|
+
const text = await res.text();
|
|
288
|
+
throw new Error(`Profile fetch failed (${res.status}): ${text}`);
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const data = await res.json();
|
|
292
|
+
return {
|
|
293
|
+
id: data.id,
|
|
294
|
+
name: data.name,
|
|
295
|
+
email: data.email,
|
|
296
|
+
picture: data.avatar_url
|
|
297
|
+
};
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
module.exports = {
|
|
301
|
+
getAuthorizationUrl,
|
|
302
|
+
exchangeCodeForToken,
|
|
303
|
+
refreshAccessToken,
|
|
304
|
+
fetchProfile,
|
|
305
|
+
AUTH_URL,
|
|
306
|
+
TOKEN_URL,
|
|
307
|
+
SCOPES
|
|
308
|
+
};
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Step 2.3: Configure OAuth in Admin Panel
|
|
312
|
+
|
|
313
|
+
**Objective:** Add OAuth credentials to database.
|
|
314
|
+
|
|
315
|
+
**Tasks:**
|
|
316
|
+
1. **Access Admin Panel**
|
|
317
|
+
- Navigate to `/admin/oauth` (or create this page)
|
|
318
|
+
- Add new provider section
|
|
319
|
+
|
|
320
|
+
2. **Add Provider Configuration**
|
|
321
|
+
```sql
|
|
322
|
+
INSERT INTO oauth_providers (
|
|
323
|
+
provider_name,
|
|
324
|
+
client_id,
|
|
325
|
+
client_secret,
|
|
326
|
+
enabled
|
|
327
|
+
) VALUES (
|
|
328
|
+
'[provider]',
|
|
329
|
+
'[encrypted_client_id]',
|
|
330
|
+
'[encrypted_client_secret]',
|
|
331
|
+
true
|
|
332
|
+
);
|
|
333
|
+
```
|
|
334
|
+
|
|
335
|
+
3. **Test OAuth Flow**
|
|
336
|
+
- Visit `/profile` page
|
|
337
|
+
- Click "Connect [Provider]"
|
|
338
|
+
- Complete authorization
|
|
339
|
+
- Verify token is saved
|
|
340
|
+
|
|
341
|
+
---
|
|
342
|
+
|
|
343
|
+
## Phase 3: API Client Implementation (8-12 hours)
|
|
344
|
+
|
|
345
|
+
### Step 3.1: Create Modular API Structure
|
|
346
|
+
|
|
347
|
+
**Objective:** Build a well-organized API client.
|
|
348
|
+
|
|
349
|
+
**Directory Structure:**
|
|
350
|
+
```
|
|
351
|
+
/packages/agentdev-client/src/[api-name]/
|
|
352
|
+
├── api.js (re-export wrapper)
|
|
353
|
+
└── api/
|
|
354
|
+
├── index.js (main entry point)
|
|
355
|
+
├── core.js (HTTP client)
|
|
356
|
+
├── [feature1].js (e.g., posts.js)
|
|
357
|
+
├── [feature2].js (e.g., analytics.js)
|
|
358
|
+
└── [feature3].js (e.g., users.js)
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Step 3.2: Create Core HTTP Client
|
|
362
|
+
|
|
363
|
+
**File:** `/packages/agentdev-client/src/[api]/api/core.js`
|
|
364
|
+
|
|
365
|
+
**Template:**
|
|
366
|
+
```javascript
|
|
367
|
+
/**
|
|
368
|
+
* [API Name] API Core - Base HTTP client and utilities
|
|
369
|
+
*/
|
|
370
|
+
|
|
371
|
+
export const API_BASE = 'https://api.provider.com';
|
|
372
|
+
export const API_VERSION = 'v1';
|
|
373
|
+
|
|
374
|
+
/**
|
|
375
|
+
* Core REST API helper
|
|
376
|
+
* Handles authentication, error responses, and standard headers
|
|
377
|
+
*/
|
|
378
|
+
export async function apiRequest(method, path, token, body = null, extraHeaders = {}) {
|
|
379
|
+
const opts = {
|
|
380
|
+
method,
|
|
381
|
+
headers: {
|
|
382
|
+
'Authorization': `Bearer ${token}`,
|
|
383
|
+
'Accept': 'application/json',
|
|
384
|
+
...extraHeaders
|
|
385
|
+
}
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
if (body) {
|
|
389
|
+
opts.headers['Content-Type'] = 'application/json';
|
|
390
|
+
opts.body = JSON.stringify(body);
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
const res = await fetch(`${API_BASE}${path}`, opts);
|
|
394
|
+
|
|
395
|
+
if (!res.ok) {
|
|
396
|
+
const text = await res.text();
|
|
397
|
+
|
|
398
|
+
// Handle token expiration
|
|
399
|
+
if (res.status === 401) {
|
|
400
|
+
throw new Error('TOKEN_EXPIRED');
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
// Handle rate limiting
|
|
404
|
+
if (res.status === 429) {
|
|
405
|
+
const retryAfter = res.headers.get('Retry-After');
|
|
406
|
+
throw new Error(`API rate limit exceeded. Retry after: ${retryAfter || 'unknown'}`);
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
// Handle forbidden
|
|
410
|
+
if (res.status === 403) {
|
|
411
|
+
throw new Error('Insufficient permissions. Check OAuth scopes.');
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
throw new Error(`API ${method} ${path} failed (${res.status}): ${text}`);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// Handle No Content responses
|
|
418
|
+
if (res.status === 204) {
|
|
419
|
+
return { success: true };
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
// Handle Created responses
|
|
423
|
+
if (res.status === 201) {
|
|
424
|
+
const location = res.headers.get('Location');
|
|
425
|
+
if (location) {
|
|
426
|
+
return { id: location, success: true };
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
return res.json();
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Resolve token from CLI argument or environment variable
|
|
435
|
+
*/
|
|
436
|
+
export function resolveToken(cliToken) {
|
|
437
|
+
return cliToken || process.env.[PROVIDER]_TOKEN || null;
|
|
438
|
+
}
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### Step 3.3: Implement Feature Modules
|
|
442
|
+
|
|
443
|
+
**Pattern:** One module per feature category
|
|
444
|
+
|
|
445
|
+
**Example - Posts Module:**
|
|
446
|
+
|
|
447
|
+
**File:** `/packages/agentdev-client/src/[api]/api/posts.js`
|
|
448
|
+
|
|
449
|
+
```javascript
|
|
450
|
+
/**
|
|
451
|
+
* [API Name] - Posts Operations
|
|
452
|
+
*/
|
|
453
|
+
|
|
454
|
+
import { apiRequest } from './core.js';
|
|
455
|
+
|
|
456
|
+
/**
|
|
457
|
+
* Create a text post
|
|
458
|
+
*/
|
|
459
|
+
export async function createPost(token, text, options = {}) {
|
|
460
|
+
const body = {
|
|
461
|
+
text: text,
|
|
462
|
+
visibility: options.visibility || 'public'
|
|
463
|
+
};
|
|
464
|
+
|
|
465
|
+
return apiRequest('POST', '/v1/posts', token, body);
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* List user's posts
|
|
470
|
+
*/
|
|
471
|
+
export async function listPosts(token, userId, options = {}) {
|
|
472
|
+
const params = new URLSearchParams({
|
|
473
|
+
user_id: userId,
|
|
474
|
+
limit: options.limit || 10,
|
|
475
|
+
offset: options.offset || 0
|
|
476
|
+
});
|
|
477
|
+
|
|
478
|
+
return apiRequest('GET', `/v1/posts?${params}`, token);
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
/**
|
|
482
|
+
* Get post details
|
|
483
|
+
*/
|
|
484
|
+
export async function getPost(token, postId) {
|
|
485
|
+
return apiRequest('GET', `/v1/posts/${postId}`, token);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
/**
|
|
489
|
+
* Delete a post
|
|
490
|
+
*/
|
|
491
|
+
export async function deletePost(token, postId) {
|
|
492
|
+
return apiRequest('DELETE', `/v1/posts/${postId}`, token);
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
/**
|
|
496
|
+
* Update a post
|
|
497
|
+
*/
|
|
498
|
+
export async function updatePost(token, postId, updates) {
|
|
499
|
+
return apiRequest('PATCH', `/v1/posts/${postId}`, token, updates);
|
|
500
|
+
}
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
### Step 3.4: Create Main Index
|
|
504
|
+
|
|
505
|
+
**File:** `/packages/agentdev-client/src/[api]/api/index.js`
|
|
506
|
+
|
|
507
|
+
```javascript
|
|
508
|
+
/**
|
|
509
|
+
* [API Name] - Main Entry Point
|
|
510
|
+
* Re-exports all API functions from modular structure
|
|
511
|
+
*/
|
|
512
|
+
|
|
513
|
+
// Core utilities
|
|
514
|
+
export { apiRequest, resolveToken, API_BASE, API_VERSION } from './core.js';
|
|
515
|
+
|
|
516
|
+
// Feature modules
|
|
517
|
+
export {
|
|
518
|
+
createPost,
|
|
519
|
+
listPosts,
|
|
520
|
+
getPost,
|
|
521
|
+
deletePost,
|
|
522
|
+
updatePost
|
|
523
|
+
} from './posts.js';
|
|
524
|
+
|
|
525
|
+
export {
|
|
526
|
+
getUserProfile,
|
|
527
|
+
updateUserProfile
|
|
528
|
+
} from './users.js';
|
|
529
|
+
|
|
530
|
+
// Add more exports as you create modules
|
|
531
|
+
```
|
|
532
|
+
|
|
533
|
+
### Step 3.5: Create Re-export Wrapper
|
|
534
|
+
|
|
535
|
+
**File:** `/packages/agentdev-client/src/[api]/api.js`
|
|
536
|
+
|
|
537
|
+
```javascript
|
|
538
|
+
/**
|
|
539
|
+
* [API Name] REST API module (ESM)
|
|
540
|
+
* Provides programmatic access to [Provider] APIs for agents.
|
|
541
|
+
*
|
|
542
|
+
* This file maintains backward compatibility by re-exporting
|
|
543
|
+
* from the modular structure in ./api/
|
|
544
|
+
*/
|
|
545
|
+
|
|
546
|
+
export * from './api/index.js';
|
|
547
|
+
```
|
|
548
|
+
|
|
549
|
+
---
|
|
550
|
+
|
|
551
|
+
## Phase 4: CLI Commands Implementation (6-10 hours)
|
|
552
|
+
|
|
553
|
+
### Step 4.1: Create Modular CLI Structure
|
|
554
|
+
|
|
555
|
+
**Directory Structure:**
|
|
556
|
+
```
|
|
557
|
+
/packages/agentdev-client/src/cli/[api-name]/
|
|
558
|
+
├── index.js (main registration)
|
|
559
|
+
├── helpers.js (shared utilities)
|
|
560
|
+
├── [feature1].js (e.g., posts.js)
|
|
561
|
+
├── [feature2].js (e.g., analytics.js)
|
|
562
|
+
└── [feature3].js (e.g., users.js)
|
|
563
|
+
```
|
|
564
|
+
|
|
565
|
+
### Step 4.2: Create CLI Helpers
|
|
566
|
+
|
|
567
|
+
**File:** `/packages/agentdev-client/src/cli/[api]/helpers.js`
|
|
568
|
+
|
|
569
|
+
```javascript
|
|
570
|
+
/**
|
|
571
|
+
* [API Name] CLI - Shared Helpers
|
|
572
|
+
*/
|
|
573
|
+
|
|
574
|
+
import chalk from 'chalk';
|
|
575
|
+
import { getConfig } from '../../config/config.js';
|
|
576
|
+
|
|
577
|
+
/**
|
|
578
|
+
* Fetch [Provider] access token from server OAuth endpoint
|
|
579
|
+
*/
|
|
580
|
+
export async function getProviderToken() {
|
|
581
|
+
const config = getConfig();
|
|
582
|
+
const apiUrl = config.apiUrl || 'https://agentdev.datatamer.ai';
|
|
583
|
+
const agentToken = config.token;
|
|
584
|
+
|
|
585
|
+
if (!agentToken) {
|
|
586
|
+
throw new Error('Agent not registered. Run "agentdev register" first.');
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
try {
|
|
590
|
+
const res = await fetch(`${apiUrl}/api/agent/oauth?provider=[provider]`, {
|
|
591
|
+
headers: {
|
|
592
|
+
'Authorization': `Bearer ${agentToken}`,
|
|
593
|
+
'Content-Type': 'application/json'
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
if (!res.ok) {
|
|
598
|
+
if (res.status === 404) {
|
|
599
|
+
throw new Error('[Provider] not connected. Connect at ' + apiUrl + '/profile');
|
|
600
|
+
}
|
|
601
|
+
const text = await res.text();
|
|
602
|
+
throw new Error(`Failed to fetch token (${res.status}): ${text}`);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
const data = await res.json();
|
|
606
|
+
return data.[provider].access_token;
|
|
607
|
+
} catch (error) {
|
|
608
|
+
if (error.message.includes('not connected')) {
|
|
609
|
+
throw error;
|
|
610
|
+
}
|
|
611
|
+
throw new Error(`Failed to fetch token: ${error.message}`);
|
|
612
|
+
}
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
/**
|
|
616
|
+
* Centralized error handler
|
|
617
|
+
*/
|
|
618
|
+
export function handleProviderError(error) {
|
|
619
|
+
if (error.message === 'TOKEN_EXPIRED') {
|
|
620
|
+
console.error(chalk.red('✗ Token expired. Please reconnect at /profile'));
|
|
621
|
+
} else if (error.message.includes('not connected')) {
|
|
622
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
623
|
+
} else if (error.message.includes('rate limit')) {
|
|
624
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
625
|
+
} else if (error.message.includes('permissions')) {
|
|
626
|
+
console.error(chalk.red('✗ ' + error.message));
|
|
627
|
+
console.error(chalk.yellow('Please reconnect to grant new permissions'));
|
|
628
|
+
} else {
|
|
629
|
+
console.error(chalk.red('✗ Operation failed:'), error.message);
|
|
630
|
+
}
|
|
631
|
+
process.exit(1);
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
### Step 4.3: Create Feature Command Handlers
|
|
636
|
+
|
|
637
|
+
**File:** `/packages/agentdev-client/src/cli/[api]/posts.js`
|
|
638
|
+
|
|
639
|
+
```javascript
|
|
640
|
+
/**
|
|
641
|
+
* [API Name] CLI - Post Commands
|
|
642
|
+
*/
|
|
643
|
+
|
|
644
|
+
import chalk from 'chalk';
|
|
645
|
+
import {
|
|
646
|
+
resolveToken,
|
|
647
|
+
createPost,
|
|
648
|
+
listPosts,
|
|
649
|
+
getPost,
|
|
650
|
+
deletePost,
|
|
651
|
+
updatePost
|
|
652
|
+
} from '../../[api]/api.js';
|
|
653
|
+
import { getProviderToken, handleProviderError } from './helpers.js';
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Handle post creation
|
|
657
|
+
*/
|
|
658
|
+
export async function handlePostCreate(opts) {
|
|
659
|
+
try {
|
|
660
|
+
const token = resolveToken() || await getProviderToken();
|
|
661
|
+
|
|
662
|
+
const result = await createPost(token, opts.text, {
|
|
663
|
+
visibility: opts.visibility || 'public'
|
|
664
|
+
});
|
|
665
|
+
|
|
666
|
+
console.log(chalk.green('✓ Post created successfully'));
|
|
667
|
+
if (result.id) {
|
|
668
|
+
console.log(chalk.gray(`Post ID: ${result.id}`));
|
|
669
|
+
}
|
|
670
|
+
} catch (error) {
|
|
671
|
+
handleProviderError(error);
|
|
672
|
+
}
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
/**
|
|
676
|
+
* Handle post listing
|
|
677
|
+
*/
|
|
678
|
+
export async function handlePostList(opts) {
|
|
679
|
+
try {
|
|
680
|
+
const token = resolveToken() || await getProviderToken();
|
|
681
|
+
|
|
682
|
+
const result = await listPosts(token, opts.userId, {
|
|
683
|
+
limit: opts.limit || 10
|
|
684
|
+
});
|
|
685
|
+
|
|
686
|
+
if (!result.posts || result.posts.length === 0) {
|
|
687
|
+
console.log(chalk.yellow('No posts found'));
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
console.log(chalk.bold(`\nPosts (${result.posts.length} shown)`));
|
|
692
|
+
console.log(chalk.gray('─'.repeat(80)));
|
|
693
|
+
|
|
694
|
+
result.posts.forEach((post, index) => {
|
|
695
|
+
console.log(`${chalk.cyan(`${index + 1}.`)} ${post.text.substring(0, 100)}...`);
|
|
696
|
+
console.log(` ${chalk.gray('ID:')} ${post.id}`);
|
|
697
|
+
console.log();
|
|
698
|
+
});
|
|
699
|
+
|
|
700
|
+
console.log(chalk.gray('─'.repeat(80)));
|
|
701
|
+
} catch (error) {
|
|
702
|
+
handleProviderError(error);
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Handle post deletion
|
|
708
|
+
*/
|
|
709
|
+
export async function handlePostDelete(postId, opts) {
|
|
710
|
+
try {
|
|
711
|
+
const token = resolveToken() || await getProviderToken();
|
|
712
|
+
|
|
713
|
+
if (!opts.confirm) {
|
|
714
|
+
console.log(chalk.yellow('⚠ Add --confirm flag to proceed'));
|
|
715
|
+
process.exit(0);
|
|
716
|
+
}
|
|
717
|
+
|
|
718
|
+
await deletePost(token, postId);
|
|
719
|
+
console.log(chalk.green('✓ Post deleted successfully'));
|
|
720
|
+
} catch (error) {
|
|
721
|
+
handleProviderError(error);
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
|
|
725
|
+
/**
|
|
726
|
+
* Register post commands
|
|
727
|
+
*/
|
|
728
|
+
export function registerPostCommands(api) {
|
|
729
|
+
const post = api
|
|
730
|
+
.command('post')
|
|
731
|
+
.description('[Provider] post operations');
|
|
732
|
+
|
|
733
|
+
post
|
|
734
|
+
.command('create')
|
|
735
|
+
.description('Create a post')
|
|
736
|
+
.requiredOption('--text <text>', 'Post text')
|
|
737
|
+
.option('--visibility <type>', 'Visibility: public or private', 'public')
|
|
738
|
+
.action(handlePostCreate);
|
|
739
|
+
|
|
740
|
+
post
|
|
741
|
+
.command('list')
|
|
742
|
+
.description('List posts')
|
|
743
|
+
.option('--user-id <id>', 'User ID')
|
|
744
|
+
.option('--limit <number>', 'Number of posts', '10')
|
|
745
|
+
.action(handlePostList);
|
|
746
|
+
|
|
747
|
+
post
|
|
748
|
+
.command('delete <post-id>')
|
|
749
|
+
.description('Delete a post')
|
|
750
|
+
.option('--confirm', 'Confirm deletion')
|
|
751
|
+
.action(handlePostDelete);
|
|
752
|
+
}
|
|
753
|
+
```
|
|
754
|
+
|
|
755
|
+
### Step 4.4: Create Main CLI Index
|
|
756
|
+
|
|
757
|
+
**File:** `/packages/agentdev-client/src/cli/[api]/index.js`
|
|
758
|
+
|
|
759
|
+
```javascript
|
|
760
|
+
/**
|
|
761
|
+
* [API Name] CLI - Main Entry Point
|
|
762
|
+
*/
|
|
763
|
+
|
|
764
|
+
import { registerPostCommands } from './posts.js';
|
|
765
|
+
import { registerUserCommands } from './users.js';
|
|
766
|
+
// Import other command modules
|
|
767
|
+
|
|
768
|
+
/**
|
|
769
|
+
* Register [Provider] command group with Commander
|
|
770
|
+
*/
|
|
771
|
+
export function register[Provider]Command(program) {
|
|
772
|
+
const api = program
|
|
773
|
+
.command('[provider]')
|
|
774
|
+
.description('[Provider] operations');
|
|
775
|
+
|
|
776
|
+
// Register all command groups
|
|
777
|
+
registerPostCommands(api);
|
|
778
|
+
registerUserCommands(api);
|
|
779
|
+
// Register other command groups
|
|
780
|
+
|
|
781
|
+
return api;
|
|
782
|
+
}
|
|
783
|
+
```
|
|
784
|
+
|
|
785
|
+
### Step 4.5: Create CLI Re-export Wrapper
|
|
786
|
+
|
|
787
|
+
**File:** `/packages/agentdev-client/src/cli/[api].js`
|
|
788
|
+
|
|
789
|
+
```javascript
|
|
790
|
+
/**
|
|
791
|
+
* `agentdev [provider]` subcommand group
|
|
792
|
+
*
|
|
793
|
+
* This file maintains backward compatibility by re-exporting
|
|
794
|
+
* from the modular structure in ./[api]/
|
|
795
|
+
*/
|
|
796
|
+
|
|
797
|
+
export { register[Provider]Command } from './[api]/index.js';
|
|
798
|
+
```
|
|
799
|
+
|
|
800
|
+
---
|
|
801
|
+
|
|
802
|
+
## Phase 5: Skill Documentation (2-4 hours)
|
|
803
|
+
|
|
804
|
+
### Step 5.1: Create Skill File
|
|
805
|
+
|
|
806
|
+
**File:** `/packages/agentdev-client/skills/agentdev-[provider].md`
|
|
807
|
+
|
|
808
|
+
**Template:**
|
|
809
|
+
```markdown
|
|
810
|
+
# agentdev [provider] — [Provider] CLI
|
|
811
|
+
|
|
812
|
+
Use `agentdev [provider]` for ALL [Provider] operations. Do NOT attempt to use [Provider] APIs directly.
|
|
813
|
+
|
|
814
|
+
## Prerequisites
|
|
815
|
+
|
|
816
|
+
User must connect their [Provider] account first:
|
|
817
|
+
1. Visit /profile page on AgentDev
|
|
818
|
+
2. Click "Connect [Provider]"
|
|
819
|
+
3. Complete OAuth authorization flow
|
|
820
|
+
|
|
821
|
+
If [Provider] is not connected, all commands will fail with instructions to connect.
|
|
822
|
+
|
|
823
|
+
## Commands
|
|
824
|
+
|
|
825
|
+
### Create Post
|
|
826
|
+
|
|
827
|
+
```bash
|
|
828
|
+
agentdev [provider] post create --text "Hello world!"
|
|
829
|
+
```
|
|
830
|
+
|
|
831
|
+
### List Posts
|
|
832
|
+
|
|
833
|
+
```bash
|
|
834
|
+
agentdev [provider] post list --limit 10
|
|
835
|
+
```
|
|
836
|
+
|
|
837
|
+
### Delete Post
|
|
838
|
+
|
|
839
|
+
```bash
|
|
840
|
+
agentdev [provider] post delete <post-id> --confirm
|
|
841
|
+
```
|
|
842
|
+
|
|
843
|
+
## Rate Limits
|
|
844
|
+
|
|
845
|
+
- **[X] requests per hour** per user
|
|
846
|
+
- **[Y] posts per day** per user
|
|
847
|
+
|
|
848
|
+
If rate limit is exceeded, you'll receive a clear error message.
|
|
849
|
+
|
|
850
|
+
## Error Handling
|
|
851
|
+
|
|
852
|
+
| Error | Meaning | Action |
|
|
853
|
+
|-------|---------|--------|
|
|
854
|
+
| "[Provider] not connected" | User hasn't connected account | Direct user to /profile |
|
|
855
|
+
| "Token expired" | OAuth token expired | User must reconnect at /profile |
|
|
856
|
+
| "Rate limit exceeded" | Hit API rate limits | Wait for retry period |
|
|
857
|
+
|
|
858
|
+
## Agent Task Examples
|
|
859
|
+
|
|
860
|
+
### Example 1: Post update
|
|
861
|
+
|
|
862
|
+
When asked to "post to [Provider] about completing task":
|
|
863
|
+
|
|
864
|
+
```bash
|
|
865
|
+
agentdev [provider] post create --text "✅ Completed task #123"
|
|
866
|
+
```
|
|
867
|
+
|
|
868
|
+
### Example 2: Check recent posts
|
|
869
|
+
|
|
870
|
+
When asked to "show my recent [Provider] posts":
|
|
871
|
+
|
|
872
|
+
```bash
|
|
873
|
+
agentdev [provider] post list --limit 5
|
|
874
|
+
```
|
|
875
|
+
|
|
876
|
+
## Required OAuth Scopes
|
|
877
|
+
|
|
878
|
+
The following scopes are automatically requested during OAuth flow:
|
|
879
|
+
- `scope1` - Description
|
|
880
|
+
- `scope2` - Description
|
|
881
|
+
- `scope3` - Description
|
|
882
|
+
|
|
883
|
+
## Notes
|
|
884
|
+
|
|
885
|
+
- All posts are created as the authenticated user
|
|
886
|
+
- Post IDs are returned on successful creation
|
|
887
|
+
- Token refresh is handled automatically
|
|
888
|
+
```
|
|
889
|
+
|
|
890
|
+
---
|
|
891
|
+
|
|
892
|
+
## Phase 6: Testing & Validation (4-6 hours)
|
|
893
|
+
|
|
894
|
+
### Step 6.1: Manual Testing Checklist
|
|
895
|
+
|
|
896
|
+
**OAuth Flow:**
|
|
897
|
+
- [ ] Visit /profile page
|
|
898
|
+
- [ ] Click "Connect [Provider]"
|
|
899
|
+
- [ ] Complete authorization
|
|
900
|
+
- [ ] Verify token is saved in database
|
|
901
|
+
- [ ] Verify token works for API calls
|
|
902
|
+
|
|
903
|
+
**CLI Commands:**
|
|
904
|
+
- [ ] Test `agentdev [provider] auth` - Check connection status
|
|
905
|
+
- [ ] Test `agentdev [provider] post create --text "test"` - Create post
|
|
906
|
+
- [ ] Test `agentdev [provider] post list` - List posts
|
|
907
|
+
- [ ] Test `agentdev [provider] post delete <id> --confirm` - Delete post
|
|
908
|
+
- [ ] Test error handling (invalid token, missing scopes, rate limits)
|
|
909
|
+
|
|
910
|
+
**Error Cases:**
|
|
911
|
+
- [ ] Test with expired token
|
|
912
|
+
- [ ] Test with missing OAuth scopes
|
|
913
|
+
- [ ] Test with invalid post ID
|
|
914
|
+
- [ ] Test rate limit handling
|
|
915
|
+
- [ ] Test network errors
|
|
916
|
+
|
|
917
|
+
### Step 6.2: Create Unit Tests
|
|
918
|
+
|
|
919
|
+
**File:** `/packages/agentdev-client/src/[api]/api/core.test.js`
|
|
920
|
+
|
|
921
|
+
```javascript
|
|
922
|
+
import { apiRequest } from './core.js';
|
|
923
|
+
|
|
924
|
+
describe('[Provider] API Core', () => {
|
|
925
|
+
test('apiRequest handles 401 errors', async () => {
|
|
926
|
+
global.fetch = jest.fn(() =>
|
|
927
|
+
Promise.resolve({
|
|
928
|
+
ok: false,
|
|
929
|
+
status: 401,
|
|
930
|
+
text: () => Promise.resolve('Unauthorized')
|
|
931
|
+
})
|
|
932
|
+
);
|
|
933
|
+
|
|
934
|
+
await expect(
|
|
935
|
+
apiRequest('GET', '/test', 'invalid-token')
|
|
936
|
+
).rejects.toThrow('TOKEN_EXPIRED');
|
|
937
|
+
});
|
|
938
|
+
|
|
939
|
+
test('apiRequest handles 429 rate limits', async () => {
|
|
940
|
+
global.fetch = jest.fn(() =>
|
|
941
|
+
Promise.resolve({
|
|
942
|
+
ok: false,
|
|
943
|
+
status: 429,
|
|
944
|
+
headers: new Map([['Retry-After', '60']]),
|
|
945
|
+
text: () => Promise.resolve('Rate limit')
|
|
946
|
+
})
|
|
947
|
+
);
|
|
948
|
+
|
|
949
|
+
await expect(
|
|
950
|
+
apiRequest('GET', '/test', 'token')
|
|
951
|
+
).rejects.toThrow('rate limit');
|
|
952
|
+
});
|
|
953
|
+
});
|
|
954
|
+
```
|
|
955
|
+
|
|
956
|
+
### Step 6.3: Integration Testing
|
|
957
|
+
|
|
958
|
+
**Create:** `/packages/agentdev-client/src/[api]/integration.test.js`
|
|
959
|
+
|
|
960
|
+
```javascript
|
|
961
|
+
/**
|
|
962
|
+
* Integration tests for [Provider] API
|
|
963
|
+
* These tests require valid OAuth credentials
|
|
964
|
+
*/
|
|
965
|
+
|
|
966
|
+
import {
|
|
967
|
+
createPost,
|
|
968
|
+
listPosts,
|
|
969
|
+
deletePost
|
|
970
|
+
} from './api.js';
|
|
971
|
+
|
|
972
|
+
// Only run if token is available
|
|
973
|
+
const TOKEN = process.env.[PROVIDER]_TOKEN;
|
|
974
|
+
const runIntegrationTests = TOKEN && process.env.RUN_INTEGRATION_TESTS;
|
|
975
|
+
|
|
976
|
+
describe.skipIf(!runIntegrationTests)('[Provider] Integration Tests', () => {
|
|
977
|
+
let testPostId;
|
|
978
|
+
|
|
979
|
+
test('Create post', async () => {
|
|
980
|
+
const result = await createPost(TOKEN, 'Test post from integration tests');
|
|
981
|
+
expect(result.id).toBeDefined();
|
|
982
|
+
testPostId = result.id;
|
|
983
|
+
});
|
|
984
|
+
|
|
985
|
+
test('List posts', async () => {
|
|
986
|
+
const result = await listPosts(TOKEN, 'me');
|
|
987
|
+
expect(result.posts).toBeDefined();
|
|
988
|
+
expect(Array.isArray(result.posts)).toBe(true);
|
|
989
|
+
});
|
|
990
|
+
|
|
991
|
+
test('Delete post', async () => {
|
|
992
|
+
if (testPostId) {
|
|
993
|
+
const result = await deletePost(TOKEN, testPostId);
|
|
994
|
+
expect(result.success).toBe(true);
|
|
995
|
+
}
|
|
996
|
+
});
|
|
997
|
+
});
|
|
998
|
+
```
|
|
999
|
+
|
|
1000
|
+
---
|
|
1001
|
+
|
|
1002
|
+
## Phase 7: Deployment & Documentation (2-3 hours)
|
|
1003
|
+
|
|
1004
|
+
### Step 7.1: Update Main CLI Entry Point
|
|
1005
|
+
|
|
1006
|
+
**File:** `/packages/agentdev-client/src/cli/index.js`
|
|
1007
|
+
|
|
1008
|
+
Add your new command:
|
|
1009
|
+
|
|
1010
|
+
```javascript
|
|
1011
|
+
import { register[Provider]Command } from './cli/[provider].js';
|
|
1012
|
+
|
|
1013
|
+
export function registerCommands(program) {
|
|
1014
|
+
// ... existing commands
|
|
1015
|
+
register[Provider]Command(program);
|
|
1016
|
+
}
|
|
1017
|
+
```
|
|
1018
|
+
|
|
1019
|
+
### Step 7.2: Build & Test
|
|
1020
|
+
|
|
1021
|
+
```bash
|
|
1022
|
+
cd /packages/agentdev-client
|
|
1023
|
+
npm run build
|
|
1024
|
+
npm test
|
|
1025
|
+
|
|
1026
|
+
# Test CLI locally
|
|
1027
|
+
node dist/cli/index.js [provider] auth
|
|
1028
|
+
node dist/cli/index.js [provider] post create --text "Test"
|
|
1029
|
+
```
|
|
1030
|
+
|
|
1031
|
+
### Step 7.3: Create Migration Guide
|
|
1032
|
+
|
|
1033
|
+
**File:** `MIGRATION_GUIDE_[PROVIDER].md`
|
|
1034
|
+
|
|
1035
|
+
```markdown
|
|
1036
|
+
# [Provider] Integration - Migration Guide
|
|
1037
|
+
|
|
1038
|
+
## For Users
|
|
1039
|
+
|
|
1040
|
+
### Step 1: Connect Your Account
|
|
1041
|
+
1. Visit https://agentdev.datatamer.ai/profile
|
|
1042
|
+
2. Click "Connect [Provider]"
|
|
1043
|
+
3. Authorize the application
|
|
1044
|
+
4. Verify connection with: `agentdev [provider] auth`
|
|
1045
|
+
|
|
1046
|
+
### Step 2: Update CLI (if needed)
|
|
1047
|
+
```bash
|
|
1048
|
+
npm install -g agentdev-client@latest
|
|
1049
|
+
```
|
|
1050
|
+
|
|
1051
|
+
### Step 3: Start Using
|
|
1052
|
+
```bash
|
|
1053
|
+
agentdev [provider] post create --text "Hello from AgentDev!"
|
|
1054
|
+
```
|
|
1055
|
+
|
|
1056
|
+
## For Developers
|
|
1057
|
+
|
|
1058
|
+
### New Files Added
|
|
1059
|
+
- `/agentdev-webui/lib/[provider].js` - OAuth handler
|
|
1060
|
+
- `/packages/agentdev-client/src/[provider]/api/` - API modules
|
|
1061
|
+
- `/packages/agentdev-client/src/cli/[provider]/` - CLI modules
|
|
1062
|
+
- `/packages/agentdev-client/skills/agentdev-[provider].md` - Documentation
|
|
1063
|
+
|
|
1064
|
+
### OAuth Scopes
|
|
1065
|
+
The following scopes are requested:
|
|
1066
|
+
- scope1, scope2, scope3
|
|
1067
|
+
|
|
1068
|
+
### Environment Variables (optional)
|
|
1069
|
+
```bash
|
|
1070
|
+
export [PROVIDER]_TOKEN="your-token-here"
|
|
1071
|
+
```
|
|
1072
|
+
```
|
|
1073
|
+
|
|
1074
|
+
### Step 7.4: Create README Section
|
|
1075
|
+
|
|
1076
|
+
Add to main README:
|
|
1077
|
+
|
|
1078
|
+
```markdown
|
|
1079
|
+
## [Provider] Integration
|
|
1080
|
+
|
|
1081
|
+
AgentDev supports [Provider] integration for [brief description].
|
|
1082
|
+
|
|
1083
|
+
### Setup
|
|
1084
|
+
1. Connect your [Provider] account at `/profile`
|
|
1085
|
+
2. Use CLI: `agentdev [provider] --help`
|
|
1086
|
+
3. See full docs: [Link to skill doc]
|
|
1087
|
+
|
|
1088
|
+
### Examples
|
|
1089
|
+
```bash
|
|
1090
|
+
# Create a post
|
|
1091
|
+
agentdev [provider] post create --text "Hello!"
|
|
1092
|
+
|
|
1093
|
+
# List posts
|
|
1094
|
+
agentdev [provider] post list --limit 10
|
|
1095
|
+
```
|
|
1096
|
+
|
|
1097
|
+
### Rate Limits
|
|
1098
|
+
- X posts per day
|
|
1099
|
+
- Y API requests per hour
|
|
1100
|
+
```
|
|
1101
|
+
|
|
1102
|
+
---
|
|
1103
|
+
|
|
1104
|
+
## Phase 8: Monitoring & Iteration (Ongoing)
|
|
1105
|
+
|
|
1106
|
+
### Step 8.1: Add Logging
|
|
1107
|
+
|
|
1108
|
+
**Update API client to log important events:**
|
|
1109
|
+
|
|
1110
|
+
```javascript
|
|
1111
|
+
export async function apiRequest(method, path, token, body, extraHeaders) {
|
|
1112
|
+
console.log(`[${new Date().toISOString()}] ${method} ${path}`);
|
|
1113
|
+
|
|
1114
|
+
try {
|
|
1115
|
+
const result = await fetch(/* ... */);
|
|
1116
|
+
console.log(`[${new Date().toISOString()}] ${method} ${path} - ${result.status}`);
|
|
1117
|
+
return result;
|
|
1118
|
+
} catch (error) {
|
|
1119
|
+
console.error(`[${new Date().toISOString()}] ${method} ${path} - ERROR:`, error.message);
|
|
1120
|
+
throw error;
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
```
|
|
1124
|
+
|
|
1125
|
+
### Step 8.2: Monitor Usage
|
|
1126
|
+
|
|
1127
|
+
**Track:**
|
|
1128
|
+
- Number of API calls per day
|
|
1129
|
+
- Error rates
|
|
1130
|
+
- Most used commands
|
|
1131
|
+
- Token refresh frequency
|
|
1132
|
+
- Rate limit hits
|
|
1133
|
+
|
|
1134
|
+
### Step 8.3: Gather Feedback
|
|
1135
|
+
|
|
1136
|
+
**Create feedback channels:**
|
|
1137
|
+
- GitHub issues for bug reports
|
|
1138
|
+
- Discord/Slack for questions
|
|
1139
|
+
- Usage analytics for feature requests
|
|
1140
|
+
|
|
1141
|
+
### Step 8.4: Iterate
|
|
1142
|
+
|
|
1143
|
+
**Based on feedback:**
|
|
1144
|
+
1. Add missing features
|
|
1145
|
+
2. Fix bugs
|
|
1146
|
+
3. Improve error messages
|
|
1147
|
+
4. Optimize performance
|
|
1148
|
+
5. Update documentation
|
|
1149
|
+
|
|
1150
|
+
---
|
|
1151
|
+
|
|
1152
|
+
## Common Patterns & Best Practices
|
|
1153
|
+
|
|
1154
|
+
### OAuth Best Practices
|
|
1155
|
+
|
|
1156
|
+
1. **Always Encrypt Credentials**
|
|
1157
|
+
```javascript
|
|
1158
|
+
const encrypted = encryption.encrypt(clientSecret);
|
|
1159
|
+
```
|
|
1160
|
+
|
|
1161
|
+
2. **Handle Token Refresh**
|
|
1162
|
+
```javascript
|
|
1163
|
+
if (isTokenExpired(token)) {
|
|
1164
|
+
token = await refreshAccessToken(refreshToken);
|
|
1165
|
+
}
|
|
1166
|
+
```
|
|
1167
|
+
|
|
1168
|
+
3. **Store Tokens Securely**
|
|
1169
|
+
- Never log tokens
|
|
1170
|
+
- Encrypt in database
|
|
1171
|
+
- Don't commit to git
|
|
1172
|
+
|
|
1173
|
+
### API Client Best Practices
|
|
1174
|
+
|
|
1175
|
+
1. **Use Modular Structure**
|
|
1176
|
+
- One module per feature category
|
|
1177
|
+
- Core module for shared logic
|
|
1178
|
+
- Index for re-exports
|
|
1179
|
+
|
|
1180
|
+
2. **Handle Errors Gracefully**
|
|
1181
|
+
```javascript
|
|
1182
|
+
if (res.status === 401) throw new Error('TOKEN_EXPIRED');
|
|
1183
|
+
if (res.status === 429) throw new Error('RATE_LIMIT');
|
|
1184
|
+
if (res.status === 403) throw new Error('FORBIDDEN');
|
|
1185
|
+
```
|
|
1186
|
+
|
|
1187
|
+
3. **Validate Input**
|
|
1188
|
+
```javascript
|
|
1189
|
+
if (!text || text.length > 280) {
|
|
1190
|
+
throw new Error('Text must be 1-280 characters');
|
|
1191
|
+
}
|
|
1192
|
+
```
|
|
1193
|
+
|
|
1194
|
+
4. **Provide Clear Error Messages**
|
|
1195
|
+
```javascript
|
|
1196
|
+
throw new Error('Post not found. Check the post ID and try again.');
|
|
1197
|
+
```
|
|
1198
|
+
|
|
1199
|
+
### CLI Best Practices
|
|
1200
|
+
|
|
1201
|
+
1. **Use Chalk for Colors**
|
|
1202
|
+
```javascript
|
|
1203
|
+
console.log(chalk.green('✓ Success'));
|
|
1204
|
+
console.error(chalk.red('✗ Error'));
|
|
1205
|
+
console.log(chalk.yellow('⚠ Warning'));
|
|
1206
|
+
console.log(chalk.gray('Additional info'));
|
|
1207
|
+
```
|
|
1208
|
+
|
|
1209
|
+
2. **Require Confirmation for Destructive Actions**
|
|
1210
|
+
```javascript
|
|
1211
|
+
if (!opts.confirm) {
|
|
1212
|
+
console.log(chalk.yellow('Add --confirm to proceed'));
|
|
1213
|
+
process.exit(0);
|
|
1214
|
+
}
|
|
1215
|
+
```
|
|
1216
|
+
|
|
1217
|
+
3. **Show Progress for Long Operations**
|
|
1218
|
+
```javascript
|
|
1219
|
+
console.log('Uploading video...');
|
|
1220
|
+
for (let i = 0; i < parts.length; i++) {
|
|
1221
|
+
console.log(` Part ${i+1}/${parts.length} uploaded`);
|
|
1222
|
+
}
|
|
1223
|
+
```
|
|
1224
|
+
|
|
1225
|
+
4. **Provide Examples in Help**
|
|
1226
|
+
```javascript
|
|
1227
|
+
.command('create')
|
|
1228
|
+
.description('Create a post')
|
|
1229
|
+
.example('agentdev [provider] post create --text "Hello"')
|
|
1230
|
+
```
|
|
1231
|
+
|
|
1232
|
+
### Documentation Best Practices
|
|
1233
|
+
|
|
1234
|
+
1. **Include Examples**
|
|
1235
|
+
- Show common use cases
|
|
1236
|
+
- Provide copy-paste commands
|
|
1237
|
+
- Explain expected output
|
|
1238
|
+
|
|
1239
|
+
2. **Document Errors**
|
|
1240
|
+
- List common errors
|
|
1241
|
+
- Explain what they mean
|
|
1242
|
+
- Provide solutions
|
|
1243
|
+
|
|
1244
|
+
3. **Keep Updated**
|
|
1245
|
+
- Update when adding features
|
|
1246
|
+
- Document breaking changes
|
|
1247
|
+
- Maintain changelog
|
|
1248
|
+
|
|
1249
|
+
---
|
|
1250
|
+
|
|
1251
|
+
## Quick Reference Checklist
|
|
1252
|
+
|
|
1253
|
+
Use this checklist for every new API integration:
|
|
1254
|
+
|
|
1255
|
+
### Pre-Implementation
|
|
1256
|
+
- [ ] Research API documentation
|
|
1257
|
+
- [ ] Identify OAuth scopes needed
|
|
1258
|
+
- [ ] List core endpoints
|
|
1259
|
+
- [ ] Document rate limits
|
|
1260
|
+
- [ ] Create implementation plan
|
|
1261
|
+
|
|
1262
|
+
### OAuth Setup
|
|
1263
|
+
- [ ] Register OAuth application
|
|
1264
|
+
- [ ] Get client ID and secret
|
|
1265
|
+
- [ ] Create `/lib/[provider].js`
|
|
1266
|
+
- [ ] Implement authorization URL
|
|
1267
|
+
- [ ] Implement token exchange
|
|
1268
|
+
- [ ] Implement token refresh
|
|
1269
|
+
- [ ] Test OAuth flow
|
|
1270
|
+
|
|
1271
|
+
### API Client
|
|
1272
|
+
- [ ] Create `/src/[api]/api/core.js`
|
|
1273
|
+
- [ ] Create feature modules (posts, users, etc.)
|
|
1274
|
+
- [ ] Create `/src/[api]/api/index.js`
|
|
1275
|
+
- [ ] Create `/src/[api]/api.js` wrapper
|
|
1276
|
+
- [ ] Write unit tests
|
|
1277
|
+
- [ ] Test API calls
|
|
1278
|
+
|
|
1279
|
+
### CLI Commands
|
|
1280
|
+
- [ ] Create `/src/cli/[api]/helpers.js`
|
|
1281
|
+
- [ ] Create feature command modules
|
|
1282
|
+
- [ ] Create `/src/cli/[api]/index.js`
|
|
1283
|
+
- [ ] Create `/src/cli/[api].js` wrapper
|
|
1284
|
+
- [ ] Register with main CLI
|
|
1285
|
+
- [ ] Test all commands
|
|
1286
|
+
|
|
1287
|
+
### Documentation
|
|
1288
|
+
- [ ] Create skill file `/skills/agentdev-[api].md`
|
|
1289
|
+
- [ ] Document all commands
|
|
1290
|
+
- [ ] Add examples
|
|
1291
|
+
- [ ] Document errors
|
|
1292
|
+
- [ ] Add to main README
|
|
1293
|
+
|
|
1294
|
+
### Testing & Deployment
|
|
1295
|
+
- [ ] Manual testing
|
|
1296
|
+
- [ ] Integration testing
|
|
1297
|
+
- [ ] Build and verify
|
|
1298
|
+
- [ ] Create migration guide
|
|
1299
|
+
- [ ] Deploy to production
|
|
1300
|
+
- [ ] Monitor for issues
|
|
1301
|
+
|
|
1302
|
+
---
|
|
1303
|
+
|
|
1304
|
+
## Example Integrations
|
|
1305
|
+
|
|
1306
|
+
This pattern has been successfully used for:
|
|
1307
|
+
|
|
1308
|
+
1. **LinkedIn** (Implemented)
|
|
1309
|
+
- OAuth 2.0
|
|
1310
|
+
- Posts, analytics, connections
|
|
1311
|
+
- Organization pages
|
|
1312
|
+
- Video uploads
|
|
1313
|
+
|
|
1314
|
+
2. **Twitter/X** (Future)
|
|
1315
|
+
- OAuth 2.0
|
|
1316
|
+
- Tweets, timelines, DMs
|
|
1317
|
+
- Media uploads
|
|
1318
|
+
- Analytics
|
|
1319
|
+
|
|
1320
|
+
3. **GitHub** (Future)
|
|
1321
|
+
- OAuth 2.0
|
|
1322
|
+
- Repos, issues, PRs
|
|
1323
|
+
- Actions, releases
|
|
1324
|
+
- Webhooks
|
|
1325
|
+
|
|
1326
|
+
4. **Slack** (Future)
|
|
1327
|
+
- OAuth 2.0
|
|
1328
|
+
- Messages, channels
|
|
1329
|
+
- File uploads
|
|
1330
|
+
- Slash commands
|
|
1331
|
+
|
|
1332
|
+
---
|
|
1333
|
+
|
|
1334
|
+
## Troubleshooting
|
|
1335
|
+
|
|
1336
|
+
### OAuth Issues
|
|
1337
|
+
|
|
1338
|
+
**Problem:** "Invalid redirect URI"
|
|
1339
|
+
**Solution:** Ensure redirect URI matches exactly in OAuth app settings
|
|
1340
|
+
|
|
1341
|
+
**Problem:** "Invalid scopes"
|
|
1342
|
+
**Solution:** Check scopes are supported and spelled correctly
|
|
1343
|
+
|
|
1344
|
+
**Problem:** "Token expired immediately"
|
|
1345
|
+
**Solution:** Check token expiration handling and refresh logic
|
|
1346
|
+
|
|
1347
|
+
### API Issues
|
|
1348
|
+
|
|
1349
|
+
**Problem:** 401 Unauthorized
|
|
1350
|
+
**Solution:** Verify token is valid and not expired
|
|
1351
|
+
|
|
1352
|
+
**Problem:** 403 Forbidden
|
|
1353
|
+
**Solution:** Check OAuth scopes include required permissions
|
|
1354
|
+
|
|
1355
|
+
**Problem:** 429 Rate Limited
|
|
1356
|
+
**Solution:** Implement exponential backoff and respect rate limits
|
|
1357
|
+
|
|
1358
|
+
### CLI Issues
|
|
1359
|
+
|
|
1360
|
+
**Problem:** Command not found
|
|
1361
|
+
**Solution:** Rebuild CLI with `npm run build`
|
|
1362
|
+
|
|
1363
|
+
**Problem:** "Not connected" error
|
|
1364
|
+
**Solution:** Direct user to connect account at /profile
|
|
1365
|
+
|
|
1366
|
+
**Problem:** Module import errors
|
|
1367
|
+
**Solution:** Check file paths and ensure proper ES module syntax
|
|
1368
|
+
|
|
1369
|
+
---
|
|
1370
|
+
|
|
1371
|
+
## Conclusion
|
|
1372
|
+
|
|
1373
|
+
This guide provides a complete, battle-tested process for integrating any API into agentdev. Follow these steps and you'll have a production-ready integration in 2-4 weeks.
|
|
1374
|
+
|
|
1375
|
+
**Key Takeaways:**
|
|
1376
|
+
1. ✅ Start with research and planning
|
|
1377
|
+
2. ✅ Use modular architecture
|
|
1378
|
+
3. ✅ Test thoroughly before deployment
|
|
1379
|
+
4. ✅ Document everything
|
|
1380
|
+
5. ✅ Monitor and iterate
|
|
1381
|
+
|
|
1382
|
+
For questions or help with integration, refer to this guide or ask the team!
|