@aisa-one/cli 0.2.2 → 0.2.3

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +134 -1
  2. package/README.md +249 -103
  3. package/dist/api.d.ts +46 -1
  4. package/dist/api.js +77 -8
  5. package/dist/cache.d.ts +18 -0
  6. package/dist/cache.js +65 -0
  7. package/dist/catalog.d.ts +90 -0
  8. package/dist/catalog.js +101 -0
  9. package/dist/commands/account.js +3 -1
  10. package/dist/commands/api.d.ts +18 -4
  11. package/dist/commands/api.js +357 -24
  12. package/dist/commands/cacheCmd.d.ts +2 -0
  13. package/dist/commands/cacheCmd.js +10 -0
  14. package/dist/commands/completionCmd.d.ts +7 -0
  15. package/dist/commands/completionCmd.js +37 -0
  16. package/dist/commands/configCmd.js +19 -1
  17. package/dist/commands/finance.d.ts +4 -0
  18. package/dist/commands/finance.js +212 -29
  19. package/dist/commands/models.js +6 -0
  20. package/dist/commands/run.d.ts +21 -0
  21. package/dist/commands/run.js +113 -6
  22. package/dist/commands/search.js +8 -3
  23. package/dist/commands/skills.d.ts +6 -2
  24. package/dist/commands/skills.js +189 -134
  25. package/dist/commands/twitter.js +2 -3
  26. package/dist/commands/video.d.ts +40 -0
  27. package/dist/commands/video.js +272 -55
  28. package/dist/completion.d.ts +26 -0
  29. package/dist/completion.js +293 -0
  30. package/dist/constants.d.ts +55 -5
  31. package/dist/constants.js +136 -11
  32. package/dist/index.js +84 -22
  33. package/dist/skills-registry.d.ts +64 -0
  34. package/dist/skills-registry.js +219 -0
  35. package/dist/types.d.ts +24 -0
  36. package/dist/utils/file.d.ts +5 -1
  37. package/dist/utils/file.js +5 -1
  38. package/dist/utils/pool.d.ts +8 -0
  39. package/dist/utils/pool.js +27 -0
  40. package/package.json +9 -3
  41. package/tests/account.test.ts +0 -89
  42. package/tests/streaming.test.ts +0 -73
@@ -1,15 +1,65 @@
1
- export declare const VERSION = "0.2.2";
1
+ export declare const VERSION = "0.2.3";
2
+ /** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
2
3
  export declare const BASE_URL = "https://api.aisa.one";
3
- export declare const CLI_BASE_URL = "https://api.aisa.one/v1";
4
- export declare const APIS_BASE_URL = "https://api.aisa.one/apis/v1";
5
4
  export declare const ENV_VAR_NAME = "AISA_API_KEY";
6
5
  export declare const MCP_URL = "https://docs.aisa.one/mcp";
6
+ /**
7
+ * First path segment of every route the LLM gateway serves under /v1 (plus
8
+ * /v1beta for Gemini). Everything else is an integration API under /apis/v1.
9
+ *
10
+ * This list is deliberately the whitelist rather than the provider slugs: the
11
+ * gateway routes are hardcoded server-side and change about once a year, while
12
+ * provider slugs are data that operations add and remove continuously. Keeping
13
+ * the whitelist on the slow-moving side means a newly added provider works
14
+ * without a CLI release.
15
+ */
16
+ export declare const LLM_ROUTE_PREFIXES: readonly string[];
7
17
  export declare const AGENT_DIRS: Record<string, string>;
8
18
  export declare const MCP_CONFIGS: Record<string, {
9
19
  path: string;
10
20
  key: string;
11
21
  }>;
12
- export declare const API_CATEGORIES: readonly ["llm", "search", "finance", "twitter", "video", "scholar"];
13
- export type ApiCategory = (typeof API_CATEGORIES)[number];
22
+ /**
23
+ * Ticker symbol → CoinGecko coin id.
24
+ *
25
+ * CoinGecko keys everything by id ("bitcoin"), not symbol ("BTC"), and dozens
26
+ * of unrelated tokens share popular symbols — resolving by symbol alone would
27
+ * happily return the price of the wrong coin. This table covers the symbols
28
+ * people actually type; anything else falls back to an explicit lookup.
29
+ */
30
+ export declare const COINGECKO_IDS: Record<string, string>;
31
+ /**
32
+ * Models routed to /v1/video/generations, and the request body each one wants.
33
+ *
34
+ * The gateway only rewrites the top-level `model` and passes the rest through,
35
+ * so the body shape belongs to whichever vendor owns the model — a Bailian-style
36
+ * `{input, parameters}` sent to Seedance is rejected outright with a 400.
37
+ *
38
+ * `requiresMedia` records the `input.media[].type` an image/clip-driven model
39
+ * needs. Without it the upstream accepts the submission and only fails a minute
40
+ * later, after billing, so the CLI refuses up front instead.
41
+ */
42
+ export type VideoFamily = "bailian" | "seedance";
43
+ export interface VideoModelSpec {
44
+ family: VideoFamily;
45
+ requiresMedia?: MediaType;
46
+ }
47
+ /** Accepted values for `input.media[].type` (enumerated by the upstream error). */
48
+ export declare const MEDIA_TYPES: readonly ["first_frame", "last_frame", "driving_audio", "first_clip"];
49
+ export type MediaType = (typeof MEDIA_TYPES)[number];
50
+ export declare const VIDEO_MODELS: Record<string, VideoModelSpec>;
51
+ export declare const DEFAULT_VIDEO_MODEL = "wan2.7-t2v";
52
+ /** Model families are matched by prefix so new revisions work without a release. */
53
+ export declare function videoModelSpec(model: string): VideoModelSpec;
54
+ /**
55
+ * Client-side grouping of integration providers.
56
+ *
57
+ * The catalog returns no description or tags — `buildCatalogItem` never
58
+ * populates them — so there is nothing server-side to filter on. Entries are
59
+ * matched by prefix, which keeps the polymarket-* family together.
60
+ */
61
+ export declare const PROVIDER_CATEGORIES: Record<string, string[]>;
62
+ export declare function categoryOf(providerId: string): string;
63
+ export declare const API_CATEGORIES: readonly [...string[], "other"];
14
64
  export declare const MODEL_PROVIDERS: readonly ["openai", "anthropic", "google", "deepseek", "xai", "moonshot", "alibaba", "bytedance"];
15
65
  export type ModelProvider = (typeof MODEL_PROVIDERS)[number];
package/dist/constants.js CHANGED
@@ -1,9 +1,31 @@
1
- export const VERSION = "0.2.2";
1
+ export const VERSION = "0.2.3";
2
+ /** Root of the platform. Per-surface bases are derived in api.ts#resolveBases. */
2
3
  export const BASE_URL = "https://api.aisa.one";
3
- export const CLI_BASE_URL = `${BASE_URL}/v1`;
4
- export const APIS_BASE_URL = `${BASE_URL}/apis/v1`;
5
4
  export const ENV_VAR_NAME = "AISA_API_KEY";
6
5
  export const MCP_URL = "https://docs.aisa.one/mcp";
6
+ /**
7
+ * First path segment of every route the LLM gateway serves under /v1 (plus
8
+ * /v1beta for Gemini). Everything else is an integration API under /apis/v1.
9
+ *
10
+ * This list is deliberately the whitelist rather than the provider slugs: the
11
+ * gateway routes are hardcoded server-side and change about once a year, while
12
+ * provider slugs are data that operations add and remove continuously. Keeping
13
+ * the whitelist on the slow-moving side means a newly added provider works
14
+ * without a CLI release.
15
+ */
16
+ export const LLM_ROUTE_PREFIXES = [
17
+ "chat",
18
+ "responses",
19
+ "embeddings",
20
+ "messages",
21
+ "models",
22
+ "rerank",
23
+ "classify",
24
+ "images",
25
+ "credits",
26
+ "video",
27
+ "v1beta",
28
+ ];
7
29
  export const AGENT_DIRS = {
8
30
  claude: "~/.claude/skills/",
9
31
  cursor: "~/.cursor/skills/",
@@ -24,14 +46,117 @@ export const MCP_CONFIGS = {
24
46
  key: "mcpServers",
25
47
  },
26
48
  };
27
- export const API_CATEGORIES = [
28
- "llm",
29
- "search",
30
- "finance",
31
- "twitter",
32
- "video",
33
- "scholar",
34
- ];
49
+ /**
50
+ * Ticker symbol → CoinGecko coin id.
51
+ *
52
+ * CoinGecko keys everything by id ("bitcoin"), not symbol ("BTC"), and dozens
53
+ * of unrelated tokens share popular symbols — resolving by symbol alone would
54
+ * happily return the price of the wrong coin. This table covers the symbols
55
+ * people actually type; anything else falls back to an explicit lookup.
56
+ */
57
+ export const COINGECKO_IDS = {
58
+ btc: "bitcoin",
59
+ eth: "ethereum",
60
+ usdt: "tether",
61
+ bnb: "binancecoin",
62
+ sol: "solana",
63
+ usdc: "usd-coin",
64
+ xrp: "ripple",
65
+ doge: "dogecoin",
66
+ ada: "cardano",
67
+ trx: "tron",
68
+ avax: "avalanche-2",
69
+ shib: "shiba-inu",
70
+ dot: "polkadot",
71
+ link: "chainlink",
72
+ bch: "bitcoin-cash",
73
+ near: "near",
74
+ matic: "matic-network",
75
+ ltc: "litecoin",
76
+ icp: "internet-computer",
77
+ uni: "uniswap",
78
+ leo: "leo-token",
79
+ dai: "dai",
80
+ etc: "ethereum-classic",
81
+ apt: "aptos",
82
+ render: "render-token",
83
+ hbar: "hedera-hashgraph",
84
+ fil: "filecoin",
85
+ arb: "arbitrum",
86
+ atom: "cosmos",
87
+ imx: "immutable-x",
88
+ op: "optimism",
89
+ vet: "vechain",
90
+ inj: "injective-protocol",
91
+ sui: "sui",
92
+ ton: "the-open-network",
93
+ pepe: "pepe",
94
+ tao: "bittensor",
95
+ sei: "sei-network",
96
+ aave: "aave",
97
+ algo: "algorand",
98
+ xlm: "stellar",
99
+ cro: "crypto-com-chain",
100
+ mnt: "mantle",
101
+ wld: "worldcoin-wld",
102
+ };
103
+ /** Accepted values for `input.media[].type` (enumerated by the upstream error). */
104
+ export const MEDIA_TYPES = ["first_frame", "last_frame", "driving_audio", "first_clip"];
105
+ export const VIDEO_MODELS = {
106
+ "wan2.7-t2v": { family: "bailian" },
107
+ "wan2.7-i2v": { family: "bailian", requiresMedia: "first_frame" },
108
+ "wan2.7-r2v": { family: "bailian", requiresMedia: "first_clip" },
109
+ "happyhorse-1.1-t2v": { family: "bailian" },
110
+ "happyhorse-1.1-i2v": { family: "bailian", requiresMedia: "first_frame" },
111
+ "happyhorse-1.1-r2v": { family: "bailian", requiresMedia: "first_clip" },
112
+ "dreamina-seedance-2-0-260128": { family: "seedance" },
113
+ "dreamina-seedance-2-0-fast-260128": { family: "seedance" },
114
+ };
115
+ export const DEFAULT_VIDEO_MODEL = "wan2.7-t2v";
116
+ /** Model families are matched by prefix so new revisions work without a release. */
117
+ export function videoModelSpec(model) {
118
+ if (VIDEO_MODELS[model])
119
+ return VIDEO_MODELS[model];
120
+ const family = model.startsWith("dreamina-seedance") ? "seedance" : "bailian";
121
+ if (/-i2v\b|-i2v$/.test(model))
122
+ return { family, requiresMedia: "first_frame" };
123
+ if (/-r2v\b|-r2v$/.test(model))
124
+ return { family, requiresMedia: "first_clip" };
125
+ return { family };
126
+ }
127
+ /**
128
+ * Client-side grouping of integration providers.
129
+ *
130
+ * The catalog returns no description or tags — `buildCatalogItem` never
131
+ * populates them — so there is nothing server-side to filter on. Entries are
132
+ * matched by prefix, which keeps the polymarket-* family together.
133
+ */
134
+ export const PROVIDER_CATEGORIES = {
135
+ finance: ["financial", "fred", "edinet", "coingecko", "polymarket", "kalshi"],
136
+ search: [
137
+ "search",
138
+ "tavily",
139
+ "brave",
140
+ "exa",
141
+ "perplexity",
142
+ "querit",
143
+ "parallel",
144
+ "dataforseo",
145
+ "jina",
146
+ "scholar",
147
+ ],
148
+ social: ["twitter", "aisa-twitter", "youtube", "scrape-creators", "waveinflu"],
149
+ productivity: ["agentmail", "apollo", "composio"],
150
+ };
151
+ export function categoryOf(providerId) {
152
+ for (const [category, prefixes] of Object.entries(PROVIDER_CATEGORIES)) {
153
+ if (prefixes.some((p) => providerId === p || providerId.startsWith(`${p}-`) || providerId.startsWith(`${p}.`))) {
154
+ return category;
155
+ }
156
+ }
157
+ return "other";
158
+ }
159
+ export const API_CATEGORIES = [...Object.keys(PROVIDER_CATEGORIES), "other"];
35
160
  export const MODEL_PROVIDERS = [
36
161
  "openai",
37
162
  "anthropic",
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  #!/usr/bin/env node
2
2
  import { Command } from "commander";
3
- import { VERSION } from "./constants.js";
3
+ import { VERSION, DEFAULT_VIDEO_MODEL } from "./constants.js";
4
4
  // Auth
5
5
  import { loginAction, logoutAction, whoamiAction } from "./commands/auth.js";
6
6
  // Account
@@ -27,6 +27,10 @@ import { skillsListAction, skillsSearchAction, skillsShowAction, skillsInstallAc
27
27
  import { mcpSetupAction, mcpStatusAction } from "./commands/mcp.js";
28
28
  // Config
29
29
  import { configSetAction, configGetAction, configListAction, configResetAction } from "./commands/configCmd.js";
30
+ // Cache
31
+ import { cacheClearAction, cachePathAction } from "./commands/cacheCmd.js";
32
+ // Completion
33
+ import { completionAction, completeAction } from "./commands/completionCmd.js";
30
34
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
31
35
  function wrap(fn) {
32
36
  return (...args) => {
@@ -63,30 +67,43 @@ program
63
67
  .action(wrap(balanceAction));
64
68
  program
65
69
  .command("usage")
66
- .description("Show usage history (WIP)")
70
+ .description("Show usage history (awaiting gateway support)")
67
71
  .option("--limit <n>", "Max records")
68
72
  .option("--days <n>", "Lookback days")
69
73
  .action(wrap(usageAction));
70
74
  // ── API ──
71
- const api = program.command("api").description("Discover and inspect APIs (WIP)");
75
+ const api = program.command("api").description("Discover and inspect APIs");
72
76
  api
73
77
  .command("list")
74
- .description("List available API endpoints (WIP)")
75
- .option("--category <cat>", "Filter by category (llm, search, finance, twitter, video, scholar)")
78
+ .description("List available APIs")
79
+ .option("--category <cat>", "Filter by category (client-side grouping): finance, search, social, productivity, other")
80
+ .option("--health", "Include provider health status")
81
+ .option("--json", "Output raw JSON")
82
+ .option("--refresh", "Bypass the cached catalog")
76
83
  .action(wrap(apiListAction));
77
84
  api
78
85
  .command("search <query>")
79
- .description("Search APIs by keyword (WIP)")
80
- .option("--limit <n>", "Max results")
86
+ .description("Search APIs and endpoints by keyword")
87
+ .option("--provider <id>", "Restrict to one API")
88
+ .option("--limit <n>", "Max results", "20")
89
+ .option("--json", "Output raw JSON")
90
+ .option("--refresh", "Bypass the cached catalog")
81
91
  .action(wrap(apiSearchAction));
82
92
  api
83
- .command("show <slug> [path]")
84
- .description("Show API endpoint details (WIP)")
93
+ .command("show <api> [path]")
94
+ .description("Show an API's endpoints, or one endpoint's details")
95
+ .option("--all", "Show every endpoint instead of the first 40")
96
+ .option("--group", "Group by the provider's raw endpoint groups")
97
+ .option("--health", "Include provider health status")
98
+ .option("--json", "Output raw JSON")
99
+ .option("--refresh", "Bypass the cached catalog")
85
100
  .action(wrap(apiShowAction));
86
101
  api
87
102
  .command("code <slug> <path>")
88
- .description("Generate code snippet (WIP)")
89
- .option("--lang <language>", "Language: typescript, python, curl", "typescript")
103
+ .description("Generate a request snippet for an endpoint")
104
+ .option("--lang <language>", "Language: curl, python, node, typescript", "curl")
105
+ .option("--method <method>", "HTTP method (the catalog's method is advisory)", "GET")
106
+ .option("--refresh", "Bypass the cached catalog")
90
107
  .action(wrap(apiCodeAction));
91
108
  // ── Run ──
92
109
  program
@@ -97,12 +114,18 @@ program
97
114
  .option("--method <method>", "HTTP method")
98
115
  .option("--raw", "Raw JSON output")
99
116
  .option("--stream", "Stream response")
117
+ .option("--domain", "Force the integration API base (/apis/v1) — the default")
118
+ .option("--llm", "Force the LLM gateway base (/v1)")
119
+ .option("--show-cost", "Print the billing headers the gateway reported (stderr)")
100
120
  .action((slug, path, opts) => wrap(runAction)(slug, path, {
101
121
  q: opts.query,
102
122
  d: opts.data,
103
123
  method: opts.method,
104
124
  raw: opts.raw,
105
125
  stream: opts.stream,
126
+ llm: opts.llm,
127
+ domain: opts.domain,
128
+ showCost: opts.showCost,
106
129
  }));
107
130
  // ── Chat (LLM Gateway) ──
108
131
  program
@@ -130,7 +153,7 @@ models
130
153
  program
131
154
  .command("web-search <query>")
132
155
  .description("Search the web")
133
- .option("--type <type>", "Search type: smart, full, youtube, scholar, tavily", "smart")
156
+ .option("--type <type>", "Search type: tavily, youtube, scholar, smart (degraded), full (degraded)", "tavily")
134
157
  .option("--limit <n>", "Max results")
135
158
  .option("--raw", "Raw JSON output")
136
159
  .action(wrap(webSearchAction));
@@ -150,13 +173,17 @@ program
150
173
  program
151
174
  .command("crypto <symbol>")
152
175
  .description("Look up crypto price")
153
- .option("--period <period>", "Time period: current, 1d, 7d, 30d, 1y")
176
+ .option("--period <period>", "Time period: current, 1d, 7d, 30d, 90d, 1y")
177
+ .option("--id <coingecko-id>", "Use an exact CoinGecko id instead of resolving the symbol")
178
+ .option("--source <source>", "Data source: coingecko (default) or financial")
154
179
  .option("--raw", "Raw JSON output")
155
180
  .action(wrap(cryptoAction));
156
181
  program
157
182
  .command("screener")
158
183
  .description("Screen stocks by criteria")
159
- .option("--sector <sector>", "Filter by sector")
184
+ .option("--sector <sector>", "Filter by GICS sector (e.g. 'Information Technology')")
185
+ .option("--min-market-cap <n>", "Minimum market cap in USD")
186
+ .option("--filter <f...>", "Extra filter as field:operator:value (e.g. market_cap:gt:1e12)")
160
187
  .option("--limit <n>", "Max results")
161
188
  .option("--raw", "Raw JSON output")
162
189
  .action(wrap(screenerAction));
@@ -388,14 +415,20 @@ const video = program.command("video").description("AI video generation");
388
415
  video
389
416
  .command("create <prompt>")
390
417
  .description("Create a video generation task")
391
- .option("--model <model>", "Generation model")
418
+ .option("--model <model>", `Generation model (default: ${DEFAULT_VIDEO_MODEL})`)
419
+ .option("--image <url...>", "Source image for i2v models (shorthand for --media first_frame=<url>)")
420
+ .option("--media <type=url...>", "Source media: first_frame, last_frame, driving_audio, first_clip")
421
+ .option("--resolution <res>", "Resolution, e.g. 720P or 1080P", "720P")
422
+ .option("--duration <seconds>", "Clip duration in seconds", "5")
423
+ .option("--body <json>", "Send this request body verbatim (escape hatch for unmodelled vendors)")
392
424
  .option("--wait", "Wait for completion")
393
- .option("--output <path>", "Download output path")
425
+ .option("--output <path>", "Download the finished video to this path (implies --wait)")
394
426
  .option("--raw", "Raw JSON output")
395
- .action(wrap(videoCreateAction));
427
+ .action((prompt, opts) => wrap(videoCreateAction)(prompt, { ...opts, wait: Boolean(opts.wait || opts.output) }));
396
428
  video
397
429
  .command("status <task-id>")
398
430
  .description("Check video task status")
431
+ .option("--output <path>", "Download the finished video to this path")
399
432
  .option("--raw", "Raw JSON output")
400
433
  .action(wrap(videoStatusAction));
401
434
  // ── Skills ──
@@ -403,13 +436,15 @@ const skills = program.command("skills").description("Browse and manage agent sk
403
436
  skills
404
437
  .command("list")
405
438
  .description("List available skills")
406
- .option("--category <cat>", "Filter by category")
439
+ .option("--category <cat>", "Filter by category (ai-models, financial, marketing, ...)")
407
440
  .option("--limit <n>", "Max results")
441
+ .option("--refresh", "Bypass the cached skill index")
408
442
  .action(wrap(skillsListAction));
409
443
  skills
410
444
  .command("search <query>")
411
445
  .description("Search skills by keyword")
412
446
  .option("--limit <n>", "Max results")
447
+ .option("--refresh", "Bypass the cached skill index")
413
448
  .action(wrap(skillsSearchAction));
414
449
  skills
415
450
  .command("show <slug>")
@@ -419,11 +454,13 @@ skills
419
454
  .command("install <slug>")
420
455
  .description("Install a skill to agent directories")
421
456
  .option("--agent <agent>", "Target agent: claude, cursor, copilot, windsurf, codex, gemini, openclaw, all")
457
+ .option("--force", "Overwrite a directory holding a different skill")
422
458
  .action(wrap(skillsInstallAction));
423
459
  skills
424
460
  .command("remove <slug>")
425
461
  .description("Remove an installed skill")
426
462
  .option("--agent <agent>", "Target agent")
463
+ .option("--force", "Remove even if the directory holds a different skill")
427
464
  .action(skillsRemoveAction);
428
465
  skills
429
466
  .command("init <name>")
@@ -463,13 +500,38 @@ configCmd
463
500
  // ── Top-level aliases ──
464
501
  program
465
502
  .command("search <query>")
466
- .description("Search APIs (alias for 'api search') (WIP)")
467
- .option("--limit <n>", "Max results")
503
+ .description("Search APIs (alias for 'api search')")
504
+ .option("--provider <id>", "Restrict to one API")
505
+ .option("--limit <n>", "Max results", "20")
506
+ .option("--json", "Output raw JSON")
507
+ .option("--refresh", "Bypass the cached catalog")
468
508
  .action(wrap(apiSearchAction));
469
509
  program
470
510
  .command("code <slug> <path>")
471
- .description("Generate code (alias for 'api code') (WIP)")
472
- .option("--lang <language>", "Language", "typescript")
511
+ .description("Generate a request snippet (alias for 'api code')")
512
+ .option("--lang <language>", "Language: curl, python, node, typescript", "curl")
513
+ .option("--method <method>", "HTTP method")
473
514
  .action(wrap(apiCodeAction));
515
+ const cache = program.command("cache").description("Manage the local catalog and skills cache");
516
+ cache
517
+ .command("clear")
518
+ .description("Delete all cached catalog and skills data")
519
+ .action(cacheClearAction);
520
+ cache
521
+ .command("path")
522
+ .description("Print the cache directory")
523
+ .action(cachePathAction);
524
+ // ── Shell completion ──
525
+ program
526
+ .command("completion [shell]")
527
+ .description("Print a shell completion script (bash, zsh, fish)")
528
+ .action(completionAction);
529
+ // Called by the generated scripts on every Tab press. Hidden, and tolerant of
530
+ // whatever half-typed input the shell hands it.
531
+ program
532
+ .command("__complete [words...]", { hidden: true })
533
+ .allowUnknownOption()
534
+ .allowExcessArguments()
535
+ .action((words = []) => completeAction(program, words));
474
536
  // ── Parse ──
475
537
  program.parse();
@@ -0,0 +1,64 @@
1
+ /**
2
+ * GitHub-backed skill registry.
3
+ *
4
+ * The repo nests skills two levels deep (`<category>/<name>/SKILL.md`), so the
5
+ * canonical slug is the repo-relative directory. Everything here is driven off
6
+ * a single recursive tree fetch: api.github.com allows only 60 unauthenticated
7
+ * requests per hour per IP, and the previous per-command fetching burned
8
+ * several of those on every invocation.
9
+ */
10
+ export declare const SKILLS_REPO = "AIsa-team/agent-skills";
11
+ export declare const GH_RAW = "https://raw.githubusercontent.com/AIsa-team/agent-skills/main";
12
+ export interface SkillBlob {
13
+ path: string;
14
+ sha: string;
15
+ }
16
+ export interface SkillIndex {
17
+ /** Canonical slugs (`<category>/<name>`), sorted. */
18
+ slugs: string[];
19
+ /** All blobs under each slug, including SKILL.md. */
20
+ blobs: Record<string, SkillBlob[]>;
21
+ }
22
+ export interface SkillInfo {
23
+ slug: string;
24
+ name: string;
25
+ description: string;
26
+ emoji: string;
27
+ }
28
+ /**
29
+ * Fetch (or reuse) the skill index. Memoized per process on top of a 1h disk
30
+ * cache with ETag revalidation, so repeated commands cost at most one
31
+ * conditional request.
32
+ */
33
+ export declare function getSkillIndex(options?: {
34
+ refresh?: boolean;
35
+ }): Promise<SkillIndex>;
36
+ /** Last path segment — what the skill is called once installed. */
37
+ export declare function leafName(slug: string): string;
38
+ /**
39
+ * Accept either a canonical `<category>/<name>` slug or a bare name. A bare
40
+ * name that matches several skills is an error rather than a guess: installing
41
+ * the wrong skill silently is worse than asking.
42
+ */
43
+ export declare function resolveSlug(input: string, index: SkillIndex): string;
44
+ /** Parse YAML frontmatter from SKILL.md content. */
45
+ export declare function parseSkillFrontmatter(slug: string, content: string): SkillInfo;
46
+ export declare function fetchSkillMarkdown(slug: string): Promise<string>;
47
+ /**
48
+ * Metadata for every skill. Cached by blob sha, so a warm cache needs zero
49
+ * content requests and only re-fetches the skills that actually changed.
50
+ */
51
+ export declare function listSkills(index: SkillIndex): Promise<SkillInfo[]>;
52
+ export interface SkillFile {
53
+ path: string;
54
+ content: Buffer;
55
+ }
56
+ /**
57
+ * Download every file in a skill directory. Content is kept as bytes: skills
58
+ * may ship images or fonts, and decoding those as UTF-8 corrupts them.
59
+ *
60
+ * A partial download is an error, not a smaller skill. Installing replaces the
61
+ * target directory, so silently dropping failed files would delete a working
62
+ * skill and leave a broken one — possibly without its SKILL.md.
63
+ */
64
+ export declare function fetchSkillFiles(slug: string, index: SkillIndex): Promise<SkillFile[]>;