@aisa-one/cli 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/CHANGELOG.md +143 -1
  2. package/LICENSE +21 -0
  3. package/README.md +151 -162
  4. package/dist/api.d.ts +10 -0
  5. package/dist/api.js +14 -3
  6. package/dist/catalog.d.ts +1 -18
  7. package/dist/catalog.js +1 -24
  8. package/dist/cli-error.d.ts +17 -0
  9. package/dist/cli-error.js +25 -0
  10. package/dist/cli-guidance.d.ts +14 -0
  11. package/dist/cli-guidance.js +55 -0
  12. package/dist/commands/account.d.ts +17 -0
  13. package/dist/commands/account.js +45 -1
  14. package/dist/commands/api.d.ts +0 -11
  15. package/dist/commands/api.js +6 -175
  16. package/dist/commands/auth.d.ts +2 -1
  17. package/dist/commands/auth.js +43 -9
  18. package/dist/commands/brand-logos.d.ts +6 -0
  19. package/dist/commands/brand-logos.js +21 -0
  20. package/dist/commands/configCmd.js +8 -3
  21. package/dist/commands/connect-shared.d.ts +136 -0
  22. package/dist/commands/connect-shared.js +143 -0
  23. package/dist/commands/connect-t2.d.ts +18 -0
  24. package/dist/commands/connect-t2.js +1599 -0
  25. package/dist/commands/connect-terminal.d.ts +65 -0
  26. package/dist/commands/connect-terminal.js +822 -0
  27. package/dist/commands/connect.d.ts +31 -0
  28. package/dist/commands/connect.js +3181 -0
  29. package/dist/commands/flow.d.ts +685 -0
  30. package/dist/commands/flow.js +697 -0
  31. package/dist/commands/install.d.ts +91 -0
  32. package/dist/commands/install.js +258 -0
  33. package/dist/commands/llm-config.d.ts +103 -0
  34. package/dist/commands/llm-config.js +452 -0
  35. package/dist/commands/manifest.d.ts +68 -0
  36. package/dist/commands/manifest.js +90 -0
  37. package/dist/commands/mcp.d.ts +59 -0
  38. package/dist/commands/mcp.js +122 -44
  39. package/dist/commands/oauth-login.d.ts +33 -0
  40. package/dist/commands/oauth-login.js +333 -0
  41. package/dist/commands/prompt.d.ts +96 -0
  42. package/dist/commands/prompt.js +397 -0
  43. package/dist/commands/serve-results.d.ts +61 -0
  44. package/dist/commands/serve-results.js +245 -0
  45. package/dist/commands/serve-signin.d.ts +28 -0
  46. package/dist/commands/serve-signin.js +90 -0
  47. package/dist/commands/signin-page.d.ts +49 -0
  48. package/dist/commands/signin-page.js +250 -0
  49. package/dist/commands/skills.js +87 -50
  50. package/dist/commands/tool-help.d.ts +69 -0
  51. package/dist/commands/tool-help.js +189 -0
  52. package/dist/commands/tool-input.d.ts +22 -0
  53. package/dist/commands/tool-input.js +220 -0
  54. package/dist/commands/tools.d.ts +12 -0
  55. package/dist/commands/tools.js +307 -0
  56. package/dist/commands/update.d.ts +11 -0
  57. package/dist/commands/update.js +92 -0
  58. package/dist/commands/vscode.d.ts +65 -0
  59. package/dist/commands/vscode.js +173 -0
  60. package/dist/commands/wrappers.d.ts +23 -0
  61. package/dist/commands/wrappers.js +102 -0
  62. package/dist/completion.js +3 -80
  63. package/dist/config.js +76 -2
  64. package/dist/constants.d.ts +51 -38
  65. package/dist/constants.js +53 -109
  66. package/dist/index.js +152 -355
  67. package/dist/json-text.d.ts +12 -0
  68. package/dist/json-text.js +60 -0
  69. package/dist/router.d.ts +39 -0
  70. package/dist/router.js +59 -0
  71. package/dist/skills-registry.js +12 -3
  72. package/dist/utils/banner.d.ts +9 -0
  73. package/dist/utils/banner.js +41 -0
  74. package/dist/utils/browser.d.ts +19 -0
  75. package/dist/utils/browser.js +31 -0
  76. package/dist/utils/exec.d.ts +43 -0
  77. package/dist/utils/exec.js +61 -0
  78. package/dist/utils/http.d.ts +53 -0
  79. package/dist/utils/http.js +124 -0
  80. package/dist/utils/install-method.d.ts +36 -0
  81. package/dist/utils/install-method.js +48 -0
  82. package/dist/utils/journal.d.ts +57 -0
  83. package/dist/utils/journal.js +188 -0
  84. package/dist/utils/key-check.d.ts +20 -0
  85. package/dist/utils/key-check.js +24 -0
  86. package/dist/utils/update-check.d.ts +23 -0
  87. package/dist/utils/update-check.js +116 -0
  88. package/dist/utils/width.d.ts +32 -0
  89. package/dist/utils/width.js +73 -0
  90. package/package.json +8 -4
  91. package/vscode-extension/README.md +6 -0
  92. package/vscode-extension/aisa-vscode.vsix +0 -0
  93. package/dist/commands/finance.d.ts +0 -17
  94. package/dist/commands/finance.js +0 -342
  95. package/dist/commands/run.d.ts +0 -28
  96. package/dist/commands/run.js +0 -182
  97. package/dist/commands/search.d.ts +0 -9
  98. package/dist/commands/search.js +0 -81
  99. package/dist/commands/twitter.d.ts +0 -138
  100. package/dist/commands/twitter.js +0 -374
  101. package/dist/commands/video.d.ts +0 -49
  102. package/dist/commands/video.js +0 -311
package/dist/index.js CHANGED
@@ -1,45 +1,69 @@
1
1
  #!/usr/bin/env node
2
- import { Command } from "commander";
3
- import { VERSION, DEFAULT_VIDEO_MODEL } from "./constants.js";
2
+ import { Command, Option } from "commander";
3
+ import { VERSION } from "./constants.js";
4
+ import { CliError } from "./cli-error.js";
4
5
  // Auth
5
6
  import { loginAction, logoutAction, whoamiAction } from "./commands/auth.js";
6
7
  // Account
7
- import { balanceAction, usageAction } from "./commands/account.js";
8
+ import { balanceAction, topupAction, usageAction } from "./commands/account.js";
8
9
  // API
9
- import { apiListAction, apiSearchAction, apiShowAction, apiCodeAction } from "./commands/api.js";
10
- // Run
11
- import { runAction } from "./commands/run.js";
10
+ import { apiListAction, apiShowAction } from "./commands/api.js";
12
11
  // Chat
13
12
  import { chatAction } from "./commands/chat.js";
14
13
  // Models
15
14
  import { modelsListAction, modelsShowAction } from "./commands/models.js";
16
15
  // Search
17
- import { webSearchAction, scholarAction } from "./commands/search.js";
18
- // Finance
19
- import { stockAction, cryptoAction, screenerAction } from "./commands/finance.js";
20
- // Twitter
21
- import { tweetAction, twitterSearchAction, twitterUserAction, twitterTrendsAction, twitterUserAboutAction, twitterBatchUsersAction, twitterUserTweetsAction, twitterMentionsAction, twitterFollowersAction, twitterFollowingAction, twitterVerifiedFollowersAction, twitterCheckFollowAction, twitterUserSearchAction, twitterDetailAction, twitterRepliesAction, twitterQuotesAction, twitterRetweetersAction, twitterThreadAction, twitterArticleAction, twitterListMembersAction, twitterListFollowersAction, twitterCommunityInfoAction, twitterCommunityMembersAction, twitterCommunityModsAction, twitterCommunityTweetsAction, twitterCommunitySearchAction, twitterSpaceAction, twitterLoginAction, twitterLogoutAction, twitterLikeAction, twitterUnlikeAction, twitterRetweetAction, twitterDeleteAction, twitterFollowAction, twitterUnfollowAction, twitterUploadMediaAction, twitterDmAction, } from "./commands/twitter.js";
22
- // Video
23
- import { videoCreateAction, videoStatusAction } from "./commands/video.js";
16
+ import { searchAction, schemaAction, quoteAction, callAction } from "./commands/tools.js";
17
+ import { callHelpAfter, quoteHelpAfter, rootHelpAfter, schemaHelpAfter, searchHelpAfter, } from "./commands/tool-help.js";
24
18
  // Skills
25
19
  import { skillsListAction, skillsSearchAction, skillsShowAction, skillsInstallAction, skillsRemoveAction, skillsInitAction, } from "./commands/skills.js";
26
20
  // MCP
27
21
  import { mcpSetupAction, mcpStatusAction } from "./commands/mcp.js";
22
+ import { connectAction } from "./commands/connect.js";
23
+ // Update
24
+ import { updateAction } from "./commands/update.js";
25
+ import { announceUpdate } from "./utils/update-check.js";
28
26
  // Config
29
27
  import { configSetAction, configGetAction, configListAction, configResetAction } from "./commands/configCmd.js";
30
28
  // Cache
31
29
  import { cacheClearAction, cachePathAction } from "./commands/cacheCmd.js";
32
30
  // Completion
33
31
  import { completionAction, completeAction } from "./commands/completionCmd.js";
32
+ // Manifest
33
+ import { manifestAction } from "./commands/manifest.js";
34
+ import { serveResultsAction } from "./commands/serve-results.js";
35
+ import { serveSignInAction } from "./commands/serve-signin.js";
34
36
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
37
  function wrap(fn) {
36
38
  return (...args) => {
37
- fn(...args).catch((err) => {
38
- console.error(`Error: ${err.message}`);
39
- process.exit(1);
39
+ fn(...args)
40
+ // After the command, never before: the thing the user asked for is what
41
+ // should reach the screen first, and this is only ever a footnote.
42
+ // announceUpdate is silent for a pipe, for an install it cannot update,
43
+ // and whenever the answer is not already on disk within its budget.
44
+ .then(() => announceUpdate())
45
+ .catch((err) => {
46
+ const code = err instanceof CliError ? err.exitCode : 1;
47
+ if (err.message)
48
+ console.error(`Error: ${err.message}`);
49
+ process.exit(code);
40
50
  });
41
51
  };
42
52
  }
53
+ function collectProvider(value, previous) {
54
+ return [...previous, value];
55
+ }
56
+ function routerIo(opts) {
57
+ return {
58
+ input: opts.input,
59
+ file: opts.file,
60
+ json: Boolean(opts.json),
61
+ limit: opts.limit,
62
+ provider: opts.provider,
63
+ includeArgumentsSchema: opts.argumentsSchema === false ? false : undefined,
64
+ includeResponseSchema: opts.includeResponseSchema === true ? true : undefined,
65
+ };
66
+ }
43
67
  const program = new Command();
44
68
  program
45
69
  .name("aisa")
@@ -48,9 +72,10 @@ program
48
72
  // ── Auth ──
49
73
  program
50
74
  .command("login")
51
- .description("Authenticate with your AIsa API key")
52
- .option("--key <key>", "API key")
53
- .action(loginAction);
75
+ .description("Sign in to AIsa — browser sign-in by default, or --key to paste one")
76
+ .option("--key <key>", "API key (skips the browser sign-in)")
77
+ .option("--no-browser", "Print the sign-in URL and paste the redirect back (detected on its own over SSH)")
78
+ .action(wrap(loginAction));
54
79
  program
55
80
  .command("logout")
56
81
  .description("Remove stored API key")
@@ -60,6 +85,11 @@ program
60
85
  .description("Show authentication status")
61
86
  .action(whoamiAction);
62
87
  // ── Account ──
88
+ program
89
+ .command("topup [amount]")
90
+ .description("Add credit — opens the console billing page (amount in USD, optional)")
91
+ .option("--no-open", "Print the URL instead of opening the browser")
92
+ .action(topupAction);
63
93
  program
64
94
  .command("balance")
65
95
  .description("Show credit balance")
@@ -71,8 +101,45 @@ program
71
101
  .option("--limit <n>", "Max records")
72
102
  .option("--days <n>", "Lookback days")
73
103
  .action(wrap(usageAction));
104
+ // ── Tool Router (same operations as MCP) ──
105
+ program
106
+ .command("search [query]")
107
+ .description("Discover published tools via the Tool Router (MCP AISA_SEARCH_TOOL)")
108
+ .option("--input <json>", "Inline JSON request body (no file required)")
109
+ .option("-f, --file <path>", "Read JSON request from file, or - for stdin")
110
+ .option("--limit <n>", "Max additional discovery results (1-20)")
111
+ .option("--provider <id>", "Exact catalog provider key (repeatable)", collectProvider, [])
112
+ .option("--json", "Write the unmodified application response to stdout (MCP identifiers unchanged)")
113
+ .addHelpText("after", searchHelpAfter())
114
+ .action((query, opts) => wrap(searchAction)(query, routerIo(opts)));
115
+ program
116
+ .command("schema [tools...]")
117
+ .description("Get published tool schemas via the Tool Router (MCP AISA_BATCH_GET_SCHEMA)")
118
+ .option("--input <json>", "Inline JSON request body (no file required)")
119
+ .option("-f, --file <path>", "Read JSON request from file, or - for stdin")
120
+ .option("--no-arguments-schema", "Omit arguments_schema (at least one schema type is required)")
121
+ .option("--include-response-schema", "Include response_schema")
122
+ .option("--json", "Write the unmodified application response to stdout (MCP identifiers unchanged)")
123
+ .addHelpText("after", schemaHelpAfter())
124
+ .action((tools, opts) => wrap(schemaAction)(tools, routerIo(opts)));
125
+ program
126
+ .command("quote")
127
+ .description("Quote published tools via the Tool Router without executing them (MCP AISA_BATCH_QUOTE)")
128
+ .option("--input <json>", "Inline JSON request body, same shape as call (no file required)")
129
+ .option("-f, --file <path>", "Read JSON request from file, or - for stdin")
130
+ .option("--json", "Write the unmodified application response to stdout (MCP identifiers unchanged)")
131
+ .addHelpText("after", quoteHelpAfter())
132
+ .action((opts) => wrap(quoteAction)(routerIo(opts)));
133
+ program
134
+ .command("call")
135
+ .description("Execute published tools via the Tool Router (MCP AISA_BATCH_USE)")
136
+ .option("--input <json>", "Inline JSON request body, same shape as quote (no file required)")
137
+ .option("-f, --file <path>", "Read JSON request from file, or - for stdin")
138
+ .option("--json", "Write the unmodified application response to stdout (MCP identifiers unchanged)")
139
+ .addHelpText("after", callHelpAfter())
140
+ .action((opts) => wrap(callAction)(routerIo(opts)));
74
141
  // ── API ──
75
- const api = program.command("api").description("Discover and inspect APIs");
142
+ const api = program.command("api").description("Browse the read-only provider and endpoint catalog");
76
143
  api
77
144
  .command("list")
78
145
  .description("List available APIs")
@@ -81,14 +148,6 @@ api
81
148
  .option("--json", "Output raw JSON")
82
149
  .option("--refresh", "Bypass the cached catalog")
83
150
  .action(wrap(apiListAction));
84
- api
85
- .command("search <query>")
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")
91
- .action(wrap(apiSearchAction));
92
151
  api
93
152
  .command("show <api> [path]")
94
153
  .description("Show an API's endpoints, or one endpoint's details")
@@ -98,35 +157,6 @@ api
98
157
  .option("--json", "Output raw JSON")
99
158
  .option("--refresh", "Bypass the cached catalog")
100
159
  .action(wrap(apiShowAction));
101
- api
102
- .command("code <slug> <path>")
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")
107
- .action(wrap(apiCodeAction));
108
- // ── Run ──
109
- program
110
- .command("run <slug> <path>")
111
- .description("Execute an API call")
112
- .option("-q, --query <params...>", "Query parameters (key=value)")
113
- .option("-d, --data <json>", "JSON request body")
114
- .option("--method <method>", "HTTP method")
115
- .option("--raw", "Raw JSON output")
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)")
120
- .action((slug, path, opts) => wrap(runAction)(slug, path, {
121
- q: opts.query,
122
- d: opts.data,
123
- method: opts.method,
124
- raw: opts.raw,
125
- stream: opts.stream,
126
- llm: opts.llm,
127
- domain: opts.domain,
128
- showCost: opts.showCost,
129
- }));
130
160
  // ── Chat (LLM Gateway) ──
131
161
  program
132
162
  .command("chat [message]")
@@ -149,288 +179,6 @@ models
149
179
  .command("show <model-id>")
150
180
  .description("Show model details and pricing")
151
181
  .action(wrap(modelsShowAction));
152
- // ── Search shortcuts ──
153
- program
154
- .command("web-search <query>")
155
- .description("Search the web")
156
- .option("--type <type>", "Search type: tavily, youtube, scholar, smart (degraded), full (degraded)", "tavily")
157
- .option("--limit <n>", "Max results")
158
- .option("--raw", "Raw JSON output")
159
- .action(wrap(webSearchAction));
160
- program
161
- .command("scholar <query>")
162
- .description("Search academic papers")
163
- .option("--limit <n>", "Max results")
164
- .option("--raw", "Raw JSON output")
165
- .action(wrap(scholarAction));
166
- // ── Finance shortcuts ──
167
- program
168
- .command("stock <symbol>")
169
- .description("Look up stock data")
170
- .option("--field <field>", "Data field: info, estimates, financials, filings, insider, institutional, news")
171
- .option("--raw", "Raw JSON output")
172
- .action(wrap(stockAction));
173
- program
174
- .command("crypto <symbol>")
175
- .description("Look up crypto price")
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")
179
- .option("--raw", "Raw JSON output")
180
- .action(wrap(cryptoAction));
181
- program
182
- .command("screener")
183
- .description("Screen stocks by criteria")
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)")
187
- .option("--limit <n>", "Max results")
188
- .option("--raw", "Raw JSON output")
189
- .action(wrap(screenerAction));
190
- // ── Twitter shortcuts ──
191
- program
192
- .command("tweet <text>")
193
- .description("Post a tweet (requires twitter login)")
194
- .option("--reply-to <id>", "Reply to tweet ID")
195
- .option("--media-ids <ids>", "Comma-separated media IDs")
196
- .option("--raw", "Raw JSON output")
197
- .action(wrap(tweetAction));
198
- const twitter = program.command("twitter").description("Twitter/X operations");
199
- // Auth
200
- twitter
201
- .command("login")
202
- .description("Login to Twitter or import cookies")
203
- .option("--username <name>", "Twitter username")
204
- .option("--email <email>", "Account email")
205
- .option("--password <pass>", "Account password")
206
- .option("--proxy <url>", "Proxy URL (required)")
207
- .option("--totp <secret>", "2FA TOTP secret")
208
- .option("--cookies <cookies>", "Import login_cookies directly")
209
- .option("--raw", "Raw JSON output")
210
- .action(wrap(twitterLoginAction));
211
- twitter
212
- .command("logout")
213
- .description("Clear stored Twitter cookies")
214
- .action(twitterLogoutAction);
215
- // User read
216
- twitter
217
- .command("user <username>")
218
- .description("Get user profile")
219
- .option("--raw", "Raw JSON output")
220
- .action(wrap(twitterUserAction));
221
- twitter
222
- .command("user-about <username>")
223
- .description("Get user profile details (country, verification, name history)")
224
- .option("--raw", "Raw JSON output")
225
- .action(wrap(twitterUserAboutAction));
226
- twitter
227
- .command("batch-users <ids>")
228
- .description("Get multiple users by comma-separated IDs")
229
- .option("--raw", "Raw JSON output")
230
- .action(wrap(twitterBatchUsersAction));
231
- twitter
232
- .command("user-tweets <username>")
233
- .description("Get user's recent tweets")
234
- .option("--cursor <cursor>", "Pagination cursor")
235
- .option("--raw", "Raw JSON output")
236
- .action(wrap(twitterUserTweetsAction));
237
- twitter
238
- .command("mentions <username>")
239
- .description("Get user mentions")
240
- .option("--cursor <cursor>", "Pagination cursor")
241
- .option("--raw", "Raw JSON output")
242
- .action(wrap(twitterMentionsAction));
243
- twitter
244
- .command("followers <username>")
245
- .description("Get user followers")
246
- .option("--cursor <cursor>", "Pagination cursor")
247
- .option("--raw", "Raw JSON output")
248
- .action(wrap(twitterFollowersAction));
249
- twitter
250
- .command("following <username>")
251
- .description("Get user followings")
252
- .option("--cursor <cursor>", "Pagination cursor")
253
- .option("--raw", "Raw JSON output")
254
- .action(wrap(twitterFollowingAction));
255
- twitter
256
- .command("verified-followers <user-id>")
257
- .description("Get verified followers (requires user ID)")
258
- .option("--cursor <cursor>", "Pagination cursor")
259
- .option("--raw", "Raw JSON output")
260
- .action(wrap(twitterVerifiedFollowersAction));
261
- twitter
262
- .command("check-follow <source> <target>")
263
- .description("Check follow relationship between two usernames")
264
- .option("--raw", "Raw JSON output")
265
- .action(wrap(twitterCheckFollowAction));
266
- twitter
267
- .command("user-search <query>")
268
- .description("Search users by keyword")
269
- .option("--cursor <cursor>", "Pagination cursor")
270
- .option("--raw", "Raw JSON output")
271
- .action(wrap(twitterUserSearchAction));
272
- // Tweet read
273
- twitter
274
- .command("search <query>")
275
- .description("Search tweets")
276
- .option("--type <type>", "Query type: latest or top", "latest")
277
- .option("--limit <n>", "Max results")
278
- .option("--cursor <cursor>", "Pagination cursor")
279
- .option("--raw", "Raw JSON output")
280
- .action(wrap(twitterSearchAction));
281
- twitter
282
- .command("detail <ids>")
283
- .description("Get tweets by comma-separated IDs")
284
- .option("--raw", "Raw JSON output")
285
- .action(wrap(twitterDetailAction));
286
- twitter
287
- .command("replies <tweet-id>")
288
- .description("Get tweet replies")
289
- .option("--cursor <cursor>", "Pagination cursor")
290
- .option("--raw", "Raw JSON output")
291
- .action(wrap(twitterRepliesAction));
292
- twitter
293
- .command("quotes <tweet-id>")
294
- .description("Get tweet quotes")
295
- .option("--cursor <cursor>", "Pagination cursor")
296
- .option("--raw", "Raw JSON output")
297
- .action(wrap(twitterQuotesAction));
298
- twitter
299
- .command("retweeters <tweet-id>")
300
- .description("Get tweet retweeters")
301
- .option("--cursor <cursor>", "Pagination cursor")
302
- .option("--raw", "Raw JSON output")
303
- .action(wrap(twitterRetweetersAction));
304
- twitter
305
- .command("thread <tweet-id>")
306
- .description("Get full conversation thread")
307
- .option("--cursor <cursor>", "Pagination cursor")
308
- .option("--raw", "Raw JSON output")
309
- .action(wrap(twitterThreadAction));
310
- twitter
311
- .command("article <tweet-id>")
312
- .description("Get article content by tweet ID")
313
- .option("--raw", "Raw JSON output")
314
- .action(wrap(twitterArticleAction));
315
- // Trends
316
- twitter
317
- .command("trends")
318
- .description("Get trending topics")
319
- .option("--woeid <id>", "Location WOEID (1 = worldwide)", "1")
320
- .option("--count <n>", "Number of trends")
321
- .option("--raw", "Raw JSON output")
322
- .action(wrap(twitterTrendsAction));
323
- // Lists
324
- twitter
325
- .command("list-members <list-id>")
326
- .description("Get list members")
327
- .option("--cursor <cursor>", "Pagination cursor")
328
- .option("--raw", "Raw JSON output")
329
- .action(wrap(twitterListMembersAction));
330
- twitter
331
- .command("list-followers <list-id>")
332
- .description("Get list followers")
333
- .option("--cursor <cursor>", "Pagination cursor")
334
- .option("--raw", "Raw JSON output")
335
- .action(wrap(twitterListFollowersAction));
336
- // Communities
337
- twitter
338
- .command("community-info <community-id>")
339
- .description("Get community info")
340
- .option("--raw", "Raw JSON output")
341
- .action(wrap(twitterCommunityInfoAction));
342
- twitter
343
- .command("community-members <community-id>")
344
- .description("Get community members")
345
- .option("--cursor <cursor>", "Pagination cursor")
346
- .option("--raw", "Raw JSON output")
347
- .action(wrap(twitterCommunityMembersAction));
348
- twitter
349
- .command("community-mods <community-id>")
350
- .description("Get community moderators")
351
- .option("--cursor <cursor>", "Pagination cursor")
352
- .option("--raw", "Raw JSON output")
353
- .action(wrap(twitterCommunityModsAction));
354
- twitter
355
- .command("community-tweets <community-id>")
356
- .description("Get community tweets")
357
- .option("--cursor <cursor>", "Pagination cursor")
358
- .option("--raw", "Raw JSON output")
359
- .action(wrap(twitterCommunityTweetsAction));
360
- twitter
361
- .command("community-search <query>")
362
- .description("Search tweets across all communities")
363
- .option("--cursor <cursor>", "Pagination cursor")
364
- .option("--raw", "Raw JSON output")
365
- .action(wrap(twitterCommunitySearchAction));
366
- // Spaces
367
- twitter
368
- .command("space <space-id>")
369
- .description("Get Space details")
370
- .option("--raw", "Raw JSON output")
371
- .action(wrap(twitterSpaceAction));
372
- // Write operations
373
- twitter
374
- .command("like <tweet-id>")
375
- .description("Like a tweet")
376
- .option("--raw", "Raw JSON output")
377
- .action(wrap(twitterLikeAction));
378
- twitter
379
- .command("unlike <tweet-id>")
380
- .description("Unlike a tweet")
381
- .option("--raw", "Raw JSON output")
382
- .action(wrap(twitterUnlikeAction));
383
- twitter
384
- .command("retweet <tweet-id>")
385
- .description("Retweet a tweet")
386
- .option("--raw", "Raw JSON output")
387
- .action(wrap(twitterRetweetAction));
388
- twitter
389
- .command("delete <tweet-id>")
390
- .description("Delete a tweet")
391
- .option("--raw", "Raw JSON output")
392
- .action(wrap(twitterDeleteAction));
393
- twitter
394
- .command("follow <user-id>")
395
- .description("Follow a user (requires user ID)")
396
- .option("--raw", "Raw JSON output")
397
- .action(wrap(twitterFollowAction));
398
- twitter
399
- .command("unfollow <user-id>")
400
- .description("Unfollow a user (requires user ID)")
401
- .option("--raw", "Raw JSON output")
402
- .action(wrap(twitterUnfollowAction));
403
- twitter
404
- .command("upload-media <file-path>")
405
- .description("Upload media file for tweets")
406
- .option("--raw", "Raw JSON output")
407
- .action(wrap(twitterUploadMediaAction));
408
- twitter
409
- .command("dm <user-id> <text>")
410
- .description("Send a direct message")
411
- .option("--raw", "Raw JSON output")
412
- .action(wrap(twitterDmAction));
413
- // ── Video shortcuts ──
414
- const video = program.command("video").description("AI video generation");
415
- video
416
- .command("create <prompt>")
417
- .description("Create a video generation task")
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)")
424
- .option("--wait", "Wait for completion")
425
- .option("--output <path>", "Download the finished video to this path (implies --wait)")
426
- .option("--raw", "Raw JSON output")
427
- .action((prompt, opts) => wrap(videoCreateAction)(prompt, { ...opts, wait: Boolean(opts.wait || opts.output) }));
428
- video
429
- .command("status <task-id>")
430
- .description("Check video task status")
431
- .option("--output <path>", "Download the finished video to this path")
432
- .option("--raw", "Raw JSON output")
433
- .action(wrap(videoStatusAction));
434
182
  // ── Skills ──
435
183
  const skills = program.command("skills").description("Browse and manage agent skills");
436
184
  skills
@@ -469,12 +217,32 @@ skills
469
217
  .option("--bare", "Minimal template")
470
218
  .action(skillsInitAction);
471
219
  // ── MCP ──
220
+ // Top-level so the zero-install one-liner works: `npx @aisa-one/cli connect`.
221
+ program
222
+ .command("connect")
223
+ .description("Connect AIsa MCP servers to your local coding agents via a one-shot local page")
224
+ .option("--no-open", "Print the URL instead of opening the browser")
225
+ .option("--port <port>", "Bind a specific port (default: random)")
226
+ .option("--dry-run", "Show what would be configured without writing anything")
227
+ .option("--template <id>", "Page template: t2 (guided steps, default) or t1 (classic two-page)")
228
+ .option("--force", "Start a new run even if another one is still open")
229
+ .option("--lang <lang>", "Page and terminal language: en or zh (default: your system locale)")
230
+ .option("--headless", "Skip the page entirely (a machine without a browser is detected on its own)")
231
+ // Hidden: how a run that was interrupted at the terminal picks itself back
232
+ // up in a detached process, so the page it opened keeps working.
233
+ .addOption(new Option("--resume <file>").hideHelp())
234
+ .action(wrap(connectAction));
235
+ program
236
+ .command("update")
237
+ .description("Update the AIsa CLI to the latest published version")
238
+ .action(wrap(updateAction));
472
239
  const mcp = program.command("mcp").description("MCP server integration");
473
240
  mcp
474
241
  .command("setup")
475
242
  .description("Configure AIsa MCP servers (from the live manifest) for AI agents")
476
- .option("--agent <agent>", "Target agent: cursor, claude-desktop, windsurf, all")
243
+ .option("--agent <agent>", "Target agent: cursor, claude-desktop, all")
477
244
  .option("--all", "Configure every live server, not just the default set")
245
+ .option("--yes", "Write the files. Without it, print what would change and stop")
478
246
  .action(mcpSetupAction);
479
247
  mcp
480
248
  .command("status")
@@ -498,21 +266,6 @@ configCmd
498
266
  .command("reset")
499
267
  .description("Reset config to defaults")
500
268
  .action(configResetAction);
501
- // ── Top-level aliases ──
502
- program
503
- .command("search <query>")
504
- .description("Search APIs (alias for 'api search')")
505
- .option("--provider <id>", "Restrict to one API")
506
- .option("--limit <n>", "Max results", "20")
507
- .option("--json", "Output raw JSON")
508
- .option("--refresh", "Bypass the cached catalog")
509
- .action(wrap(apiSearchAction));
510
- program
511
- .command("code <slug> <path>")
512
- .description("Generate a request snippet (alias for 'api code')")
513
- .option("--lang <language>", "Language: curl, python, node, typescript", "curl")
514
- .option("--method <method>", "HTTP method")
515
- .action(wrap(apiCodeAction));
516
269
  const cache = program.command("cache").description("Manage the local catalog and skills cache");
517
270
  cache
518
271
  .command("clear")
@@ -523,6 +276,22 @@ cache
523
276
  .description("Print the cache directory")
524
277
  .action(cachePathAction);
525
278
  // ── Shell completion ──
279
+ // The whole tree as JSON. Agents get one shot at a top-level dump, and the
280
+ // default help renders every subcommand as a bare `[options]`.
281
+ // Hidden: started by `connect` when the user asks for the terminal back but
282
+ // the results page should outlive it. Serves that one page and nothing else.
283
+ program
284
+ .command("__serve-results <file>", { hidden: true })
285
+ .action(wrap(serveResultsAction));
286
+ // Hidden: started by `login` so the page the browser landed on survives a
287
+ // refresh after the terminal has been handed back.
288
+ program
289
+ .command("__serve-signin <port> <until>", { hidden: true })
290
+ .action(wrap(serveSignInAction));
291
+ program
292
+ .command("manifest [command...]")
293
+ .description("Print commands, arguments and flags as JSON (for agents and scripts)")
294
+ .action((path = []) => manifestAction(program, path));
526
295
  program
527
296
  .command("completion [shell]")
528
297
  .description("Print a shell completion script (bash, zsh, fish)")
@@ -534,5 +303,33 @@ program
534
303
  .allowUnknownOption()
535
304
  .allowExcessArguments()
536
305
  .action((words = []) => completeAction(program, words));
306
+ /**
307
+ * Point every help page at the manifest.
308
+ *
309
+ * Not the flags themselves: `git`, `docker`, `gh` and `npm` all list
310
+ * subcommands as name-plus-description, because that page's job is choosing a
311
+ * command, not calling one. Printing flags there breaks a convention every
312
+ * developer has a reflex for, and would still be truncated on the longest
313
+ * entries — so a reader who needs the full set has to drill in anyway.
314
+ *
315
+ * One line is enough for the reader who cannot drill in cheaply. Given only
316
+ * `aisa --help`, an LLM invented `--json` (the flag is `--raw`); given the
317
+ * same page plus this line, it ran `aisa manifest` first instead of guessing,
318
+ * saying outright that guessing risked an error. Measured 2026-08-24.
319
+ */
320
+ function applyHelpStyle(cmd) {
321
+ if (cmd.commands.length > 0) {
322
+ // Advertise the narrow form: the whole tree is ~15k tokens, one subtree
323
+ // is a fraction of that, and an agent reads whichever it is shown.
324
+ const scope = cmd.parent ? ` ${cmd.name()}` : " [command]";
325
+ cmd.addHelpText("after", `\nAgents: \`aisa manifest${scope}\` prints these commands, arguments and flags as JSON.`);
326
+ }
327
+ for (const c of cmd.commands)
328
+ applyHelpStyle(c);
329
+ }
330
+ program.addHelpText("after", rootHelpAfter());
331
+ // Last, after the human-facing examples: it is the line an agent scanning to
332
+ // the end of the page will find.
333
+ applyHelpStyle(program);
537
334
  // ── Parse ──
538
335
  program.parse();
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Parse application JSON while keeping number tokens as strings at their
3
+ * structural locations. Strings are copied with escapes so digits inside
4
+ * quotes are not treated as numbers.
5
+ *
6
+ * `--json` must keep using the original raw body; this is only for human
7
+ * rendering and local inspection.
8
+ */
9
+ export declare function parseJsonKeepingNumberTokens(source: string): unknown;
10
+ export declare function quoteNumberTokens(source: string): string;
11
+ /** Exact token from a value produced by parseJsonKeepingNumberTokens. */
12
+ export declare function numberToken(value: unknown): string | undefined;