@tolinax/ayoune-cli 2026.2.1 → 2026.2.2

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 (78) hide show
  1. package/data/defaultActions.js +9 -0
  2. package/data/modelsAndRights.js +3189 -0
  3. package/data/modules.js +111 -0
  4. package/data/operations.js +5 -0
  5. package/data/services.js +139 -0
  6. package/lib/api/apiCallHandler.js +68 -0
  7. package/lib/api/apiClient.js +100 -0
  8. package/lib/api/auditCallHandler.js +21 -0
  9. package/lib/api/decodeToken.js +4 -0
  10. package/lib/api/handleAPIError.js +59 -0
  11. package/lib/api/login.js +45 -0
  12. package/lib/commands/createActionsCommand.js +109 -0
  13. package/lib/commands/createAiCommand.js +188 -0
  14. package/lib/commands/createAliasCommand.js +106 -0
  15. package/lib/commands/createAuditCommand.js +49 -0
  16. package/lib/commands/createCompletionsCommand.js +136 -0
  17. package/lib/commands/createConfigCommand.js +208 -0
  18. package/lib/commands/createCopyCommand.js +39 -0
  19. package/lib/commands/createCreateCommand.js +50 -0
  20. package/lib/commands/createDeployCommand.js +666 -0
  21. package/lib/commands/createDescribeCommand.js +42 -0
  22. package/lib/commands/createEditCommand.js +43 -0
  23. package/lib/commands/createEventsCommand.js +60 -0
  24. package/lib/commands/createExecCommand.js +182 -0
  25. package/lib/commands/createGetCommand.js +47 -0
  26. package/lib/commands/createListCommand.js +49 -0
  27. package/lib/commands/createLoginCommand.js +18 -0
  28. package/lib/commands/createLogoutCommand.js +21 -0
  29. package/lib/commands/createModulesCommand.js +89 -0
  30. package/lib/commands/createMonitorCommand.js +283 -0
  31. package/lib/commands/createProgram.js +163 -0
  32. package/lib/commands/createServicesCommand.js +228 -0
  33. package/lib/commands/createStorageCommand.js +54 -0
  34. package/lib/commands/createStreamCommand.js +50 -0
  35. package/lib/commands/createWhoAmICommand.js +88 -0
  36. package/lib/exitCodes.js +6 -0
  37. package/lib/helpers/addSpacesToCamelCase.js +5 -0
  38. package/lib/helpers/config.js +6 -0
  39. package/lib/helpers/configLoader.js +60 -0
  40. package/lib/helpers/formatDocument.js +176 -0
  41. package/lib/helpers/handleResponseFormatOptions.js +85 -0
  42. package/lib/helpers/initializeSettings.js +14 -0
  43. package/lib/helpers/localStorage.js +4 -0
  44. package/lib/helpers/makeRandomToken.js +27 -0
  45. package/lib/helpers/parseInt.js +7 -0
  46. package/lib/helpers/requireArg.js +9 -0
  47. package/lib/helpers/saveFile.js +39 -0
  48. package/lib/models/getCollections.js +15 -0
  49. package/lib/models/getModelsInModules.js +13 -0
  50. package/lib/models/getModuleFromCollection.js +7 -0
  51. package/lib/operations/handleAuditOperation.js +22 -0
  52. package/lib/operations/handleCollectionOperation.js +91 -0
  53. package/lib/operations/handleCopySingleOperation.js +22 -0
  54. package/lib/operations/handleCreateSingleOperation.js +35 -0
  55. package/lib/operations/handleDeleteSingleOperation.js +14 -0
  56. package/lib/operations/handleDescribeSingleOperation.js +22 -0
  57. package/lib/operations/handleEditOperation.js +51 -0
  58. package/lib/operations/handleEditRawOperation.js +35 -0
  59. package/lib/operations/handleGetOperation.js +29 -0
  60. package/lib/operations/handleGetSingleOperation.js +20 -0
  61. package/lib/operations/handleListOperation.js +63 -0
  62. package/lib/operations/handleSingleAuditOperation.js +27 -0
  63. package/lib/prompts/promptAudits.js +15 -0
  64. package/lib/prompts/promptCollection.js +13 -0
  65. package/lib/prompts/promptCollectionInModule.js +13 -0
  66. package/lib/prompts/promptCollectionWithModule.js +15 -0
  67. package/lib/prompts/promptConfirm.js +12 -0
  68. package/lib/prompts/promptDefaultAction.js +13 -0
  69. package/lib/prompts/promptEntry.js +19 -0
  70. package/lib/prompts/promptFileName.js +12 -0
  71. package/lib/prompts/promptFilePath.js +18 -0
  72. package/lib/prompts/promptModule.js +19 -0
  73. package/lib/prompts/promptName.js +11 -0
  74. package/lib/prompts/promptOperation.js +13 -0
  75. package/lib/socket/customerSocketClient.js +13 -0
  76. package/lib/socket/socketClient.js +12 -0
  77. package/lib/types.js +1 -0
  78. package/package.json +2 -2
@@ -0,0 +1,283 @@
1
+ import { apiCallHandler } from "../api/apiCallHandler.js";
2
+ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
3
+ import { saveFile } from "../helpers/saveFile.js";
4
+ import { spinner } from "../../index.js";
5
+ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
6
+ export function createMonitorCommand(program) {
7
+ const monitor = program
8
+ .command("monitor")
9
+ .alias("mon")
10
+ .description("Monitor platform activity, logs, and alerts");
11
+ // ay monitor logs [type]
12
+ monitor
13
+ .command("logs [type]")
14
+ .description("List recent platform logs (api, error, mail, ai, trigger, ...)")
15
+ .addHelpText("after", `
16
+ Log types: api, error, mail, ai, trigger, doi, export, sms, whatsapp, production, setup, state, shop, score, sensor, stock, soi, reward, merge, download, post, webreceiver, work, computingentitieslogs, consumerapi, accessterminal, googleads
17
+
18
+ Examples:
19
+ ay monitor logs error List recent error logs
20
+ ay monitor logs api -l 10 List last 10 API logs
21
+ ay monitor logs ai -r table List AI logs in table format`)
22
+ .option("-l, --limit <number>", "Limit results", parseInt, 25)
23
+ .option("-p, --page <number>", "Page number", parseInt, 1)
24
+ .option("--sort <field>", "Sort by field", "-createdAt")
25
+ .action(async (type, options) => {
26
+ var _a, _b, _c;
27
+ try {
28
+ const opts = { ...program.opts(), ...options };
29
+ const logType = type || "api";
30
+ const collectionMap = {
31
+ api: "apilogs",
32
+ error: "errorlogs",
33
+ mail: "maillogs",
34
+ ai: "ailogs",
35
+ trigger: "triggerlogs",
36
+ doi: "doilogs",
37
+ export: "exportlogs",
38
+ sms: "smslogs",
39
+ whatsapp: "whatsapplogs",
40
+ production: "productionlogs",
41
+ setup: "setuplogs",
42
+ state: "statelogs",
43
+ shop: "shoplogs",
44
+ score: "scorelogs",
45
+ sensor: "sensorlogs",
46
+ stock: "stocklogs",
47
+ soi: "soilogs",
48
+ reward: "rewardlogs",
49
+ merge: "mergelogs",
50
+ download: "downloadlogs",
51
+ post: "postlogs",
52
+ webreceiver: "webreceiverlogs",
53
+ work: "worklogs",
54
+ consumerapi: "consumerapilogs",
55
+ accessterminal: "accessterminallogs",
56
+ googleads: "adwordslogs",
57
+ computing: "computingentitieslogs",
58
+ };
59
+ const collection = collectionMap[logType] || `${logType}logs`;
60
+ spinner.start({ text: `Fetching ${logType} logs...`, color: "magenta" });
61
+ const res = await apiCallHandler("logs", collection, "get", null, {
62
+ page: opts.page,
63
+ limit: opts.limit,
64
+ sort: opts.sort,
65
+ responseFormat: opts.responseFormat,
66
+ verbosity: opts.verbosity,
67
+ hideMeta: opts.hideMeta,
68
+ });
69
+ handleResponseFormatOptions(opts, res);
70
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
71
+ spinner.success({ text: `Found ${total} ${logType} log entries` });
72
+ spinner.stop();
73
+ if (opts.save)
74
+ await saveFile(`monitor-logs-${logType}`, opts, res);
75
+ }
76
+ catch (e) {
77
+ spinner.error({ text: e.message || "Failed to fetch logs" });
78
+ process.exit(EXIT_GENERAL_ERROR);
79
+ }
80
+ });
81
+ // ay monitor alerts — command group
82
+ const alerts = monitor
83
+ .command("alerts")
84
+ .description("Manage platform alerts (list, acknowledge, resolve)");
85
+ // ay monitor alerts list
86
+ alerts
87
+ .command("list")
88
+ .alias("ls")
89
+ .description("List active alerts")
90
+ .addHelpText("after", `
91
+ Examples:
92
+ ay monitor alerts list List all active alerts
93
+ ay monitor alerts list --severity critical Show critical alerts only
94
+ ay monitor alerts list --type pod_crash Filter by alert type
95
+ ay monitor alerts list --status acknowledged Show acknowledged alerts`)
96
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
97
+ .option("-p, --page <number>", "Page number", parseInt, 1)
98
+ .option("--severity <level>", "Filter: info, warning, critical")
99
+ .option("--type <type>", "Filter: pod_crash, oom_killed, image_pull_error, deployment_failed, pipeline_failed, cluster_unreachable, high_restart_count, custom")
100
+ .option("--status <status>", "Filter: active, acknowledged, resolved", "active")
101
+ .action(async (options) => {
102
+ var _a, _b, _c;
103
+ try {
104
+ const opts = { ...program.opts(), ...options };
105
+ spinner.start({ text: "Fetching alerts...", color: "magenta" });
106
+ const params = {
107
+ page: opts.page,
108
+ limit: opts.limit,
109
+ responseFormat: opts.responseFormat,
110
+ verbosity: opts.verbosity,
111
+ hideMeta: opts.hideMeta,
112
+ };
113
+ if (opts.severity)
114
+ params.severity = opts.severity;
115
+ if (opts.type)
116
+ params.type = opts.type;
117
+ if (opts.status)
118
+ params.status = opts.status;
119
+ const res = await apiCallHandler("devops", "alerts", "get", null, params);
120
+ handleResponseFormatOptions(opts, res);
121
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
122
+ spinner.success({ text: `Found ${total} alerts` });
123
+ spinner.stop();
124
+ if (opts.save)
125
+ await saveFile("monitor-alerts", opts, res);
126
+ }
127
+ catch (e) {
128
+ spinner.error({ text: e.message || "Failed to fetch alerts" });
129
+ process.exit(EXIT_GENERAL_ERROR);
130
+ }
131
+ });
132
+ // ay monitor alerts ack <id>
133
+ alerts
134
+ .command("ack <id>")
135
+ .alias("acknowledge")
136
+ .description("Acknowledge an alert")
137
+ .action(async (id, options) => {
138
+ try {
139
+ const opts = { ...program.opts(), ...options };
140
+ spinner.start({ text: `Acknowledging alert ${id}...`, color: "magenta" });
141
+ const res = await apiCallHandler("devops", `alerts/${id}/acknowledge`, "put", null, {
142
+ responseFormat: opts.responseFormat,
143
+ });
144
+ handleResponseFormatOptions(opts, res);
145
+ spinner.success({ text: `Alert ${id} acknowledged` });
146
+ spinner.stop();
147
+ }
148
+ catch (e) {
149
+ spinner.error({ text: e.message || "Failed to acknowledge alert" });
150
+ process.exit(EXIT_GENERAL_ERROR);
151
+ }
152
+ });
153
+ // ay monitor alerts resolve <id>
154
+ alerts
155
+ .command("resolve <id>")
156
+ .description("Resolve an alert")
157
+ .action(async (id, options) => {
158
+ try {
159
+ const opts = { ...program.opts(), ...options };
160
+ spinner.start({ text: `Resolving alert ${id}...`, color: "magenta" });
161
+ const res = await apiCallHandler("devops", `alerts/${id}/resolve`, "put", null, {
162
+ responseFormat: opts.responseFormat,
163
+ });
164
+ handleResponseFormatOptions(opts, res);
165
+ spinner.success({ text: `Alert ${id} resolved` });
166
+ spinner.stop();
167
+ }
168
+ catch (e) {
169
+ spinner.error({ text: e.message || "Failed to resolve alert" });
170
+ process.exit(EXIT_GENERAL_ERROR);
171
+ }
172
+ });
173
+ // ay monitor sessions
174
+ monitor
175
+ .command("sessions")
176
+ .description("List active user sessions")
177
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
178
+ .action(async (options) => {
179
+ var _a, _b, _c;
180
+ try {
181
+ const opts = { ...program.opts(), ...options };
182
+ spinner.start({ text: "Fetching active sessions...", color: "magenta" });
183
+ const res = await apiCallHandler("monitoring", "sessions", "get", null, {
184
+ limit: opts.limit,
185
+ responseFormat: opts.responseFormat,
186
+ verbosity: opts.verbosity,
187
+ });
188
+ handleResponseFormatOptions(opts, res);
189
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
190
+ spinner.success({ text: `Found ${total} active sessions` });
191
+ spinner.stop();
192
+ if (opts.save)
193
+ await saveFile("monitor-sessions", opts, res);
194
+ }
195
+ catch (e) {
196
+ spinner.error({ text: e.message || "Failed to fetch sessions" });
197
+ process.exit(EXIT_GENERAL_ERROR);
198
+ }
199
+ });
200
+ // ay monitor checks
201
+ monitor
202
+ .command("checks")
203
+ .description("List monitoring checks and their results")
204
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
205
+ .action(async (options) => {
206
+ var _a, _b, _c;
207
+ try {
208
+ const opts = { ...program.opts(), ...options };
209
+ spinner.start({ text: "Fetching monitoring checks...", color: "magenta" });
210
+ const res = await apiCallHandler("monitoring", "checks", "get", null, {
211
+ limit: opts.limit,
212
+ responseFormat: opts.responseFormat,
213
+ verbosity: opts.verbosity,
214
+ });
215
+ handleResponseFormatOptions(opts, res);
216
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
217
+ spinner.success({ text: `Found ${total} monitoring checks` });
218
+ spinner.stop();
219
+ if (opts.save)
220
+ await saveFile("monitor-checks", opts, res);
221
+ }
222
+ catch (e) {
223
+ spinner.error({ text: e.message || "Failed to fetch checks" });
224
+ process.exit(EXIT_GENERAL_ERROR);
225
+ }
226
+ });
227
+ // ay monitor activeusers
228
+ monitor
229
+ .command("activeusers")
230
+ .alias("users")
231
+ .description("Show currently active users on the platform")
232
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
233
+ .action(async (options) => {
234
+ var _a, _b, _c;
235
+ try {
236
+ const opts = { ...program.opts(), ...options };
237
+ spinner.start({ text: "Fetching active users...", color: "magenta" });
238
+ const res = await apiCallHandler("monitoring", "activeusers", "get", null, {
239
+ limit: opts.limit,
240
+ responseFormat: opts.responseFormat,
241
+ verbosity: opts.verbosity,
242
+ });
243
+ handleResponseFormatOptions(opts, res);
244
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
245
+ spinner.success({ text: `${total} active users` });
246
+ spinner.stop();
247
+ if (opts.save)
248
+ await saveFile("monitor-activeusers", opts, res);
249
+ }
250
+ catch (e) {
251
+ spinner.error({ text: e.message || "Failed to fetch active users" });
252
+ process.exit(EXIT_GENERAL_ERROR);
253
+ }
254
+ });
255
+ // ay monitor pagestats
256
+ monitor
257
+ .command("pagestats")
258
+ .alias("pages")
259
+ .description("View page view statistics")
260
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
261
+ .action(async (options) => {
262
+ var _a, _b, _c;
263
+ try {
264
+ const opts = { ...program.opts(), ...options };
265
+ spinner.start({ text: "Fetching page statistics...", color: "magenta" });
266
+ const res = await apiCallHandler("monitoring", "pagestats", "get", null, {
267
+ limit: opts.limit,
268
+ responseFormat: opts.responseFormat,
269
+ verbosity: opts.verbosity,
270
+ });
271
+ handleResponseFormatOptions(opts, res);
272
+ const total = (_c = (_b = (_a = res.meta) === null || _a === void 0 ? void 0 : _a.pageInfo) === null || _b === void 0 ? void 0 : _b.totalEntries) !== null && _c !== void 0 ? _c : 0;
273
+ spinner.success({ text: `Found ${total} page stat entries` });
274
+ spinner.stop();
275
+ if (opts.save)
276
+ await saveFile("monitor-pagestats", opts, res);
277
+ }
278
+ catch (e) {
279
+ spinner.error({ text: e.message || "Failed to fetch page stats" });
280
+ process.exit(EXIT_GENERAL_ERROR);
281
+ }
282
+ });
283
+ }
@@ -0,0 +1,163 @@
1
+ //Defines the main program structure for command line interface
2
+ import { Option } from "commander";
3
+ import chalk from "chalk";
4
+ import path from "path";
5
+ import os from "os";
6
+ import { spinner } from "../../index.js";
7
+ import { createModulesCommand } from "./createModulesCommand.js";
8
+ import { createListCommand } from "./createListCommand.js";
9
+ import { createGetCommand } from "./createGetCommand.js";
10
+ import { createEditCommand } from "./createEditCommand.js";
11
+ import { createLoginCommand } from "./createLoginCommand.js";
12
+ import { createDescribeCommand } from "./createDescribeCommand.js";
13
+ import { createCopyCommand } from "./createCopyCommand.js";
14
+ import { createCreateCommand } from "./createCreateCommand.js";
15
+ import { createStorageCommand } from "./createStorageCommand.js";
16
+ import { createAuditCommand } from "./createAuditCommand.js";
17
+ import { createStreamCommand } from "./createStreamCommand.js";
18
+ import { createEventsCommand } from "./createEventsCommand.js";
19
+ import { createWhoAmICommand } from "./createWhoAmICommand.js";
20
+ import { createLogoutCommand } from "./createLogoutCommand.js";
21
+ import { createCompletionsCommand } from "./createCompletionsCommand.js";
22
+ import { createAliasCommand, registerUserAliases } from "./createAliasCommand.js";
23
+ import { createConfigCommand } from "./createConfigCommand.js";
24
+ import { createActionsCommand } from "./createActionsCommand.js";
25
+ import { createExecCommand } from "./createExecCommand.js";
26
+ import { createAiCommand } from "./createAiCommand.js";
27
+ import { enableDebug } from "../api/apiClient.js";
28
+ import { enableDryRun } from "../api/apiCallHandler.js";
29
+ import { enableJsonErrors } from "../api/handleAPIError.js";
30
+ import { createServicesCommand } from "./createServicesCommand.js";
31
+ import { createDeployCommand } from "./createDeployCommand.js";
32
+ import { createMonitorCommand } from "./createMonitorCommand.js";
33
+ import { localStorage } from "../helpers/localStorage.js";
34
+ import { login } from "../api/login.js";
35
+ import { loadConfig } from "../helpers/configLoader.js";
36
+ export function createProgram(program) {
37
+ program
38
+ .version("2024.8.0")
39
+ .addOption(new Option("-r, --responseFormat <format>", "Set the output format")
40
+ .choices(["json", "csv", "yaml", "table"])
41
+ .default("json"))
42
+ .addOption(new Option("-v, --verbosity <level>", "Set the verbosity level of the returned meta information")
43
+ .choices(["default", "extended", "minimal"])
44
+ .default("default")
45
+ .conflicts("hideMeta"))
46
+ .addOption(new Option("-m, --hideMeta", "Returns only the payload without meta information. ")
47
+ .default(false)
48
+ .conflicts("verbosity"))
49
+ .addOption(new Option("-s, --save", "Saves the response as file"))
50
+ .addOption(new Option("-d, --debug", "Show detailed request/response information"))
51
+ .addOption(new Option("-o, --outPath [filePath]", "Lets you set a path").default(path.join(os.homedir(), "aYOUne")))
52
+ .addOption(new Option("-n, --name [fileName]", "Lets you set a filename"))
53
+ .addOption(new Option("-q, --quiet", "Suppress all output except errors and results"))
54
+ .addOption(new Option("--force", "Skip confirmation prompts for destructive actions"))
55
+ .addOption(new Option("--dry-run", "Preview what a command would do without executing"))
56
+ .addOption(new Option("--jq <expression>", "Filter JSON output using JMESPath expression"))
57
+ .addOption(new Option("--columns <fields>", "Comma-separated list of columns to display"))
58
+ .addOption(new Option("--no-color", "Disable colored output"))
59
+ .addOption(new Option("--json-errors", "Output errors as JSON to stderr (for AI agents/scripts)"))
60
+ .description("aYOUne - Business as a Service Command Line Interface");
61
+ program.showHelpAfterError();
62
+ program.showSuggestionAfterError(true);
63
+ createModulesCommand(program);
64
+ createListCommand(program);
65
+ createGetCommand(program);
66
+ createEditCommand(program);
67
+ createCopyCommand(program);
68
+ createDescribeCommand(program);
69
+ createCreateCommand(program);
70
+ createStorageCommand(program);
71
+ createAuditCommand(program);
72
+ createStreamCommand(program);
73
+ createEventsCommand(program);
74
+ createWhoAmICommand(program);
75
+ createLogoutCommand(program);
76
+ createActionsCommand(program);
77
+ createExecCommand(program);
78
+ createAiCommand(program);
79
+ createServicesCommand(program);
80
+ createDeployCommand(program);
81
+ createMonitorCommand(program);
82
+ createCompletionsCommand(program);
83
+ createAliasCommand(program);
84
+ createConfigCommand(program);
85
+ registerUserAliases(program);
86
+ createLoginCommand(program);
87
+ program.addHelpText("beforeAll", `
88
+ __ ______ _ _
89
+ \\ \\ / / __ \\| | | |
90
+ __ \\ \\_/ / | | | | | |_ __ ___
91
+ / _\` \\ /| | | | | | | '_ \\ / _ \\
92
+ | (_| || | | |__| | |__| | | | | __/
93
+ \\__,_||_| \\____/ \\____/|_| |_|\\___|
94
+ `);
95
+ program.configureHelp({
96
+ sortOptions: true,
97
+ sortSubcommands: true,
98
+ showGlobalOptions: true,
99
+ });
100
+ // Respect NO_COLOR env var (no-color.org standard)
101
+ if (process.env.NO_COLOR !== undefined) {
102
+ chalk.level = 0;
103
+ }
104
+ program.hook("preAction", async (thisCommand) => {
105
+ var _a;
106
+ // Apply saved defaults — only when the user didn't pass the flag explicitly
107
+ const config = loadConfig();
108
+ const defaults = (_a = config.defaults) !== null && _a !== void 0 ? _a : {};
109
+ const rawArgs = process.argv.slice(2);
110
+ if (defaults.responseFormat && !rawArgs.some(a => ["-r", "--responseFormat"].includes(a)))
111
+ program.setOptionValue("responseFormat", defaults.responseFormat);
112
+ if (defaults.verbosity && !rawArgs.some(a => ["-v", "--verbosity"].includes(a)))
113
+ program.setOptionValue("verbosity", defaults.verbosity);
114
+ if (defaults.outPath && !rawArgs.some(a => ["-o", "--outPath"].includes(a)))
115
+ program.setOptionValue("outPath", defaults.outPath);
116
+ if (defaults.hideMeta && !rawArgs.some(a => ["-m", "--hideMeta"].includes(a)))
117
+ program.setOptionValue("hideMeta", defaults.hideMeta);
118
+ if (defaults.quiet && !rawArgs.some(a => ["-q", "--quiet"].includes(a)))
119
+ program.setOptionValue("quiet", defaults.quiet);
120
+ if (defaults.force && !rawArgs.some(a => ["--force"].includes(a)))
121
+ program.setOptionValue("force", defaults.force);
122
+ if (defaults.dryRun && !rawArgs.some(a => ["--dry-run"].includes(a)))
123
+ program.setOptionValue("dryRun", defaults.dryRun);
124
+ const opts = program.opts();
125
+ if (opts.color === false) {
126
+ chalk.level = 0;
127
+ }
128
+ if (opts.debug) {
129
+ enableDebug();
130
+ }
131
+ if (opts.dryRun) {
132
+ enableDryRun();
133
+ }
134
+ if (opts.jsonErrors) {
135
+ enableJsonErrors();
136
+ }
137
+ if (opts.quiet) {
138
+ spinner.start = () => spinner;
139
+ spinner.update = () => spinner;
140
+ spinner.success = () => spinner;
141
+ spinner.stop = () => spinner;
142
+ // spinner.error left intact
143
+ }
144
+ // Token from env var (headless/AI agent mode) — takes precedence over stored token
145
+ const envToken = process.env.AYOUNE_TOKEN;
146
+ if (envToken && !localStorage.getItem("token")) {
147
+ localStorage.setItem("token", envToken);
148
+ }
149
+ // First-run onboarding: auto-login if no token stored
150
+ const cmdName = thisCommand.name();
151
+ const skipAuth = ["login", "logout", "whoami", "completions", "alias", "config", "help"];
152
+ if (!skipAuth.includes(cmdName) && process.stdin.isTTY) {
153
+ const token = localStorage.getItem("token");
154
+ if (!token) {
155
+ console.error(chalk.cyan.bold("\n Welcome to aYOUne CLI!\n"));
156
+ console.error(chalk.dim(" You need to authenticate before using this command.\n"));
157
+ await login();
158
+ }
159
+ }
160
+ });
161
+ //Parse command line arguments
162
+ program.parse(process.argv);
163
+ }
@@ -0,0 +1,228 @@
1
+ import { apiCallHandler } from "../api/apiCallHandler.js";
2
+ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
3
+ import { saveFile } from "../helpers/saveFile.js";
4
+ import { spinner } from "../../index.js";
5
+ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
6
+ import { aYOUneModules } from "../../data/modules.js";
7
+ import { aYOUneServices } from "../../data/services.js";
8
+ function buildServiceRegistry() {
9
+ const services = [];
10
+ // APIs from modules
11
+ for (const m of aYOUneModules) {
12
+ services.push({
13
+ name: m.label,
14
+ type: "api",
15
+ module: m.module,
16
+ host: m.host,
17
+ });
18
+ }
19
+ // Services
20
+ for (const s of aYOUneServices) {
21
+ services.push({
22
+ name: s.label,
23
+ type: "service",
24
+ module: s.module,
25
+ host: s.host,
26
+ });
27
+ }
28
+ return services;
29
+ }
30
+ export function createServicesCommand(program) {
31
+ const svc = program
32
+ .command("services")
33
+ .alias("svc")
34
+ .description("Discover and manage aYOUne platform services");
35
+ // ay services list
36
+ svc
37
+ .command("list")
38
+ .alias("ls")
39
+ .description("List all registered services, APIs, and gateways")
40
+ .option("--type <type>", "Filter by type: api, service, gateway, worker")
41
+ .option("--module <module>", "Filter by module name")
42
+ .action(async (options) => {
43
+ try {
44
+ const opts = { ...program.opts(), ...options };
45
+ spinner.start({ text: "Loading service registry...", color: "magenta" });
46
+ let services = buildServiceRegistry();
47
+ if (opts.type) {
48
+ services = services.filter((s) => s.type === opts.type);
49
+ }
50
+ if (opts.module) {
51
+ services = services.filter((s) => s.module === opts.module);
52
+ }
53
+ const res = {
54
+ payload: services,
55
+ meta: { responseTime: 0, pageInfo: { totalEntries: services.length, page: 1, totalPages: 1 } },
56
+ };
57
+ handleResponseFormatOptions(opts, res);
58
+ spinner.success({ text: `Found ${services.length} services` });
59
+ spinner.stop();
60
+ if (opts.save)
61
+ await saveFile("services-list", opts, res);
62
+ }
63
+ catch (e) {
64
+ spinner.error({ text: e.message || "Failed to list services" });
65
+ process.exit(EXIT_GENERAL_ERROR);
66
+ }
67
+ });
68
+ // ay services endpoints <host>
69
+ svc
70
+ .command("endpoints <host>")
71
+ .alias("ep")
72
+ .description("List API endpoints for a service host")
73
+ .addHelpText("after", `
74
+ Examples:
75
+ ay services endpoints ai.ayoune.app
76
+ ay services endpoints crm-api.ayoune.app -r table`)
77
+ .action(async (host, options) => {
78
+ try {
79
+ const opts = { ...program.opts(), ...options };
80
+ spinner.start({ text: `Fetching endpoints for ${host}...`, color: "magenta" });
81
+ const res = await apiCallHandler("config", "ayouneapiactions", "get", null, {
82
+ limit: 500,
83
+ responseFormat: "json",
84
+ });
85
+ if (!(res === null || res === void 0 ? void 0 : res.payload)) {
86
+ spinner.error({ text: "No API actions found" });
87
+ return;
88
+ }
89
+ const endpoints = (Array.isArray(res.payload) ? res.payload : [])
90
+ .filter((a) => {
91
+ const h = a.host || "";
92
+ return h.includes(host) && !a.deprecated;
93
+ })
94
+ .map((a) => ({
95
+ method: (a.method || "GET").toUpperCase(),
96
+ endpoint: a.endpoint || "",
97
+ operationId: a.operationId || "",
98
+ action: a.action || "",
99
+ description: a.shortDescription || a.description || "",
100
+ }))
101
+ .sort((a, b) => a.endpoint.localeCompare(b.endpoint));
102
+ const formattedRes = {
103
+ payload: endpoints,
104
+ meta: { responseTime: 0, pageInfo: { totalEntries: endpoints.length, page: 1, totalPages: 1 } },
105
+ };
106
+ handleResponseFormatOptions(opts, formattedRes);
107
+ spinner.success({ text: `Found ${endpoints.length} endpoints on ${host}` });
108
+ spinner.stop();
109
+ if (opts.save)
110
+ await saveFile("service-endpoints", opts, formattedRes);
111
+ }
112
+ catch (e) {
113
+ spinner.error({ text: e.message || "Failed to fetch endpoints" });
114
+ process.exit(EXIT_GENERAL_ERROR);
115
+ }
116
+ });
117
+ // ay services health [host]
118
+ svc
119
+ .command("health [host]")
120
+ .description("Check health of a service or all services")
121
+ .option("--timeout <ms>", "Request timeout in ms", parseInt, 5000)
122
+ .action(async (host, options) => {
123
+ try {
124
+ const opts = { ...program.opts(), ...options };
125
+ const targets = host
126
+ ? [{ name: host, host }]
127
+ : buildServiceRegistry().map((s) => ({ name: s.name, host: s.host }));
128
+ // Deduplicate by host
129
+ const uniqueTargets = [...new Map(targets.map((t) => [t.host, t])).values()];
130
+ spinner.start({ text: `Checking ${uniqueTargets.length} service(s)...`, color: "magenta" });
131
+ const { default: axios } = await import("axios");
132
+ const https = await import("https");
133
+ const agent = new https.Agent({ rejectUnauthorized: false });
134
+ const results = await Promise.allSettled(uniqueTargets.map(async (t) => {
135
+ const start = Date.now();
136
+ try {
137
+ const resp = await axios.get(`https://${t.host}/`, {
138
+ timeout: opts.timeout,
139
+ httpsAgent: agent,
140
+ validateStatus: () => true,
141
+ });
142
+ return {
143
+ host: t.host,
144
+ name: t.name,
145
+ status: resp.status < 500 ? "healthy" : "unhealthy",
146
+ statusCode: resp.status,
147
+ responseTime: Date.now() - start,
148
+ };
149
+ }
150
+ catch (e) {
151
+ return {
152
+ host: t.host,
153
+ name: t.name,
154
+ status: "unreachable",
155
+ statusCode: 0,
156
+ responseTime: Date.now() - start,
157
+ error: e.code || e.message,
158
+ };
159
+ }
160
+ }));
161
+ const payload = results.map((r) => (r.status === "fulfilled" ? r.value : { status: "error" }));
162
+ const healthy = payload.filter((p) => p.status === "healthy").length;
163
+ const res = {
164
+ payload,
165
+ meta: {
166
+ responseTime: 0,
167
+ pageInfo: { totalEntries: payload.length, page: 1, totalPages: 1 },
168
+ },
169
+ };
170
+ handleResponseFormatOptions(opts, res);
171
+ spinner.success({ text: `${healthy}/${uniqueTargets.length} services healthy` });
172
+ spinner.stop();
173
+ if (opts.save)
174
+ await saveFile("services-health", opts, res);
175
+ }
176
+ catch (e) {
177
+ spinner.error({ text: e.message || "Health check failed" });
178
+ process.exit(EXIT_GENERAL_ERROR);
179
+ }
180
+ });
181
+ // ay services describe <module>
182
+ svc
183
+ .command("describe <module>")
184
+ .alias("desc")
185
+ .description("Show detailed info about a module/service")
186
+ .action(async (moduleName, options) => {
187
+ try {
188
+ const opts = { ...program.opts(), ...options };
189
+ spinner.start({ text: `Describing ${moduleName}...`, color: "magenta" });
190
+ // Find matching entries
191
+ const apis = aYOUneModules.filter((m) => m.module === moduleName);
192
+ const svcs = aYOUneServices.filter((s) => s.module === moduleName);
193
+ // Fetch endpoint count from apiactions
194
+ const res = await apiCallHandler("config", "ayouneapiactions", "get", null, {
195
+ limit: 500,
196
+ responseFormat: "json",
197
+ });
198
+ const allActions = Array.isArray(res === null || res === void 0 ? void 0 : res.payload) ? res.payload : [];
199
+ const moduleActions = allActions.filter((a) => a.nameSpace === moduleName && !a.deprecated);
200
+ const methods = {};
201
+ for (const a of moduleActions) {
202
+ const m = (a.method || "GET").toUpperCase();
203
+ methods[m] = (methods[m] || 0) + 1;
204
+ }
205
+ const description = {
206
+ module: moduleName,
207
+ apis: apis.map((a) => ({ label: a.label, host: a.host })),
208
+ services: svcs.map((s) => ({ label: s.label, host: s.host })),
209
+ endpoints: {
210
+ total: moduleActions.length,
211
+ byMethod: methods,
212
+ },
213
+ capabilities: [...new Set(moduleActions.map((a) => a.capability).filter(Boolean))].sort(),
214
+ };
215
+ const formattedRes = {
216
+ payload: description,
217
+ meta: { responseTime: 0 },
218
+ };
219
+ handleResponseFormatOptions(opts, formattedRes);
220
+ spinner.success({ text: `Module: ${moduleName} — ${moduleActions.length} endpoints` });
221
+ spinner.stop();
222
+ }
223
+ catch (e) {
224
+ spinner.error({ text: e.message || "Failed to describe service" });
225
+ process.exit(EXIT_GENERAL_ERROR);
226
+ }
227
+ });
228
+ }