@tolinax/ayoune-cli 2026.3.0 → 2026.4.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.
- package/data/contextSlots.js +189 -0
- package/data/modelsAndRights.js +56 -0
- package/data/modules.js +16 -0
- package/lib/api/apiCallHandler.js +6 -2
- package/lib/api/apiClient.js +9 -1
- package/lib/api/auditCallHandler.js +2 -2
- package/lib/api/handleAPIError.js +20 -18
- package/lib/api/login.js +3 -3
- package/lib/api/searchClient.js +119 -0
- package/lib/commands/createAccessCommand.js +126 -0
- package/lib/commands/createActionsCommand.js +40 -9
- package/lib/commands/createAiCommand.js +17 -17
- package/lib/commands/createAliasCommand.js +4 -6
- package/lib/commands/createAuditCommand.js +5 -9
- package/lib/commands/createBatchCommand.js +15 -28
- package/lib/commands/createCompletionsCommand.js +6 -3
- package/lib/commands/createConfigCommand.js +8 -14
- package/lib/commands/createContextCommand.js +163 -0
- package/lib/commands/createCopyCommand.js +4 -7
- package/lib/commands/createCreateCommand.js +4 -7
- package/lib/commands/createDeleteCommand.js +4 -6
- package/lib/commands/createDeployCommand.js +31 -55
- package/lib/commands/createDescribeCommand.js +12 -10
- package/lib/commands/createEditCommand.js +13 -8
- package/lib/commands/createEventsCommand.js +4 -4
- package/lib/commands/createExecCommand.js +65 -35
- package/lib/commands/createExportCommand.js +21 -24
- package/lib/commands/createGetCommand.js +13 -14
- package/lib/commands/createJobsCommand.js +8 -13
- package/lib/commands/createListCommand.js +13 -14
- package/lib/commands/createLoginCommand.js +16 -4
- package/lib/commands/createLogoutCommand.js +2 -2
- package/lib/commands/createModulesCommand.js +16 -19
- package/lib/commands/createMonitorCommand.js +9 -16
- package/lib/commands/createPermissionsCommand.js +10 -18
- package/lib/commands/createProgram.js +47 -21
- package/lib/commands/createSearchCommand.js +219 -69
- package/lib/commands/createSelfHostUpdateCommand.js +166 -0
- package/lib/commands/createServicesCommand.js +5 -8
- package/lib/commands/createSetupCommand.js +305 -0
- package/lib/commands/createStatusCommand.js +147 -0
- package/lib/commands/createStorageCommand.js +2 -3
- package/lib/commands/createStreamCommand.js +4 -4
- package/lib/commands/createSyncCommand.js +5 -8
- package/lib/commands/createTemplateCommand.js +9 -16
- package/lib/commands/createUpdateCommand.js +12 -15
- package/lib/commands/createUsersCommand.js +21 -31
- package/lib/commands/createWebhooksCommand.js +15 -22
- package/lib/commands/createWhoAmICommand.js +8 -6
- package/lib/helpers/cliError.js +24 -0
- package/lib/helpers/config.js +1 -0
- package/lib/helpers/configLoader.js +6 -0
- package/lib/helpers/contextInjector.js +65 -0
- package/lib/helpers/contextResolver.js +70 -0
- package/lib/helpers/contextStore.js +46 -0
- package/lib/helpers/handleResponseFormatOptions.js +59 -10
- package/lib/helpers/logo.js +48 -0
- package/lib/helpers/resolveCollectionArgs.js +36 -0
- package/lib/helpers/sanitizeFields.js +18 -0
- package/lib/helpers/secureStorage.js +72 -0
- package/lib/helpers/tokenPayload.js +21 -0
- package/lib/helpers/updateNotifier.js +49 -0
- package/lib/models/getModuleFromCollection.js +4 -1
- package/lib/operations/handleCopySingleOperation.js +10 -2
- package/lib/operations/handleCreateSingleOperation.js +3 -0
- package/lib/operations/handleDescribeSingleOperation.js +23 -0
- package/lib/operations/handleGetOperation.js +9 -3
- package/lib/operations/handleListOperation.js +14 -10
- package/lib/prompts/promptModule.js +9 -6
- package/package.json +163 -158
|
@@ -6,6 +6,7 @@ import { saveFile } from "../helpers/saveFile.js";
|
|
|
6
6
|
import { localStorage } from "../helpers/localStorage.js";
|
|
7
7
|
import { spinner } from "../../index.js";
|
|
8
8
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
9
|
+
import { cliError } from "../helpers/cliError.js";
|
|
9
10
|
export function createUpdateCommand(program) {
|
|
10
11
|
program
|
|
11
12
|
.command("update")
|
|
@@ -29,12 +30,10 @@ Examples:
|
|
|
29
30
|
.action(async (collection, id, options) => {
|
|
30
31
|
try {
|
|
31
32
|
if (!collection) {
|
|
32
|
-
|
|
33
|
-
process.exit(EXIT_MISUSE);
|
|
33
|
+
cliError("Missing required argument: collection", EXIT_MISUSE);
|
|
34
34
|
}
|
|
35
35
|
if (!id) {
|
|
36
|
-
|
|
37
|
-
process.exit(EXIT_MISUSE);
|
|
36
|
+
cliError("Missing required argument: id", EXIT_MISUSE);
|
|
38
37
|
}
|
|
39
38
|
const opts = { ...program.opts(), ...options };
|
|
40
39
|
const module = getModuleFromCollection(collection);
|
|
@@ -45,8 +44,7 @@ Examples:
|
|
|
45
44
|
body = JSON.parse(opts.body);
|
|
46
45
|
}
|
|
47
46
|
catch (_a) {
|
|
48
|
-
|
|
49
|
-
process.exit(EXIT_MISUSE);
|
|
47
|
+
cliError("Invalid JSON in --body", EXIT_MISUSE);
|
|
50
48
|
}
|
|
51
49
|
}
|
|
52
50
|
if (opts.bodyFile) {
|
|
@@ -56,8 +54,7 @@ Examples:
|
|
|
56
54
|
body = JSON.parse(content);
|
|
57
55
|
}
|
|
58
56
|
catch (_b) {
|
|
59
|
-
|
|
60
|
-
process.exit(EXIT_MISUSE);
|
|
57
|
+
cliError(`Invalid JSON in file: ${opts.bodyFile}`, EXIT_MISUSE);
|
|
61
58
|
}
|
|
62
59
|
}
|
|
63
60
|
if (opts.bodyStdin && !process.stdin.isTTY) {
|
|
@@ -71,14 +68,12 @@ Examples:
|
|
|
71
68
|
body = JSON.parse(stdinContent);
|
|
72
69
|
}
|
|
73
70
|
catch (_c) {
|
|
74
|
-
|
|
75
|
-
process.exit(EXIT_MISUSE);
|
|
71
|
+
cliError("Invalid JSON from stdin", EXIT_MISUSE);
|
|
76
72
|
}
|
|
77
73
|
}
|
|
78
74
|
}
|
|
79
75
|
if (!body) {
|
|
80
|
-
|
|
81
|
-
process.exit(EXIT_MISUSE);
|
|
76
|
+
cliError("No update data provided. Use --body, --body-file, or --body-stdin.", EXIT_MISUSE);
|
|
82
77
|
}
|
|
83
78
|
// Merge mode: GET existing → merge → PUT
|
|
84
79
|
if (opts.merge) {
|
|
@@ -98,7 +93,10 @@ Examples:
|
|
|
98
93
|
verbosity: opts.verbosity,
|
|
99
94
|
hideMeta: opts.hideMeta,
|
|
100
95
|
});
|
|
101
|
-
|
|
96
|
+
// Dry-run returns null payload — skip output to avoid printing "null"
|
|
97
|
+
if ((res === null || res === void 0 ? void 0 : res.payload) !== null && (res === null || res === void 0 ? void 0 : res.payload) !== undefined) {
|
|
98
|
+
handleResponseFormatOptions(opts, res);
|
|
99
|
+
}
|
|
102
100
|
spinner.success({ text: `Updated entry ${id} in ${collection}` });
|
|
103
101
|
spinner.stop();
|
|
104
102
|
localStorage.setItem("lastModule", module.module);
|
|
@@ -108,8 +106,7 @@ Examples:
|
|
|
108
106
|
await saveFile("update", opts, res);
|
|
109
107
|
}
|
|
110
108
|
catch (e) {
|
|
111
|
-
|
|
112
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
109
|
+
cliError(e.message || "An unexpected error occurred", EXIT_GENERAL_ERROR);
|
|
113
110
|
}
|
|
114
111
|
});
|
|
115
112
|
}
|
|
@@ -4,6 +4,7 @@ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOpti
|
|
|
4
4
|
import { saveFile } from "../helpers/saveFile.js";
|
|
5
5
|
import { spinner } from "../../index.js";
|
|
6
6
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
7
|
+
import { cliError } from "../helpers/cliError.js";
|
|
7
8
|
export function createUsersCommand(program) {
|
|
8
9
|
const users = program
|
|
9
10
|
.command("users")
|
|
@@ -36,7 +37,7 @@ export function createUsersCommand(program) {
|
|
|
36
37
|
params.role = opts.role;
|
|
37
38
|
if (opts.active)
|
|
38
39
|
params.active = "true";
|
|
39
|
-
const res = await apiCallHandler("
|
|
40
|
+
const res = await apiCallHandler("su", "users", "get", null, params);
|
|
40
41
|
handleResponseFormatOptions(opts, res);
|
|
41
42
|
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;
|
|
42
43
|
spinner.success({ text: `Found ${total} users` });
|
|
@@ -45,8 +46,7 @@ export function createUsersCommand(program) {
|
|
|
45
46
|
await saveFile("users-list", opts, res);
|
|
46
47
|
}
|
|
47
48
|
catch (e) {
|
|
48
|
-
|
|
49
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
49
|
+
cliError(e.message || "Failed to list users", EXIT_GENERAL_ERROR);
|
|
50
50
|
}
|
|
51
51
|
});
|
|
52
52
|
// ay users get <id>
|
|
@@ -57,7 +57,7 @@ export function createUsersCommand(program) {
|
|
|
57
57
|
try {
|
|
58
58
|
const opts = { ...program.opts(), ...options };
|
|
59
59
|
spinner.start({ text: `Fetching user ${id}...`, color: "magenta" });
|
|
60
|
-
const res = await apiCallHandler("
|
|
60
|
+
const res = await apiCallHandler("su", `users/${id}`, "get", null, {
|
|
61
61
|
responseFormat: opts.responseFormat,
|
|
62
62
|
verbosity: opts.verbosity,
|
|
63
63
|
});
|
|
@@ -66,8 +66,7 @@ export function createUsersCommand(program) {
|
|
|
66
66
|
spinner.stop();
|
|
67
67
|
}
|
|
68
68
|
catch (e) {
|
|
69
|
-
|
|
70
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
69
|
+
cliError(e.message || "Failed to get user", EXIT_GENERAL_ERROR);
|
|
71
70
|
}
|
|
72
71
|
});
|
|
73
72
|
// ay users invite --email <email> --role <roleId>
|
|
@@ -89,7 +88,7 @@ export function createUsersCommand(program) {
|
|
|
89
88
|
body.firstName = opts.firstName;
|
|
90
89
|
if (opts.lastName)
|
|
91
90
|
body.lastName = opts.lastName;
|
|
92
|
-
const res = await apiCallHandler("
|
|
91
|
+
const res = await apiCallHandler("su", "users", "post", body, {
|
|
93
92
|
responseFormat: opts.responseFormat,
|
|
94
93
|
});
|
|
95
94
|
handleResponseFormatOptions(opts, res);
|
|
@@ -97,8 +96,7 @@ export function createUsersCommand(program) {
|
|
|
97
96
|
spinner.stop();
|
|
98
97
|
}
|
|
99
98
|
catch (e) {
|
|
100
|
-
|
|
101
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
99
|
+
cliError(e.message || "Failed to invite user", EXIT_GENERAL_ERROR);
|
|
102
100
|
}
|
|
103
101
|
});
|
|
104
102
|
// ay users deactivate <id>
|
|
@@ -119,7 +117,7 @@ export function createUsersCommand(program) {
|
|
|
119
117
|
}
|
|
120
118
|
}
|
|
121
119
|
spinner.start({ text: `Deactivating user ${id}...`, color: "magenta" });
|
|
122
|
-
const res = await apiCallHandler("
|
|
120
|
+
const res = await apiCallHandler("su", "users", "put", { _id: id, active: false }, {
|
|
123
121
|
responseFormat: opts.responseFormat,
|
|
124
122
|
});
|
|
125
123
|
handleResponseFormatOptions(opts, res);
|
|
@@ -127,8 +125,7 @@ export function createUsersCommand(program) {
|
|
|
127
125
|
spinner.stop();
|
|
128
126
|
}
|
|
129
127
|
catch (e) {
|
|
130
|
-
|
|
131
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
128
|
+
cliError(e.message || "Failed to deactivate user", EXIT_GENERAL_ERROR);
|
|
132
129
|
}
|
|
133
130
|
});
|
|
134
131
|
// ── TEAMS ──────────────────────────────────────────────
|
|
@@ -156,7 +153,7 @@ export function createUsersCommand(program) {
|
|
|
156
153
|
};
|
|
157
154
|
if (opts.search)
|
|
158
155
|
params.q = opts.search;
|
|
159
|
-
const res = await apiCallHandler("
|
|
156
|
+
const res = await apiCallHandler("su", "teams", "get", null, params);
|
|
160
157
|
handleResponseFormatOptions(opts, res);
|
|
161
158
|
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;
|
|
162
159
|
spinner.success({ text: `Found ${total} teams` });
|
|
@@ -165,8 +162,7 @@ export function createUsersCommand(program) {
|
|
|
165
162
|
await saveFile("teams-list", opts, res);
|
|
166
163
|
}
|
|
167
164
|
catch (e) {
|
|
168
|
-
|
|
169
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
165
|
+
cliError(e.message || "Failed to list teams", EXIT_GENERAL_ERROR);
|
|
170
166
|
}
|
|
171
167
|
});
|
|
172
168
|
// ay users teams get <id>
|
|
@@ -177,7 +173,7 @@ export function createUsersCommand(program) {
|
|
|
177
173
|
try {
|
|
178
174
|
const opts = { ...program.opts(), ...options };
|
|
179
175
|
spinner.start({ text: `Fetching team ${id}...`, color: "magenta" });
|
|
180
|
-
const res = await apiCallHandler("
|
|
176
|
+
const res = await apiCallHandler("su", `teams/${id}`, "get", null, {
|
|
181
177
|
responseFormat: opts.responseFormat,
|
|
182
178
|
verbosity: opts.verbosity,
|
|
183
179
|
});
|
|
@@ -186,8 +182,7 @@ export function createUsersCommand(program) {
|
|
|
186
182
|
spinner.stop();
|
|
187
183
|
}
|
|
188
184
|
catch (e) {
|
|
189
|
-
|
|
190
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
185
|
+
cliError(e.message || "Failed to get team", EXIT_GENERAL_ERROR);
|
|
191
186
|
}
|
|
192
187
|
});
|
|
193
188
|
// ay users teams create --body '{...}'
|
|
@@ -205,19 +200,17 @@ export function createUsersCommand(program) {
|
|
|
205
200
|
body = JSON.parse(opts.body);
|
|
206
201
|
}
|
|
207
202
|
catch (_a) {
|
|
208
|
-
|
|
209
|
-
process.exit(EXIT_MISUSE);
|
|
203
|
+
cliError("Invalid JSON in --body", EXIT_MISUSE);
|
|
210
204
|
}
|
|
211
205
|
}
|
|
212
206
|
else if (opts.name) {
|
|
213
207
|
body = { name: opts.name };
|
|
214
208
|
}
|
|
215
209
|
if (!body) {
|
|
216
|
-
|
|
217
|
-
process.exit(EXIT_MISUSE);
|
|
210
|
+
cliError("Provide team definition via --name or --body", EXIT_MISUSE);
|
|
218
211
|
}
|
|
219
212
|
spinner.start({ text: "Creating team...", color: "magenta" });
|
|
220
|
-
const res = await apiCallHandler("
|
|
213
|
+
const res = await apiCallHandler("su", "teams", "post", body, {
|
|
221
214
|
responseFormat: opts.responseFormat,
|
|
222
215
|
});
|
|
223
216
|
handleResponseFormatOptions(opts, res);
|
|
@@ -225,8 +218,7 @@ export function createUsersCommand(program) {
|
|
|
225
218
|
spinner.stop();
|
|
226
219
|
}
|
|
227
220
|
catch (e) {
|
|
228
|
-
|
|
229
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
221
|
+
cliError(e.message || "Failed to create team", EXIT_GENERAL_ERROR);
|
|
230
222
|
}
|
|
231
223
|
});
|
|
232
224
|
// ── ROLES ──────────────────────────────────────────────
|
|
@@ -244,7 +236,7 @@ export function createUsersCommand(program) {
|
|
|
244
236
|
try {
|
|
245
237
|
const opts = { ...program.opts(), ...options };
|
|
246
238
|
spinner.start({ text: "Fetching roles...", color: "magenta" });
|
|
247
|
-
const res = await apiCallHandler("
|
|
239
|
+
const res = await apiCallHandler("su", "roles", "get", null, {
|
|
248
240
|
limit: opts.limit,
|
|
249
241
|
responseFormat: opts.responseFormat,
|
|
250
242
|
verbosity: opts.verbosity,
|
|
@@ -257,8 +249,7 @@ export function createUsersCommand(program) {
|
|
|
257
249
|
await saveFile("roles-list", opts, res);
|
|
258
250
|
}
|
|
259
251
|
catch (e) {
|
|
260
|
-
|
|
261
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
252
|
+
cliError(e.message || "Failed to list roles", EXIT_GENERAL_ERROR);
|
|
262
253
|
}
|
|
263
254
|
});
|
|
264
255
|
// ay users roles get <id>
|
|
@@ -269,7 +260,7 @@ export function createUsersCommand(program) {
|
|
|
269
260
|
try {
|
|
270
261
|
const opts = { ...program.opts(), ...options };
|
|
271
262
|
spinner.start({ text: `Fetching role ${id}...`, color: "magenta" });
|
|
272
|
-
const res = await apiCallHandler("
|
|
263
|
+
const res = await apiCallHandler("su", `roles/${id}`, "get", null, {
|
|
273
264
|
responseFormat: opts.responseFormat,
|
|
274
265
|
verbosity: opts.verbosity,
|
|
275
266
|
});
|
|
@@ -278,8 +269,7 @@ export function createUsersCommand(program) {
|
|
|
278
269
|
spinner.stop();
|
|
279
270
|
}
|
|
280
271
|
catch (e) {
|
|
281
|
-
|
|
282
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
272
|
+
cliError(e.message || "Failed to get role", EXIT_GENERAL_ERROR);
|
|
283
273
|
}
|
|
284
274
|
});
|
|
285
275
|
}
|
|
@@ -3,6 +3,7 @@ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOpti
|
|
|
3
3
|
import { saveFile } from "../helpers/saveFile.js";
|
|
4
4
|
import { spinner } from "../../index.js";
|
|
5
5
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
6
|
+
import { cliError } from "../helpers/cliError.js";
|
|
6
7
|
export function createWebhooksCommand(program) {
|
|
7
8
|
const hooks = program
|
|
8
9
|
.command("webhooks")
|
|
@@ -16,7 +17,7 @@ export function createWebhooksCommand(program) {
|
|
|
16
17
|
.option("-l, --limit <number>", "Limit results", parseInt, 50)
|
|
17
18
|
.option("-p, --page <number>", "Page number", parseInt, 1)
|
|
18
19
|
.action(async (options) => {
|
|
19
|
-
var _a, _b
|
|
20
|
+
var _a, _b;
|
|
20
21
|
try {
|
|
21
22
|
const opts = { ...program.opts(), ...options };
|
|
22
23
|
spinner.start({ text: "Fetching webhooks...", color: "magenta" });
|
|
@@ -26,16 +27,15 @@ export function createWebhooksCommand(program) {
|
|
|
26
27
|
responseFormat: opts.responseFormat,
|
|
27
28
|
verbosity: opts.verbosity,
|
|
28
29
|
});
|
|
29
|
-
handleResponseFormatOptions(opts, res);
|
|
30
|
-
const total = (
|
|
30
|
+
const { result: fmtResult, meta: fmtMeta } = handleResponseFormatOptions(opts, res);
|
|
31
|
+
const total = (_b = (_a = fmtMeta === null || fmtMeta === void 0 ? void 0 : fmtMeta.pageInfo) === null || _a === void 0 ? void 0 : _a.totalEntries) !== null && _b !== void 0 ? _b : (Array.isArray(fmtResult) ? fmtResult.length : 0);
|
|
31
32
|
spinner.success({ text: `Found ${total} webhooks` });
|
|
32
33
|
spinner.stop();
|
|
33
34
|
if (opts.save)
|
|
34
35
|
await saveFile("webhooks-list", opts, res);
|
|
35
36
|
}
|
|
36
37
|
catch (e) {
|
|
37
|
-
|
|
38
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
38
|
+
cliError(e.message || "Failed to list webhooks", EXIT_GENERAL_ERROR);
|
|
39
39
|
}
|
|
40
40
|
});
|
|
41
41
|
// ay webhooks get <id>
|
|
@@ -55,8 +55,7 @@ export function createWebhooksCommand(program) {
|
|
|
55
55
|
spinner.stop();
|
|
56
56
|
}
|
|
57
57
|
catch (e) {
|
|
58
|
-
|
|
59
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
58
|
+
cliError(e.message || "Failed to get webhook", EXIT_GENERAL_ERROR);
|
|
60
59
|
}
|
|
61
60
|
});
|
|
62
61
|
// ay webhooks create --body '{...}'
|
|
@@ -74,8 +73,7 @@ export function createWebhooksCommand(program) {
|
|
|
74
73
|
body = JSON.parse(opts.body);
|
|
75
74
|
}
|
|
76
75
|
catch (_a) {
|
|
77
|
-
|
|
78
|
-
process.exit(EXIT_MISUSE);
|
|
76
|
+
cliError("Invalid JSON in --body", EXIT_MISUSE);
|
|
79
77
|
}
|
|
80
78
|
}
|
|
81
79
|
else if (opts.bodyFile) {
|
|
@@ -84,13 +82,11 @@ export function createWebhooksCommand(program) {
|
|
|
84
82
|
body = JSON.parse(fs.readFileSync(opts.bodyFile, "utf-8"));
|
|
85
83
|
}
|
|
86
84
|
catch (_b) {
|
|
87
|
-
|
|
88
|
-
process.exit(EXIT_MISUSE);
|
|
85
|
+
cliError(`Invalid JSON in file: ${opts.bodyFile}`, EXIT_MISUSE);
|
|
89
86
|
}
|
|
90
87
|
}
|
|
91
88
|
if (!body) {
|
|
92
|
-
|
|
93
|
-
process.exit(EXIT_MISUSE);
|
|
89
|
+
cliError("Provide webhook definition via --body or --body-file", EXIT_MISUSE);
|
|
94
90
|
}
|
|
95
91
|
spinner.start({ text: "Creating webhook...", color: "magenta" });
|
|
96
92
|
const res = await apiCallHandler("config", "hooks", "post", body, {
|
|
@@ -101,8 +97,7 @@ export function createWebhooksCommand(program) {
|
|
|
101
97
|
spinner.stop();
|
|
102
98
|
}
|
|
103
99
|
catch (e) {
|
|
104
|
-
|
|
105
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
100
|
+
cliError(e.message || "Failed to create webhook", EXIT_GENERAL_ERROR);
|
|
106
101
|
}
|
|
107
102
|
});
|
|
108
103
|
// ay webhooks delete <id>
|
|
@@ -122,8 +117,7 @@ export function createWebhooksCommand(program) {
|
|
|
122
117
|
spinner.stop();
|
|
123
118
|
}
|
|
124
119
|
catch (e) {
|
|
125
|
-
|
|
126
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
120
|
+
cliError(e.message || "Failed to delete webhook", EXIT_GENERAL_ERROR);
|
|
127
121
|
}
|
|
128
122
|
});
|
|
129
123
|
// ay webhooks templates
|
|
@@ -132,7 +126,7 @@ export function createWebhooksCommand(program) {
|
|
|
132
126
|
.description("List available webhook templates")
|
|
133
127
|
.option("-l, --limit <number>", "Limit results", parseInt, 50)
|
|
134
128
|
.action(async (options) => {
|
|
135
|
-
var _a, _b
|
|
129
|
+
var _a, _b;
|
|
136
130
|
try {
|
|
137
131
|
const opts = { ...program.opts(), ...options };
|
|
138
132
|
spinner.start({ text: "Fetching webhook templates...", color: "magenta" });
|
|
@@ -141,16 +135,15 @@ export function createWebhooksCommand(program) {
|
|
|
141
135
|
responseFormat: opts.responseFormat,
|
|
142
136
|
verbosity: opts.verbosity,
|
|
143
137
|
});
|
|
144
|
-
handleResponseFormatOptions(opts, res);
|
|
145
|
-
const total = (
|
|
138
|
+
const { result: fmtResult, meta: fmtMeta } = handleResponseFormatOptions(opts, res);
|
|
139
|
+
const total = (_b = (_a = fmtMeta === null || fmtMeta === void 0 ? void 0 : fmtMeta.pageInfo) === null || _a === void 0 ? void 0 : _a.totalEntries) !== null && _b !== void 0 ? _b : (Array.isArray(fmtResult) ? fmtResult.length : 0);
|
|
146
140
|
spinner.success({ text: `Found ${total} webhook templates` });
|
|
147
141
|
spinner.stop();
|
|
148
142
|
if (opts.save)
|
|
149
143
|
await saveFile("webhook-templates", opts, res);
|
|
150
144
|
}
|
|
151
145
|
catch (e) {
|
|
152
|
-
|
|
153
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
146
|
+
cliError(e.message || "Failed to list templates", EXIT_GENERAL_ERROR);
|
|
154
147
|
}
|
|
155
148
|
});
|
|
156
149
|
}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import chalk from "chalk";
|
|
2
2
|
import moment from "moment";
|
|
3
|
-
import {
|
|
3
|
+
import { secureStorage } from "../helpers/secureStorage.js";
|
|
4
4
|
import { decodeToken } from "../api/decodeToken.js";
|
|
5
|
-
import { spinner } from "../../index.js";
|
|
6
5
|
import { login } from "../api/login.js";
|
|
7
6
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
7
|
+
import { cliError } from "../helpers/cliError.js";
|
|
8
8
|
const LABEL_MAP = {
|
|
9
9
|
_id: "User ID",
|
|
10
10
|
_customerID: "Customer",
|
|
@@ -30,6 +30,9 @@ function formatValue(key, value) {
|
|
|
30
30
|
}
|
|
31
31
|
return `${formatted} ${chalk.dim(`(${relative})`)}`;
|
|
32
32
|
}
|
|
33
|
+
if (key === "type" && value === "superuser") {
|
|
34
|
+
return chalk.yellow.bold("superuser");
|
|
35
|
+
}
|
|
33
36
|
if (typeof value === "object" && value !== null) {
|
|
34
37
|
return JSON.stringify(value);
|
|
35
38
|
}
|
|
@@ -68,21 +71,20 @@ export function createWhoAmICommand(program) {
|
|
|
68
71
|
.description("Display the currently authenticated user")
|
|
69
72
|
.action(async (options) => {
|
|
70
73
|
try {
|
|
71
|
-
const tokenPayload = decodeToken(
|
|
74
|
+
const tokenPayload = decodeToken(secureStorage.getItem("token"));
|
|
72
75
|
if (tokenPayload) {
|
|
73
76
|
displayUser(tokenPayload.payload);
|
|
74
77
|
}
|
|
75
78
|
else {
|
|
76
79
|
await login();
|
|
77
|
-
const newPayload = decodeToken(
|
|
80
|
+
const newPayload = decodeToken(secureStorage.getItem("token"));
|
|
78
81
|
if (newPayload) {
|
|
79
82
|
displayUser(newPayload.payload);
|
|
80
83
|
}
|
|
81
84
|
}
|
|
82
85
|
}
|
|
83
86
|
catch (e) {
|
|
84
|
-
|
|
85
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
87
|
+
cliError(e.message || "An unexpected error occurred", EXIT_GENERAL_ERROR);
|
|
86
88
|
}
|
|
87
89
|
});
|
|
88
90
|
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { spinner } from "../../index.js";
|
|
2
|
+
let jsonErrorsEnabled = false;
|
|
3
|
+
export function setJsonErrorsEnabled(enabled) {
|
|
4
|
+
jsonErrorsEnabled = enabled;
|
|
5
|
+
}
|
|
6
|
+
export function isJsonErrorsEnabled() {
|
|
7
|
+
return jsonErrorsEnabled;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Centralized CLI error handler.
|
|
11
|
+
* When --json-errors is active, emits structured JSON to stderr.
|
|
12
|
+
* Otherwise, uses spinner.error for human-readable output.
|
|
13
|
+
* Always calls process.exit with the given code.
|
|
14
|
+
*/
|
|
15
|
+
export function cliError(message, code, type = "cli_error") {
|
|
16
|
+
if (jsonErrorsEnabled) {
|
|
17
|
+
const err = { error: type, code, message };
|
|
18
|
+
console.error(JSON.stringify(err));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
spinner.error({ text: message });
|
|
22
|
+
}
|
|
23
|
+
process.exit(code);
|
|
24
|
+
}
|
package/lib/helpers/config.js
CHANGED
|
@@ -3,4 +3,5 @@ export const config = {
|
|
|
3
3
|
auditUrl: process.env.AYOUNE_AUDIT_URL || "https://audit.ayoune.app",
|
|
4
4
|
notifierUrl: process.env.AYOUNE_NOTIFIER_URL || "https://notifier.ayoune.app",
|
|
5
5
|
loginUrl: process.env.AYOUNE_LOGIN_URL || "https://login.ayoune.app",
|
|
6
|
+
searchUrl: process.env.AYOUNE_SEARCH_HOST || "https://search-api.ayoune.app",
|
|
6
7
|
};
|
|
@@ -58,3 +58,9 @@ export function getNotifierUrl(config) {
|
|
|
58
58
|
profile.notifierUrl ||
|
|
59
59
|
"https://notifier.ayoune.app");
|
|
60
60
|
}
|
|
61
|
+
export function getSearchUrl(config) {
|
|
62
|
+
const profile = getActiveProfile(config);
|
|
63
|
+
return (process.env.AYOUNE_SEARCH_HOST ||
|
|
64
|
+
profile.searchUrl ||
|
|
65
|
+
"https://search-api.ayoune.app");
|
|
66
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { contextSlots } from "../../data/contextSlots.js";
|
|
2
|
+
import { getActiveContext } from "./contextStore.js";
|
|
3
|
+
let contextDisabled = false;
|
|
4
|
+
export function disableContext() {
|
|
5
|
+
contextDisabled = true;
|
|
6
|
+
}
|
|
7
|
+
export function hasActiveContext() {
|
|
8
|
+
if (contextDisabled)
|
|
9
|
+
return false;
|
|
10
|
+
return Object.keys(getActiveContext()).length > 0;
|
|
11
|
+
}
|
|
12
|
+
export function getContextCreateFields(collection) {
|
|
13
|
+
if (contextDisabled)
|
|
14
|
+
return {};
|
|
15
|
+
const active = getActiveContext();
|
|
16
|
+
const fields = {};
|
|
17
|
+
const col = collection.toLowerCase();
|
|
18
|
+
for (const slot of contextSlots) {
|
|
19
|
+
const entry = active[slot.slot];
|
|
20
|
+
if (!entry)
|
|
21
|
+
continue;
|
|
22
|
+
const fieldName = slot.injectAsCreateField[col];
|
|
23
|
+
if (fieldName) {
|
|
24
|
+
fields[fieldName] = entry.id;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return fields;
|
|
28
|
+
}
|
|
29
|
+
export function getContextFilterParams(collection) {
|
|
30
|
+
if (contextDisabled)
|
|
31
|
+
return {};
|
|
32
|
+
const active = getActiveContext();
|
|
33
|
+
const params = {};
|
|
34
|
+
const col = collection.toLowerCase();
|
|
35
|
+
for (const slot of contextSlots) {
|
|
36
|
+
const entry = active[slot.slot];
|
|
37
|
+
if (!entry)
|
|
38
|
+
continue;
|
|
39
|
+
const paramName = slot.injectAsFilterField[col];
|
|
40
|
+
if (paramName) {
|
|
41
|
+
params[paramName] = entry.id;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return params;
|
|
45
|
+
}
|
|
46
|
+
export function getContextSummary() {
|
|
47
|
+
if (contextDisabled)
|
|
48
|
+
return "";
|
|
49
|
+
const active = getActiveContext();
|
|
50
|
+
const entries = Object.entries(active);
|
|
51
|
+
if (entries.length === 0)
|
|
52
|
+
return "";
|
|
53
|
+
const lines = entries.map(([slot, entry]) => `- Active ${slot}: "${entry.name}" (${entry.collection}, ID: ${entry.id})`);
|
|
54
|
+
return `[Active context]\n${lines.join("\n")}`;
|
|
55
|
+
}
|
|
56
|
+
export function getContextForAI() {
|
|
57
|
+
if (contextDisabled)
|
|
58
|
+
return {};
|
|
59
|
+
const active = getActiveContext();
|
|
60
|
+
const result = {};
|
|
61
|
+
for (const [slot, entry] of Object.entries(active)) {
|
|
62
|
+
result[slot] = { id: entry.id, name: entry.name, collection: entry.collection };
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { apiCallHandler } from "../api/apiCallHandler.js";
|
|
2
|
+
import { getSlot, getChildSlots } from "../../data/contextSlots.js";
|
|
3
|
+
import { getContextEntry } from "./contextStore.js";
|
|
4
|
+
const OBJECT_ID_RE = /^[0-9a-fA-F]{24}$/;
|
|
5
|
+
export async function resolveEntity(slot, input) {
|
|
6
|
+
const slotDef = getSlot(slot);
|
|
7
|
+
if (!slotDef)
|
|
8
|
+
return [];
|
|
9
|
+
// Direct ID lookup
|
|
10
|
+
if (OBJECT_ID_RE.test(input)) {
|
|
11
|
+
try {
|
|
12
|
+
const res = await apiCallHandler(slotDef.module, `${slotDef.collection}/${input}`, "get", null, { fields: `_id,${slotDef.nameField}`, responseFormat: "json" });
|
|
13
|
+
if (res === null || res === void 0 ? void 0 : res.payload) {
|
|
14
|
+
const entity = Array.isArray(res.payload) ? res.payload[0] : res.payload;
|
|
15
|
+
if (entity === null || entity === void 0 ? void 0 : entity._id) {
|
|
16
|
+
return [{ id: entity._id, name: entity[slotDef.nameField] || entity._id }];
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
catch (_a) {
|
|
21
|
+
// Fall through to search
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
// Search by name
|
|
25
|
+
const params = {
|
|
26
|
+
q: input,
|
|
27
|
+
limit: 5,
|
|
28
|
+
responseFormat: "json",
|
|
29
|
+
fields: `_id,${slotDef.nameField}`,
|
|
30
|
+
};
|
|
31
|
+
// If parent context is active, filter by it
|
|
32
|
+
if (slotDef.parent) {
|
|
33
|
+
const parentEntry = getContextEntry(slotDef.parent);
|
|
34
|
+
if (parentEntry) {
|
|
35
|
+
const parentSlot = getSlot(slotDef.parent);
|
|
36
|
+
if (parentSlot) {
|
|
37
|
+
const filterField = parentSlot.injectAsFilterField[slotDef.collection];
|
|
38
|
+
if (filterField) {
|
|
39
|
+
params[filterField] = parentEntry.id;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const res = await apiCallHandler(slotDef.module, slotDef.collection, "get", null, params);
|
|
46
|
+
if ((res === null || res === void 0 ? void 0 : res.payload) && Array.isArray(res.payload)) {
|
|
47
|
+
return res.payload.map((e) => ({
|
|
48
|
+
id: e._id,
|
|
49
|
+
name: e[slotDef.nameField] || e._id,
|
|
50
|
+
}));
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (_b) {
|
|
54
|
+
// API error — return empty
|
|
55
|
+
}
|
|
56
|
+
return [];
|
|
57
|
+
}
|
|
58
|
+
export function validateHierarchy(slot) {
|
|
59
|
+
const slotDef = getSlot(slot);
|
|
60
|
+
if (!(slotDef === null || slotDef === void 0 ? void 0 : slotDef.parent))
|
|
61
|
+
return null;
|
|
62
|
+
const parentEntry = getContextEntry(slotDef.parent);
|
|
63
|
+
if (!parentEntry) {
|
|
64
|
+
return `Warning: Setting "${slot}" without parent "${slotDef.parent}" context. Results may not be scoped correctly.`;
|
|
65
|
+
}
|
|
66
|
+
return null;
|
|
67
|
+
}
|
|
68
|
+
export function getDependentSlots(slot) {
|
|
69
|
+
return getChildSlots(slot).map((s) => s.slot);
|
|
70
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import os from "os";
|
|
4
|
+
const CONTEXT_PATH = path.join(os.homedir(), ".config", "ayoune", "context.json");
|
|
5
|
+
function ensureDir() {
|
|
6
|
+
const dir = path.dirname(CONTEXT_PATH);
|
|
7
|
+
if (!existsSync(dir)) {
|
|
8
|
+
mkdirSync(dir, { recursive: true });
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
export function loadContext() {
|
|
12
|
+
if (!existsSync(CONTEXT_PATH)) {
|
|
13
|
+
return { active: {} };
|
|
14
|
+
}
|
|
15
|
+
try {
|
|
16
|
+
const raw = readFileSync(CONTEXT_PATH, "utf-8");
|
|
17
|
+
return JSON.parse(raw);
|
|
18
|
+
}
|
|
19
|
+
catch (_a) {
|
|
20
|
+
return { active: {} };
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export function saveContext(data) {
|
|
24
|
+
ensureDir();
|
|
25
|
+
writeFileSync(CONTEXT_PATH, JSON.stringify(data, null, 2), "utf-8");
|
|
26
|
+
}
|
|
27
|
+
export function getContextEntry(slot) {
|
|
28
|
+
const ctx = loadContext();
|
|
29
|
+
return ctx.active[slot];
|
|
30
|
+
}
|
|
31
|
+
export function setContextEntry(slot, entry) {
|
|
32
|
+
const ctx = loadContext();
|
|
33
|
+
ctx.active[slot] = entry;
|
|
34
|
+
saveContext(ctx);
|
|
35
|
+
}
|
|
36
|
+
export function unsetContextEntry(slot) {
|
|
37
|
+
const ctx = loadContext();
|
|
38
|
+
delete ctx.active[slot];
|
|
39
|
+
saveContext(ctx);
|
|
40
|
+
}
|
|
41
|
+
export function clearAllContext() {
|
|
42
|
+
saveContext({ active: {} });
|
|
43
|
+
}
|
|
44
|
+
export function getActiveContext() {
|
|
45
|
+
return loadContext().active;
|
|
46
|
+
}
|