viruagent-cli 0.3.7 → 0.4.1
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/README.ko.md +41 -25
- package/README.md +40 -24
- package/bin/index.js +91 -1
- package/package.json +3 -2
- package/skills/viruagent-insta.md +163 -0
- package/skills/viruagent-naver.md +122 -0
- package/skills/viruagent-tistory.md +117 -0
- package/skills/viruagent.md +37 -246
- package/src/providers/insta/apiClient.js +630 -0
- package/src/providers/insta/auth.js +135 -0
- package/src/providers/insta/index.js +293 -0
- package/src/providers/insta/session.js +118 -0
- package/src/providers/insta/smartComment.js +67 -0
- package/src/providers/insta/utils.js +34 -0
- package/src/runner.js +82 -9
- package/src/services/providerManager.js +5 -2
package/src/runner.js
CHANGED
|
@@ -46,19 +46,27 @@ const runCommand = async (command, opts = {}) => {
|
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
if (command === 'install-skill') {
|
|
49
|
-
const
|
|
50
|
-
|
|
51
|
-
throw createError('FILE_NOT_FOUND', 'Skill file not found in package');
|
|
52
|
-
}
|
|
49
|
+
const skillsDir = path.resolve(__dirname, '..', 'skills');
|
|
50
|
+
const skillFiles = ['viruagent.md', 'viruagent-tistory.md', 'viruagent-naver.md', 'viruagent-insta.md'];
|
|
53
51
|
|
|
54
|
-
// Detect target: Claude Code (~/.claude/commands/) or custom
|
|
55
52
|
const targetDir = opts.target
|
|
56
53
|
|| path.join(os.homedir(), '.claude', 'commands');
|
|
57
54
|
fs.mkdirSync(targetDir, { recursive: true });
|
|
58
55
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
56
|
+
const installed = [];
|
|
57
|
+
for (const file of skillFiles) {
|
|
58
|
+
const src = path.join(skillsDir, file);
|
|
59
|
+
if (!fs.existsSync(src)) continue;
|
|
60
|
+
const dest = path.join(targetDir, file);
|
|
61
|
+
fs.copyFileSync(src, dest);
|
|
62
|
+
installed.push(dest);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (installed.length === 0) {
|
|
66
|
+
throw createError('FILE_NOT_FOUND', 'Skill files not found in package');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
return { installed: true, paths: installed, count: installed.length };
|
|
62
70
|
}
|
|
63
71
|
|
|
64
72
|
const manager = createProviderManager();
|
|
@@ -149,7 +157,10 @@ const runCommand = async (command, opts = {}) => {
|
|
|
149
157
|
|
|
150
158
|
case 'list-posts':
|
|
151
159
|
return withProvider(() =>
|
|
152
|
-
provider.listPosts({
|
|
160
|
+
provider.listPosts({
|
|
161
|
+
username: opts.username || undefined,
|
|
162
|
+
limit: parseIntOrNull(opts.limit) || 20,
|
|
163
|
+
})
|
|
153
164
|
)();
|
|
154
165
|
|
|
155
166
|
case 'read-post': {
|
|
@@ -167,6 +178,68 @@ const runCommand = async (command, opts = {}) => {
|
|
|
167
178
|
case 'logout':
|
|
168
179
|
return withProvider(() => provider.logout())();
|
|
169
180
|
|
|
181
|
+
// ── Instagram 전용 (다른 프로바이더에도 메서드가 있으면 동작) ──
|
|
182
|
+
|
|
183
|
+
case 'get-profile':
|
|
184
|
+
if (!opts.username) {
|
|
185
|
+
throw createError('MISSING_PARAM', 'get-profile requires --username');
|
|
186
|
+
}
|
|
187
|
+
return withProvider(() => provider.getProfile({ username: opts.username }))();
|
|
188
|
+
|
|
189
|
+
case 'get-feed':
|
|
190
|
+
return withProvider(() => provider.getFeed())();
|
|
191
|
+
|
|
192
|
+
case 'like':
|
|
193
|
+
if (!opts.postId) {
|
|
194
|
+
throw createError('MISSING_PARAM', 'like requires --post-id');
|
|
195
|
+
}
|
|
196
|
+
return withProvider(() => provider.like({ postId: opts.postId }))();
|
|
197
|
+
|
|
198
|
+
case 'unlike':
|
|
199
|
+
if (!opts.postId) {
|
|
200
|
+
throw createError('MISSING_PARAM', 'unlike requires --post-id');
|
|
201
|
+
}
|
|
202
|
+
return withProvider(() => provider.unlike({ postId: opts.postId }))();
|
|
203
|
+
|
|
204
|
+
case 'comment':
|
|
205
|
+
if (!opts.postId || !opts.text) {
|
|
206
|
+
throw createError('MISSING_PARAM', 'comment requires --post-id and --text');
|
|
207
|
+
}
|
|
208
|
+
return withProvider(() => provider.comment({ postId: opts.postId, text: opts.text }))();
|
|
209
|
+
|
|
210
|
+
case 'follow':
|
|
211
|
+
if (!opts.username) {
|
|
212
|
+
throw createError('MISSING_PARAM', 'follow requires --username');
|
|
213
|
+
}
|
|
214
|
+
return withProvider(() => provider.follow({ username: opts.username }))();
|
|
215
|
+
|
|
216
|
+
case 'unfollow':
|
|
217
|
+
if (!opts.username) {
|
|
218
|
+
throw createError('MISSING_PARAM', 'unfollow requires --username');
|
|
219
|
+
}
|
|
220
|
+
return withProvider(() => provider.unfollow({ username: opts.username }))();
|
|
221
|
+
|
|
222
|
+
case 'like-comment':
|
|
223
|
+
if (!opts.commentId) {
|
|
224
|
+
throw createError('MISSING_PARAM', 'like-comment requires --comment-id');
|
|
225
|
+
}
|
|
226
|
+
return withProvider(() => provider.likeComment({ commentId: opts.commentId }))();
|
|
227
|
+
|
|
228
|
+
case 'unlike-comment':
|
|
229
|
+
if (!opts.commentId) {
|
|
230
|
+
throw createError('MISSING_PARAM', 'unlike-comment requires --comment-id');
|
|
231
|
+
}
|
|
232
|
+
return withProvider(() => provider.unlikeComment({ commentId: opts.commentId }))();
|
|
233
|
+
|
|
234
|
+
case 'analyze-post':
|
|
235
|
+
if (!opts.postId) {
|
|
236
|
+
throw createError('MISSING_PARAM', 'analyze-post requires --post-id');
|
|
237
|
+
}
|
|
238
|
+
return withProvider(() => provider.analyzePost({ postId: opts.postId }))();
|
|
239
|
+
|
|
240
|
+
case 'rate-limit-status':
|
|
241
|
+
return withProvider(() => Promise.resolve(provider.rateLimitStatus()))();
|
|
242
|
+
|
|
170
243
|
default:
|
|
171
244
|
throw createError('UNKNOWN_COMMAND', `Unknown command: ${command}`, 'viruagent-cli --spec');
|
|
172
245
|
}
|
|
@@ -2,13 +2,15 @@ const path = require('path');
|
|
|
2
2
|
const { getSessionPath } = require('../storage/sessionStore');
|
|
3
3
|
const createTistoryProvider = require('../providers/tistory');
|
|
4
4
|
const createNaverProvider = require('../providers/naver');
|
|
5
|
+
const createInstaProvider = require('../providers/insta');
|
|
5
6
|
|
|
6
7
|
const providerFactory = {
|
|
7
8
|
tistory: createTistoryProvider,
|
|
8
9
|
naver: createNaverProvider,
|
|
10
|
+
insta: createInstaProvider,
|
|
9
11
|
};
|
|
10
12
|
|
|
11
|
-
const providers = ['tistory', 'naver'];
|
|
13
|
+
const providers = ['tistory', 'naver', 'insta'];
|
|
12
14
|
|
|
13
15
|
const createProviderManager = () => {
|
|
14
16
|
const cache = new Map();
|
|
@@ -32,9 +34,10 @@ const createProviderManager = () => {
|
|
|
32
34
|
return cache.get(normalized);
|
|
33
35
|
};
|
|
34
36
|
|
|
37
|
+
const providerNames = { tistory: 'Tistory', naver: 'Naver Blog', insta: 'Instagram' };
|
|
35
38
|
const getAvailableProviders = () => providers.map((provider) => ({
|
|
36
39
|
id: provider,
|
|
37
|
-
name: provider
|
|
40
|
+
name: providerNames[provider] || provider,
|
|
38
41
|
}));
|
|
39
42
|
|
|
40
43
|
return { getProvider, getAvailableProviders };
|