@aisa-one/cli 0.0.1 → 0.1.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.md +203 -0
- package/dist/api.d.ts +11 -0
- package/dist/api.js +61 -0
- package/dist/commands/account.d.ts +5 -0
- package/dist/commands/account.js +47 -0
- package/dist/commands/api.d.ts +10 -0
- package/dist/commands/api.js +116 -0
- package/dist/commands/auth.d.ts +5 -0
- package/dist/commands/auth.js +29 -0
- package/dist/commands/chat.d.ts +8 -0
- package/dist/commands/chat.js +78 -0
- package/dist/commands/configCmd.d.ts +4 -0
- package/dist/commands/configCmd.js +36 -0
- package/dist/commands/finance.d.ts +13 -0
- package/dist/commands/finance.js +85 -0
- package/dist/commands/mcp.d.ts +4 -0
- package/dist/commands/mcp.js +67 -0
- package/dist/commands/models.d.ts +4 -0
- package/dist/commands/models.js +65 -0
- package/dist/commands/run.d.ts +7 -0
- package/dist/commands/run.js +70 -0
- package/dist/commands/search.d.ts +9 -0
- package/dist/commands/search.js +43 -0
- package/dist/commands/skills.d.ts +22 -0
- package/dist/commands/skills.js +555 -0
- package/dist/commands/twitter.d.ts +14 -0
- package/dist/commands/twitter.js +85 -0
- package/dist/commands/video.d.ts +9 -0
- package/dist/commands/video.js +73 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +56 -0
- package/dist/constants.d.ts +14 -0
- package/dist/constants.js +43 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +291 -0
- package/dist/types.d.ts +100 -0
- package/dist/types.js +1 -0
- package/dist/utils/display.d.ts +8 -0
- package/dist/utils/display.js +33 -0
- package/dist/utils/file.d.ts +12 -0
- package/dist/utils/file.js +70 -0
- package/dist/utils/streaming.d.ts +5 -0
- package/dist/utils/streaming.js +37 -0
- package/package.json +53 -5
- package/index.js +0 -3
|
@@ -0,0 +1,555 @@
|
|
|
1
|
+
import ora from "ora";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join, resolve } from "node:path";
|
|
5
|
+
import { requireApiKey } from "../config.js";
|
|
6
|
+
import { apiRequest } from "../api.js";
|
|
7
|
+
import { error, success, badge, hint, truncate } from "../utils/display.js";
|
|
8
|
+
import { expandHome, ensureDir, writeSkillFiles, readSkillDir, removeDir, detectAgents } from "../utils/file.js";
|
|
9
|
+
import { AGENT_DIRS } from "../constants.js";
|
|
10
|
+
// --- Skill Templates ---
|
|
11
|
+
const TEMPLATES = {
|
|
12
|
+
default: `---
|
|
13
|
+
name: my-skill
|
|
14
|
+
description: "Describe what this skill does."
|
|
15
|
+
category: general
|
|
16
|
+
tags: []
|
|
17
|
+
metadata:
|
|
18
|
+
aisa:
|
|
19
|
+
apis: []
|
|
20
|
+
requires:
|
|
21
|
+
auth: true
|
|
22
|
+
env: [AISA_API_KEY]
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# My Skill
|
|
26
|
+
|
|
27
|
+
Describe how an AI agent should use this skill.
|
|
28
|
+
|
|
29
|
+
## Authentication
|
|
30
|
+
|
|
31
|
+
\`\`\`bash
|
|
32
|
+
export AISA_API_KEY=sk-your-key
|
|
33
|
+
\`\`\`
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
\`\`\`bash
|
|
38
|
+
aisa run <slug> <path> -q "param=value"
|
|
39
|
+
\`\`\`
|
|
40
|
+
`,
|
|
41
|
+
llm: `---
|
|
42
|
+
name: llm-assistant
|
|
43
|
+
description: "Use AISA's unified LLM gateway to chat with 70+ AI models."
|
|
44
|
+
category: llm
|
|
45
|
+
tags: [llm, chat, openai, claude, gemini]
|
|
46
|
+
metadata:
|
|
47
|
+
aisa:
|
|
48
|
+
apis: [chat/completions, models]
|
|
49
|
+
requires:
|
|
50
|
+
auth: true
|
|
51
|
+
env: [AISA_API_KEY]
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# LLM Assistant Skill
|
|
55
|
+
|
|
56
|
+
Use the AISA unified gateway to access 70+ language models through a single API.
|
|
57
|
+
|
|
58
|
+
## Authentication
|
|
59
|
+
|
|
60
|
+
\`\`\`bash
|
|
61
|
+
export AISA_API_KEY=sk-your-key
|
|
62
|
+
\`\`\`
|
|
63
|
+
|
|
64
|
+
## Chat Completion
|
|
65
|
+
|
|
66
|
+
\`\`\`bash
|
|
67
|
+
aisa chat "Your question here" --model gpt-4.1
|
|
68
|
+
\`\`\`
|
|
69
|
+
|
|
70
|
+
## Streaming
|
|
71
|
+
|
|
72
|
+
\`\`\`bash
|
|
73
|
+
aisa chat "Explain quantum computing" --model claude-opus-4-6 --stream
|
|
74
|
+
\`\`\`
|
|
75
|
+
|
|
76
|
+
## List Models
|
|
77
|
+
|
|
78
|
+
\`\`\`bash
|
|
79
|
+
aisa models
|
|
80
|
+
aisa models --provider anthropic
|
|
81
|
+
\`\`\`
|
|
82
|
+
|
|
83
|
+
## REST API (OpenAI-compatible)
|
|
84
|
+
|
|
85
|
+
\`\`\`bash
|
|
86
|
+
curl -X POST https://api.aisa.one/v1/chat/completions \\
|
|
87
|
+
-H "Authorization: Bearer $AISA_API_KEY" \\
|
|
88
|
+
-H "Content-Type: application/json" \\
|
|
89
|
+
-d '{"model": "gpt-4.1", "messages": [{"role": "user", "content": "Hello"}]}'
|
|
90
|
+
\`\`\`
|
|
91
|
+
`,
|
|
92
|
+
search: `---
|
|
93
|
+
name: web-search
|
|
94
|
+
description: "Search the web, YouTube, and academic papers via AISA APIs."
|
|
95
|
+
category: search
|
|
96
|
+
tags: [search, web, youtube, scholar, tavily]
|
|
97
|
+
metadata:
|
|
98
|
+
aisa:
|
|
99
|
+
apis: [search/smart, search/full, youtube/search, scholar/search, tavily/search]
|
|
100
|
+
requires:
|
|
101
|
+
auth: true
|
|
102
|
+
env: [AISA_API_KEY]
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
# Web Search Skill
|
|
106
|
+
|
|
107
|
+
Search the web, YouTube, and academic papers through AISA's unified search APIs.
|
|
108
|
+
|
|
109
|
+
## Authentication
|
|
110
|
+
|
|
111
|
+
\`\`\`bash
|
|
112
|
+
export AISA_API_KEY=sk-your-key
|
|
113
|
+
\`\`\`
|
|
114
|
+
|
|
115
|
+
## Smart Search
|
|
116
|
+
|
|
117
|
+
\`\`\`bash
|
|
118
|
+
aisa web-search "latest AI research" --type smart
|
|
119
|
+
\`\`\`
|
|
120
|
+
|
|
121
|
+
## YouTube Search
|
|
122
|
+
|
|
123
|
+
\`\`\`bash
|
|
124
|
+
aisa web-search "machine learning tutorial" --type youtube
|
|
125
|
+
\`\`\`
|
|
126
|
+
|
|
127
|
+
## Scholar Search
|
|
128
|
+
|
|
129
|
+
\`\`\`bash
|
|
130
|
+
aisa scholar "transformer architecture"
|
|
131
|
+
\`\`\`
|
|
132
|
+
|
|
133
|
+
## Tavily Deep Search
|
|
134
|
+
|
|
135
|
+
\`\`\`bash
|
|
136
|
+
aisa run tavily /search -d '{"query": "NVIDIA earnings 2025", "search_depth": "advanced"}'
|
|
137
|
+
\`\`\`
|
|
138
|
+
|
|
139
|
+
## Tavily Extract (webpage content)
|
|
140
|
+
|
|
141
|
+
\`\`\`bash
|
|
142
|
+
aisa run tavily /extract -d '{"urls": ["https://example.com"]}'
|
|
143
|
+
\`\`\`
|
|
144
|
+
`,
|
|
145
|
+
finance: `---
|
|
146
|
+
name: finance-analyst
|
|
147
|
+
description: "Access stock prices, earnings, SEC filings, and financial data via AISA."
|
|
148
|
+
category: finance
|
|
149
|
+
tags: [stocks, earnings, sec-filings, crypto, financial-analysis]
|
|
150
|
+
metadata:
|
|
151
|
+
aisa:
|
|
152
|
+
apis: [stock/price, analyst-estimates, financial-statements, filings, insider-trades, crypto/price]
|
|
153
|
+
requires:
|
|
154
|
+
auth: true
|
|
155
|
+
env: [AISA_API_KEY]
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
# Finance Analyst Skill
|
|
159
|
+
|
|
160
|
+
Access real-time and historical financial data through AISA's finance APIs.
|
|
161
|
+
|
|
162
|
+
## Authentication
|
|
163
|
+
|
|
164
|
+
\`\`\`bash
|
|
165
|
+
export AISA_API_KEY=sk-your-key
|
|
166
|
+
\`\`\`
|
|
167
|
+
|
|
168
|
+
## Stock Prices
|
|
169
|
+
|
|
170
|
+
\`\`\`bash
|
|
171
|
+
aisa stock AAPL
|
|
172
|
+
aisa stock MSFT --field earnings
|
|
173
|
+
aisa stock TSLA --field filings
|
|
174
|
+
\`\`\`
|
|
175
|
+
|
|
176
|
+
## Crypto Prices
|
|
177
|
+
|
|
178
|
+
\`\`\`bash
|
|
179
|
+
aisa crypto BTC
|
|
180
|
+
aisa crypto ETH --period 30d
|
|
181
|
+
\`\`\`
|
|
182
|
+
|
|
183
|
+
## Stock Screener
|
|
184
|
+
|
|
185
|
+
\`\`\`bash
|
|
186
|
+
aisa screener --sector Technology --limit 20
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
## Financial Statements
|
|
190
|
+
|
|
191
|
+
\`\`\`bash
|
|
192
|
+
aisa run financial-statements -q "symbol=AAPL&period=annual"
|
|
193
|
+
\`\`\`
|
|
194
|
+
|
|
195
|
+
## SEC Filings
|
|
196
|
+
|
|
197
|
+
\`\`\`bash
|
|
198
|
+
aisa run filings -q "symbol=TSLA&type=10-K"
|
|
199
|
+
\`\`\`
|
|
200
|
+
|
|
201
|
+
## Insider Trades
|
|
202
|
+
|
|
203
|
+
\`\`\`bash
|
|
204
|
+
aisa stock NVDA --field insider
|
|
205
|
+
\`\`\`
|
|
206
|
+
`,
|
|
207
|
+
twitter: `---
|
|
208
|
+
name: twitter-manager
|
|
209
|
+
description: "Post tweets, search Twitter, get user profiles and trends via AISA."
|
|
210
|
+
category: twitter
|
|
211
|
+
tags: [twitter, tweets, social-media, trends]
|
|
212
|
+
metadata:
|
|
213
|
+
aisa:
|
|
214
|
+
apis: [twitter/create-tweet-v2, twitter/tweet/advanced-search, twitter/user/info, twitter/trends]
|
|
215
|
+
requires:
|
|
216
|
+
auth: true
|
|
217
|
+
env: [AISA_API_KEY]
|
|
218
|
+
---
|
|
219
|
+
|
|
220
|
+
# Twitter Manager Skill
|
|
221
|
+
|
|
222
|
+
Interact with Twitter/X through AISA's Twitter APIs.
|
|
223
|
+
|
|
224
|
+
## Authentication
|
|
225
|
+
|
|
226
|
+
\`\`\`bash
|
|
227
|
+
export AISA_API_KEY=sk-your-key
|
|
228
|
+
\`\`\`
|
|
229
|
+
|
|
230
|
+
## Post a Tweet
|
|
231
|
+
|
|
232
|
+
\`\`\`bash
|
|
233
|
+
aisa tweet "Hello from AISA CLI!"
|
|
234
|
+
\`\`\`
|
|
235
|
+
|
|
236
|
+
## Search Tweets
|
|
237
|
+
|
|
238
|
+
\`\`\`bash
|
|
239
|
+
aisa twitter search "AI agents" --limit 20
|
|
240
|
+
\`\`\`
|
|
241
|
+
|
|
242
|
+
## Get User Profile
|
|
243
|
+
|
|
244
|
+
\`\`\`bash
|
|
245
|
+
aisa twitter user elonmusk
|
|
246
|
+
\`\`\`
|
|
247
|
+
|
|
248
|
+
## Trending Topics
|
|
249
|
+
|
|
250
|
+
\`\`\`bash
|
|
251
|
+
aisa twitter trends
|
|
252
|
+
\`\`\`
|
|
253
|
+
|
|
254
|
+
## Advanced: Get Tweet Replies
|
|
255
|
+
|
|
256
|
+
\`\`\`bash
|
|
257
|
+
aisa run twitter/tweet/replies -q "id=1234567890"
|
|
258
|
+
\`\`\`
|
|
259
|
+
|
|
260
|
+
## Advanced: Send DM
|
|
261
|
+
|
|
262
|
+
\`\`\`bash
|
|
263
|
+
aisa run twitter/send-dm-to-user -d '{"userId": "123", "text": "Hello!"}'
|
|
264
|
+
\`\`\`
|
|
265
|
+
`,
|
|
266
|
+
video: `---
|
|
267
|
+
name: video-generator
|
|
268
|
+
description: "Generate videos from text prompts using AISA's video synthesis API."
|
|
269
|
+
category: video
|
|
270
|
+
tags: [video, generation, aigc, synthesis]
|
|
271
|
+
metadata:
|
|
272
|
+
aisa:
|
|
273
|
+
apis: [services/aigc/video-generation/video-synthesis, services/aigc/tasks]
|
|
274
|
+
requires:
|
|
275
|
+
auth: true
|
|
276
|
+
env: [AISA_API_KEY]
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
# Video Generator Skill
|
|
280
|
+
|
|
281
|
+
Generate videos from text prompts using AISA's AI video generation APIs.
|
|
282
|
+
|
|
283
|
+
## Authentication
|
|
284
|
+
|
|
285
|
+
\`\`\`bash
|
|
286
|
+
export AISA_API_KEY=sk-your-key
|
|
287
|
+
\`\`\`
|
|
288
|
+
|
|
289
|
+
## Create Video
|
|
290
|
+
|
|
291
|
+
\`\`\`bash
|
|
292
|
+
aisa video create "A cat playing piano in a jazz bar"
|
|
293
|
+
\`\`\`
|
|
294
|
+
|
|
295
|
+
## Create and Wait for Result
|
|
296
|
+
|
|
297
|
+
\`\`\`bash
|
|
298
|
+
aisa video create "Sunset over mountains timelapse" --wait
|
|
299
|
+
\`\`\`
|
|
300
|
+
|
|
301
|
+
## Check Task Status
|
|
302
|
+
|
|
303
|
+
\`\`\`bash
|
|
304
|
+
aisa video status <task-id>
|
|
305
|
+
\`\`\`
|
|
306
|
+
`,
|
|
307
|
+
};
|
|
308
|
+
// --- Commands ---
|
|
309
|
+
export async function skillsListAction(options) {
|
|
310
|
+
const key = requireApiKey();
|
|
311
|
+
const spinner = ora("Fetching skills...").start();
|
|
312
|
+
const query = {};
|
|
313
|
+
if (options.category)
|
|
314
|
+
query.category = options.category;
|
|
315
|
+
if (options.limit)
|
|
316
|
+
query.limit = options.limit;
|
|
317
|
+
const res = await apiRequest(key, "cli/skills", { query });
|
|
318
|
+
if (!res.success || !res.data) {
|
|
319
|
+
spinner.fail("Failed to fetch skills");
|
|
320
|
+
error(res.error || "Unknown error");
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
spinner.stop();
|
|
324
|
+
const { skills } = res.data;
|
|
325
|
+
if (skills.length === 0) {
|
|
326
|
+
console.log(" No skills found.");
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
for (const s of skills) {
|
|
330
|
+
const verified = s.verified ? chalk.green(" ✓") : "";
|
|
331
|
+
console.log(`\n ${chalk.cyan.bold(s.name)}${verified} ${chalk.gray(s.slug)} ${badge(s.category)}`);
|
|
332
|
+
console.log(` ${chalk.gray(truncate(s.description, 60))}`);
|
|
333
|
+
console.log(` ${chalk.gray(`${s.installs} installs`)}`);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
export async function skillsSearchAction(query, options) {
|
|
337
|
+
const key = requireApiKey();
|
|
338
|
+
const spinner = ora(`Searching skills: "${query}"...`).start();
|
|
339
|
+
const res = await apiRequest(key, "cli/skills/search", {
|
|
340
|
+
method: "POST",
|
|
341
|
+
body: { query, limit: parseInt(options.limit || "10") },
|
|
342
|
+
});
|
|
343
|
+
if (!res.success || !res.data) {
|
|
344
|
+
spinner.fail("Search failed");
|
|
345
|
+
error(res.error || "Unknown error");
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
spinner.stop();
|
|
349
|
+
const { skills } = res.data;
|
|
350
|
+
if (skills.length === 0) {
|
|
351
|
+
console.log(` No skills found for "${query}".`);
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
for (const s of skills) {
|
|
355
|
+
const verified = s.verified ? chalk.green(" ✓") : "";
|
|
356
|
+
console.log(`\n ${chalk.cyan.bold(s.name)}${verified} ${chalk.gray(s.slug)} ${badge(s.category)}`);
|
|
357
|
+
console.log(` ${chalk.gray(s.description)}`);
|
|
358
|
+
}
|
|
359
|
+
console.log(chalk.gray("\n Run 'aisa skills add <owner/name>' to install"));
|
|
360
|
+
}
|
|
361
|
+
export async function skillsShowAction(slug) {
|
|
362
|
+
const key = requireApiKey();
|
|
363
|
+
const spinner = ora(`Loading ${slug}...`).start();
|
|
364
|
+
const res = await apiRequest(key, `cli/skills/${slug}`);
|
|
365
|
+
if (!res.success || !res.data) {
|
|
366
|
+
spinner.fail("Skill not found");
|
|
367
|
+
error(res.error || "Unknown error");
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
spinner.stop();
|
|
371
|
+
const s = res.data;
|
|
372
|
+
const verified = s.verified ? chalk.green(" ✓ verified") : "";
|
|
373
|
+
console.log(`\n ${chalk.cyan.bold(s.name)}${verified}`);
|
|
374
|
+
console.log(` ${s.description}`);
|
|
375
|
+
console.log(` Category: ${badge(s.category)}`);
|
|
376
|
+
console.log(` Tags: ${s.tags.join(", ")}`);
|
|
377
|
+
console.log(` Installs: ${s.installs}`);
|
|
378
|
+
console.log(` Files: ${s.files.map((f) => f.path).join(", ")}`);
|
|
379
|
+
console.log(chalk.gray(`\n Install: aisa skills add ${s.slug}`));
|
|
380
|
+
}
|
|
381
|
+
export async function skillsAddAction(slug, options) {
|
|
382
|
+
const key = requireApiKey();
|
|
383
|
+
const spinner = ora(`Fetching skill '${slug}'...`).start();
|
|
384
|
+
const res = await apiRequest(key, `cli/skills/${slug}`);
|
|
385
|
+
if (!res.success || !res.data) {
|
|
386
|
+
spinner.fail("Failed to fetch skill");
|
|
387
|
+
error(res.error || "Unknown error");
|
|
388
|
+
return;
|
|
389
|
+
}
|
|
390
|
+
spinner.stop();
|
|
391
|
+
const skill = res.data;
|
|
392
|
+
// Determine targets
|
|
393
|
+
let targets;
|
|
394
|
+
if (options.agent) {
|
|
395
|
+
if (options.agent === "all") {
|
|
396
|
+
targets = Object.keys(AGENT_DIRS);
|
|
397
|
+
}
|
|
398
|
+
else {
|
|
399
|
+
if (!AGENT_DIRS[options.agent]) {
|
|
400
|
+
error(`Unknown agent: ${options.agent}. Valid: ${Object.keys(AGENT_DIRS).join(", ")}, all`);
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
targets = [options.agent];
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
targets = detectAgents(AGENT_DIRS);
|
|
408
|
+
if (targets.length === 0) {
|
|
409
|
+
targets = Object.keys(AGENT_DIRS);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
let installed = 0;
|
|
413
|
+
for (const agent of targets) {
|
|
414
|
+
const dir = expandHome(join(AGENT_DIRS[agent], slug));
|
|
415
|
+
ensureDir(dir);
|
|
416
|
+
writeSkillFiles(dir, skill.files);
|
|
417
|
+
console.log(` ${chalk.green("✓")} ${AGENT_DIRS[agent]} (${agent})`);
|
|
418
|
+
installed++;
|
|
419
|
+
}
|
|
420
|
+
success(`Skill '${skill.name}' installed to ${installed} agent(s)`);
|
|
421
|
+
}
|
|
422
|
+
export async function skillsRemoveAction(slug, options) {
|
|
423
|
+
let targets;
|
|
424
|
+
if (options.agent && options.agent !== "all") {
|
|
425
|
+
targets = [options.agent];
|
|
426
|
+
}
|
|
427
|
+
else {
|
|
428
|
+
targets = Object.keys(AGENT_DIRS);
|
|
429
|
+
}
|
|
430
|
+
let removed = 0;
|
|
431
|
+
for (const agent of targets) {
|
|
432
|
+
const dir = expandHome(join(AGENT_DIRS[agent], slug));
|
|
433
|
+
if (existsSync(dir)) {
|
|
434
|
+
removeDir(dir);
|
|
435
|
+
console.log(` ${chalk.green("✓")} Removed from ${AGENT_DIRS[agent]}`);
|
|
436
|
+
removed++;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
if (removed === 0) {
|
|
440
|
+
console.log(" Skill not found in any agent directory.");
|
|
441
|
+
}
|
|
442
|
+
else {
|
|
443
|
+
success(`Removed '${slug}' from ${removed} agent(s)`);
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
export function skillsInitAction(name, options) {
|
|
447
|
+
const dir = resolve(name);
|
|
448
|
+
if (existsSync(dir)) {
|
|
449
|
+
error(`Directory '${name}' already exists.`);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
mkdirSync(dir, { recursive: true });
|
|
453
|
+
if (options.bare) {
|
|
454
|
+
const minimal = TEMPLATES.default
|
|
455
|
+
.replace("my-skill", name)
|
|
456
|
+
.replace("Describe what this skill does.", `${name} skill.`);
|
|
457
|
+
writeFileSync(join(dir, "SKILL.md"), minimal, "utf-8");
|
|
458
|
+
}
|
|
459
|
+
else {
|
|
460
|
+
const template = options.template || "default";
|
|
461
|
+
const content = TEMPLATES[template];
|
|
462
|
+
if (!content) {
|
|
463
|
+
error(`Unknown template: ${template}. Valid: ${Object.keys(TEMPLATES).join(", ")}`);
|
|
464
|
+
removeDir(dir);
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
467
|
+
const filled = content.replace(/my-skill/g, name);
|
|
468
|
+
writeFileSync(join(dir, "SKILL.md"), filled, "utf-8");
|
|
469
|
+
}
|
|
470
|
+
success(`Skill initialized: ${name}/`);
|
|
471
|
+
console.log(` ${chalk.gray(join(name, "SKILL.md"))}`);
|
|
472
|
+
hint("Edit SKILL.md, then run 'aisa skills submit ./" + name + "'");
|
|
473
|
+
}
|
|
474
|
+
export async function skillsSubmitAction(path) {
|
|
475
|
+
const key = requireApiKey();
|
|
476
|
+
const dir = resolve(path);
|
|
477
|
+
if (!existsSync(join(dir, "SKILL.md"))) {
|
|
478
|
+
error("No SKILL.md found. Run 'aisa skills init <name>' first.");
|
|
479
|
+
return;
|
|
480
|
+
}
|
|
481
|
+
const spinner = ora("Submitting skill...").start();
|
|
482
|
+
const files = readSkillDir(dir);
|
|
483
|
+
const res = await apiRequest(key, "cli/skills", {
|
|
484
|
+
method: "POST",
|
|
485
|
+
body: { files },
|
|
486
|
+
});
|
|
487
|
+
if (!res.success || !res.data) {
|
|
488
|
+
spinner.fail("Failed to submit skill");
|
|
489
|
+
error(res.error || "Unknown error");
|
|
490
|
+
return;
|
|
491
|
+
}
|
|
492
|
+
spinner.stop();
|
|
493
|
+
success(`Skill submitted: ${res.data.slug}`);
|
|
494
|
+
hint(`Request verification: aisa skills request-verification ${res.data.slug}`);
|
|
495
|
+
}
|
|
496
|
+
export async function skillsPushAction(slug) {
|
|
497
|
+
const key = requireApiKey();
|
|
498
|
+
const dir = resolve(".");
|
|
499
|
+
if (!existsSync(join(dir, "SKILL.md"))) {
|
|
500
|
+
error("No SKILL.md in current directory.");
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
const spinner = ora(`Pushing updates to ${slug}...`).start();
|
|
504
|
+
const files = readSkillDir(dir);
|
|
505
|
+
const res = await apiRequest(key, `cli/skills/${slug}`, {
|
|
506
|
+
method: "PUT",
|
|
507
|
+
body: { files },
|
|
508
|
+
});
|
|
509
|
+
if (!res.success) {
|
|
510
|
+
spinner.fail("Failed to push updates");
|
|
511
|
+
error(res.error || "Unknown error");
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
spinner.stop();
|
|
515
|
+
success(`Skill '${slug}' updated.`);
|
|
516
|
+
}
|
|
517
|
+
export async function skillsVerifyAction(slug) {
|
|
518
|
+
const key = requireApiKey();
|
|
519
|
+
const spinner = ora("Requesting verification...").start();
|
|
520
|
+
const res = await apiRequest(key, `cli/skills/${slug}/verify`, { method: "POST" });
|
|
521
|
+
if (!res.success) {
|
|
522
|
+
spinner.fail("Failed to request verification");
|
|
523
|
+
error(res.error || "Unknown error");
|
|
524
|
+
return;
|
|
525
|
+
}
|
|
526
|
+
spinner.stop();
|
|
527
|
+
success("Verification requested. The AISA team will review your skill.");
|
|
528
|
+
}
|
|
529
|
+
export async function skillsUpdateAction(slug) {
|
|
530
|
+
const key = requireApiKey();
|
|
531
|
+
if (slug) {
|
|
532
|
+
// Update single skill
|
|
533
|
+
const spinner = ora(`Updating ${slug}...`).start();
|
|
534
|
+
const res = await apiRequest(key, `cli/skills/${slug}`);
|
|
535
|
+
if (!res.success || !res.data) {
|
|
536
|
+
spinner.fail("Failed to fetch skill");
|
|
537
|
+
error(res.error || "Unknown error");
|
|
538
|
+
return;
|
|
539
|
+
}
|
|
540
|
+
spinner.stop();
|
|
541
|
+
const skill = res.data;
|
|
542
|
+
const targets = detectAgents(AGENT_DIRS);
|
|
543
|
+
for (const agent of targets) {
|
|
544
|
+
const dir = expandHome(join(AGENT_DIRS[agent], slug));
|
|
545
|
+
if (existsSync(dir)) {
|
|
546
|
+
writeSkillFiles(dir, skill.files);
|
|
547
|
+
console.log(` ${chalk.green("✓")} Updated in ${AGENT_DIRS[agent]}`);
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
success(`Skill '${slug}' updated.`);
|
|
551
|
+
}
|
|
552
|
+
else {
|
|
553
|
+
console.log(" Specify a skill to update: aisa skills update <owner/name>");
|
|
554
|
+
}
|
|
555
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export declare function tweetAction(text: string, options: {
|
|
2
|
+
replyTo?: string;
|
|
3
|
+
raw?: boolean;
|
|
4
|
+
}): Promise<void>;
|
|
5
|
+
export declare function twitterSearchAction(query: string, options: {
|
|
6
|
+
limit?: string;
|
|
7
|
+
raw?: boolean;
|
|
8
|
+
}): Promise<void>;
|
|
9
|
+
export declare function twitterUserAction(username: string, options: {
|
|
10
|
+
raw?: boolean;
|
|
11
|
+
}): Promise<void>;
|
|
12
|
+
export declare function twitterTrendsAction(options: {
|
|
13
|
+
raw?: boolean;
|
|
14
|
+
}): Promise<void>;
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import ora from "ora";
|
|
2
|
+
import chalk from "chalk";
|
|
3
|
+
import { requireApiKey } from "../config.js";
|
|
4
|
+
import { apiRequest } from "../api.js";
|
|
5
|
+
import { error, formatJson } from "../utils/display.js";
|
|
6
|
+
export async function tweetAction(text, options) {
|
|
7
|
+
const key = requireApiKey();
|
|
8
|
+
const spinner = ora("Posting tweet...").start();
|
|
9
|
+
const body = { text };
|
|
10
|
+
if (options.replyTo)
|
|
11
|
+
body.reply_to = options.replyTo;
|
|
12
|
+
const res = await apiRequest(key, "twitter/create-tweet-v2", {
|
|
13
|
+
method: "POST",
|
|
14
|
+
body,
|
|
15
|
+
});
|
|
16
|
+
if (!res.success) {
|
|
17
|
+
spinner.fail("Failed to post tweet");
|
|
18
|
+
error(res.error || "Unknown error");
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
spinner.stop();
|
|
22
|
+
if (options.raw) {
|
|
23
|
+
console.log(JSON.stringify(res.data));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
console.log(chalk.green("Tweet posted!"));
|
|
27
|
+
console.log(formatJson(res.data));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
export async function twitterSearchAction(query, options) {
|
|
31
|
+
const key = requireApiKey();
|
|
32
|
+
const spinner = ora(`Searching tweets: "${query}"...`).start();
|
|
33
|
+
const q = { query };
|
|
34
|
+
if (options.limit)
|
|
35
|
+
q.limit = options.limit;
|
|
36
|
+
const res = await apiRequest(key, "twitter/tweet/advanced-search", { query: q });
|
|
37
|
+
if (!res.success) {
|
|
38
|
+
spinner.fail("Twitter search failed");
|
|
39
|
+
error(res.error || "Unknown error");
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
spinner.stop();
|
|
43
|
+
if (options.raw) {
|
|
44
|
+
console.log(JSON.stringify(res.data));
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.log(formatJson(res.data));
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
export async function twitterUserAction(username, options) {
|
|
51
|
+
const key = requireApiKey();
|
|
52
|
+
const spinner = ora(`Fetching @${username}...`).start();
|
|
53
|
+
const res = await apiRequest(key, "twitter/user/info", {
|
|
54
|
+
query: { username },
|
|
55
|
+
});
|
|
56
|
+
if (!res.success) {
|
|
57
|
+
spinner.fail("Failed to fetch user");
|
|
58
|
+
error(res.error || "Unknown error");
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
spinner.stop();
|
|
62
|
+
if (options.raw) {
|
|
63
|
+
console.log(JSON.stringify(res.data));
|
|
64
|
+
}
|
|
65
|
+
else {
|
|
66
|
+
console.log(formatJson(res.data));
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
export async function twitterTrendsAction(options) {
|
|
70
|
+
const key = requireApiKey();
|
|
71
|
+
const spinner = ora("Fetching trends...").start();
|
|
72
|
+
const res = await apiRequest(key, "twitter/trends");
|
|
73
|
+
if (!res.success) {
|
|
74
|
+
spinner.fail("Failed to fetch trends");
|
|
75
|
+
error(res.error || "Unknown error");
|
|
76
|
+
return;
|
|
77
|
+
}
|
|
78
|
+
spinner.stop();
|
|
79
|
+
if (options.raw) {
|
|
80
|
+
console.log(JSON.stringify(res.data));
|
|
81
|
+
}
|
|
82
|
+
else {
|
|
83
|
+
console.log(formatJson(res.data));
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export declare function videoCreateAction(prompt: string, options: {
|
|
2
|
+
model?: string;
|
|
3
|
+
wait?: boolean;
|
|
4
|
+
output?: string;
|
|
5
|
+
raw?: boolean;
|
|
6
|
+
}): Promise<void>;
|
|
7
|
+
export declare function videoStatusAction(taskId: string, options: {
|
|
8
|
+
raw?: boolean;
|
|
9
|
+
}): Promise<void>;
|