@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
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { api, getModuleBaseUrl } from "../api/apiClient.js";
|
|
2
2
|
import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
|
|
3
3
|
import { saveFile } from "../helpers/saveFile.js";
|
|
4
|
+
import { secureStorage } from "../helpers/secureStorage.js";
|
|
4
5
|
import { spinner } from "../../index.js";
|
|
5
|
-
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
6
|
+
import { EXIT_GENERAL_ERROR, EXIT_PERMISSION_DENIED } from "../exitCodes.js";
|
|
7
|
+
import { cliError } from "../helpers/cliError.js";
|
|
6
8
|
export function createActionsCommand(program) {
|
|
7
9
|
program
|
|
8
10
|
.command("actions [search]")
|
|
@@ -26,7 +28,7 @@ Examples:
|
|
|
26
28
|
.option("-p, --page <number>", "Page", parseInt, 1)
|
|
27
29
|
.option("-l, --limit <number>", "Limit", parseInt, 100)
|
|
28
30
|
.action(async (search, options) => {
|
|
29
|
-
var _a;
|
|
31
|
+
var _a, _b, _c;
|
|
30
32
|
try {
|
|
31
33
|
const opts = { ...program.opts(), ...options };
|
|
32
34
|
spinner.start({ text: "Fetching API actions...", color: "magenta" });
|
|
@@ -40,10 +42,40 @@ Examples:
|
|
|
40
42
|
};
|
|
41
43
|
if (search)
|
|
42
44
|
params.q = search;
|
|
43
|
-
//
|
|
44
|
-
const
|
|
45
|
+
// Try su module first (full access), fall back to config module (limited access)
|
|
46
|
+
const modules = ["su", "config"];
|
|
47
|
+
let res = null;
|
|
48
|
+
let permissionDenied = false;
|
|
49
|
+
for (const mod of modules) {
|
|
50
|
+
try {
|
|
51
|
+
const token = secureStorage.getItem("token") || "";
|
|
52
|
+
const response = await api({
|
|
53
|
+
baseURL: getModuleBaseUrl(mod),
|
|
54
|
+
method: "get",
|
|
55
|
+
url: "ayouneapiactions",
|
|
56
|
+
params,
|
|
57
|
+
headers: { Authorization: `Bearer ${token}` },
|
|
58
|
+
});
|
|
59
|
+
res = response.data;
|
|
60
|
+
if (res === null || res === void 0 ? void 0 : res.payload)
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
// On 401/403 permission denied, try next module
|
|
65
|
+
if (((_a = e.response) === null || _a === void 0 ? void 0 : _a.status) === 403 || ((_b = e.response) === null || _b === void 0 ? void 0 : _b.status) === 401) {
|
|
66
|
+
permissionDenied = true;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
// For other errors (network, 500, etc.), only throw on last module
|
|
70
|
+
if (mod === modules[modules.length - 1])
|
|
71
|
+
throw e;
|
|
72
|
+
}
|
|
73
|
+
}
|
|
45
74
|
if (!(res === null || res === void 0 ? void 0 : res.payload)) {
|
|
46
|
-
|
|
75
|
+
if (permissionDenied) {
|
|
76
|
+
cliError("Permission denied: you do not have access to query API actions. Contact your administrator for the required rights.", EXIT_PERMISSION_DENIED, "permission_denied");
|
|
77
|
+
}
|
|
78
|
+
spinner.error({ text: "No API actions found" });
|
|
47
79
|
return;
|
|
48
80
|
}
|
|
49
81
|
let actions = Array.isArray(res.payload) ? res.payload : [res.payload];
|
|
@@ -91,7 +123,7 @@ Examples:
|
|
|
91
123
|
})),
|
|
92
124
|
meta: {
|
|
93
125
|
...res.meta,
|
|
94
|
-
pageInfo: { ...(
|
|
126
|
+
pageInfo: { ...(_c = res.meta) === null || _c === void 0 ? void 0 : _c.pageInfo, totalEntries: actions.length },
|
|
95
127
|
},
|
|
96
128
|
};
|
|
97
129
|
const { plainResult, result, content } = handleResponseFormatOptions(opts, formattedRes);
|
|
@@ -102,8 +134,7 @@ Examples:
|
|
|
102
134
|
}
|
|
103
135
|
}
|
|
104
136
|
catch (e) {
|
|
105
|
-
|
|
106
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
137
|
+
cliError(e.message || "Failed to fetch API actions", EXIT_GENERAL_ERROR);
|
|
107
138
|
}
|
|
108
139
|
});
|
|
109
140
|
}
|
|
@@ -2,9 +2,11 @@ import { apiCallHandler } from "../api/apiCallHandler.js";
|
|
|
2
2
|
import { api } from "../api/apiClient.js";
|
|
3
3
|
import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
|
|
4
4
|
import { saveFile } from "../helpers/saveFile.js";
|
|
5
|
-
import {
|
|
5
|
+
import { secureStorage } from "../helpers/secureStorage.js";
|
|
6
6
|
import { spinner } from "../../index.js";
|
|
7
7
|
import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
|
|
8
|
+
import { cliError } from "../helpers/cliError.js";
|
|
9
|
+
import { getContextSummary, getContextForAI, hasActiveContext } from "../helpers/contextInjector.js";
|
|
8
10
|
const AI_HOST = "ai.ayoune.app";
|
|
9
11
|
export function createAiCommand(program) {
|
|
10
12
|
const ai = program
|
|
@@ -17,7 +19,7 @@ export function createAiCommand(program) {
|
|
|
17
19
|
try {
|
|
18
20
|
const opts = { ...program.opts() };
|
|
19
21
|
spinner.start({ text: "Fetching AI actions...", color: "magenta" });
|
|
20
|
-
const res = await apiCallHandler("
|
|
22
|
+
const res = await apiCallHandler("su", "ayouneapiactions", "get", null, {
|
|
21
23
|
q: "ai",
|
|
22
24
|
limit: 200,
|
|
23
25
|
responseFormat: "json",
|
|
@@ -43,8 +45,7 @@ export function createAiCommand(program) {
|
|
|
43
45
|
spinner.stop();
|
|
44
46
|
}
|
|
45
47
|
catch (e) {
|
|
46
|
-
|
|
47
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
48
|
+
cliError(e.message || "Failed to fetch AI actions", EXIT_GENERAL_ERROR);
|
|
48
49
|
}
|
|
49
50
|
});
|
|
50
51
|
// ay ai conversations — list AI conversations
|
|
@@ -57,7 +58,7 @@ export function createAiCommand(program) {
|
|
|
57
58
|
try {
|
|
58
59
|
const opts = { ...program.opts(), ...options };
|
|
59
60
|
spinner.start({ text: "Fetching AI conversations...", color: "magenta" });
|
|
60
|
-
const res = await apiCallHandler("ai", "
|
|
61
|
+
const res = await apiCallHandler("ai", "aiconversations", "get", null, {
|
|
61
62
|
page: opts.page,
|
|
62
63
|
limit: opts.limit,
|
|
63
64
|
responseFormat: opts.responseFormat,
|
|
@@ -72,8 +73,7 @@ export function createAiCommand(program) {
|
|
|
72
73
|
await saveFile("ai-conversations", opts, res);
|
|
73
74
|
}
|
|
74
75
|
catch (e) {
|
|
75
|
-
|
|
76
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
76
|
+
cliError(e.message || "Failed to list conversations", EXIT_GENERAL_ERROR);
|
|
77
77
|
}
|
|
78
78
|
});
|
|
79
79
|
// ay ai prompts — list AI prompt templates
|
|
@@ -86,7 +86,7 @@ export function createAiCommand(program) {
|
|
|
86
86
|
try {
|
|
87
87
|
const opts = { ...program.opts(), ...options };
|
|
88
88
|
spinner.start({ text: "Fetching AI prompts...", color: "magenta" });
|
|
89
|
-
const res = await apiCallHandler("ai", "
|
|
89
|
+
const res = await apiCallHandler("ai", "aiprompts", "get", null, {
|
|
90
90
|
page: opts.page,
|
|
91
91
|
limit: opts.limit,
|
|
92
92
|
responseFormat: opts.responseFormat,
|
|
@@ -101,8 +101,7 @@ export function createAiCommand(program) {
|
|
|
101
101
|
await saveFile("ai-prompts", opts, res);
|
|
102
102
|
}
|
|
103
103
|
catch (e) {
|
|
104
|
-
|
|
105
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
104
|
+
cliError(e.message || "Failed to list prompts", EXIT_GENERAL_ERROR);
|
|
106
105
|
}
|
|
107
106
|
});
|
|
108
107
|
// ay ai ask <prompt> — send a prompt to AI
|
|
@@ -120,6 +119,10 @@ export function createAiCommand(program) {
|
|
|
120
119
|
body.conversationId = opts.conversation;
|
|
121
120
|
if (opts.model)
|
|
122
121
|
body.model = opts.model;
|
|
122
|
+
if (hasActiveContext()) {
|
|
123
|
+
body.context = getContextForAI();
|
|
124
|
+
body.prompt = `${getContextSummary()}\n\nUser question: ${prompt}`;
|
|
125
|
+
}
|
|
123
126
|
const res = await apiCallHandler("ai", "ask", "post", body, {
|
|
124
127
|
responseFormat: opts.responseFormat,
|
|
125
128
|
verbosity: opts.verbosity,
|
|
@@ -132,8 +135,7 @@ export function createAiCommand(program) {
|
|
|
132
135
|
await saveFile("ai-ask", opts, res);
|
|
133
136
|
}
|
|
134
137
|
catch (e) {
|
|
135
|
-
|
|
136
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
138
|
+
cliError(e.message || "AI request failed", EXIT_GENERAL_ERROR);
|
|
137
139
|
}
|
|
138
140
|
});
|
|
139
141
|
// ay ai generate <type> <prompt> — generate content
|
|
@@ -156,8 +158,7 @@ Examples:
|
|
|
156
158
|
};
|
|
157
159
|
const host = typeHostMap[type];
|
|
158
160
|
if (!host) {
|
|
159
|
-
|
|
160
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
161
|
+
cliError(`Unknown type: ${type}. Use: text, image, video`, EXIT_GENERAL_ERROR);
|
|
161
162
|
}
|
|
162
163
|
spinner.start({ text: `Generating ${type}...`, color: "magenta" });
|
|
163
164
|
const response = await api({
|
|
@@ -170,7 +171,7 @@ Examples:
|
|
|
170
171
|
verbosity: opts.verbosity,
|
|
171
172
|
},
|
|
172
173
|
headers: {
|
|
173
|
-
Authorization: `Bearer ${
|
|
174
|
+
Authorization: `Bearer ${secureStorage.getItem("token")}`,
|
|
174
175
|
},
|
|
175
176
|
});
|
|
176
177
|
const res = response.data;
|
|
@@ -181,8 +182,7 @@ Examples:
|
|
|
181
182
|
await saveFile(`ai-generate-${type}`, opts, res);
|
|
182
183
|
}
|
|
183
184
|
catch (e) {
|
|
184
|
-
|
|
185
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
185
|
+
cliError(e.message || `${type} generation failed`, EXIT_GENERAL_ERROR);
|
|
186
186
|
}
|
|
187
187
|
});
|
|
188
188
|
}
|
|
@@ -3,6 +3,7 @@ import path from "path";
|
|
|
3
3
|
import os from "os";
|
|
4
4
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
5
5
|
import { spinner } from "../../index.js";
|
|
6
|
+
import { cliError } from "../helpers/cliError.js";
|
|
6
7
|
const ALIASES_PATH = path.join(os.homedir(), ".config", "ayoune", "aliases.json");
|
|
7
8
|
export function loadAliases() {
|
|
8
9
|
if (!existsSync(ALIASES_PATH)) {
|
|
@@ -42,8 +43,7 @@ Examples:
|
|
|
42
43
|
spinner.success({ text: `Alias '${name}' set to '${command}'` });
|
|
43
44
|
}
|
|
44
45
|
catch (e) {
|
|
45
|
-
|
|
46
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
46
|
+
cliError(e.message || "Failed to save alias", EXIT_GENERAL_ERROR);
|
|
47
47
|
}
|
|
48
48
|
});
|
|
49
49
|
alias
|
|
@@ -67,16 +67,14 @@ Examples:
|
|
|
67
67
|
try {
|
|
68
68
|
const aliases = loadAliases();
|
|
69
69
|
if (!(name in aliases)) {
|
|
70
|
-
|
|
71
|
-
process.exit(EXIT_MISUSE);
|
|
70
|
+
cliError(`Alias '${name}' not found`, EXIT_MISUSE);
|
|
72
71
|
}
|
|
73
72
|
delete aliases[name];
|
|
74
73
|
saveAliases(aliases);
|
|
75
74
|
spinner.success({ text: `Alias '${name}' removed` });
|
|
76
75
|
}
|
|
77
76
|
catch (e) {
|
|
78
|
-
|
|
79
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
77
|
+
cliError(e.message || "Failed to remove alias", EXIT_GENERAL_ERROR);
|
|
80
78
|
}
|
|
81
79
|
});
|
|
82
80
|
}
|
|
@@ -4,8 +4,8 @@ import { handleAuditOperation } from "../operations/handleAuditOperation.js";
|
|
|
4
4
|
import { promptAudits } from "../prompts/promptAudits.js";
|
|
5
5
|
import { handleSingleAuditOperation } from "../operations/handleSingleAuditOperation.js";
|
|
6
6
|
import yaml from "js-yaml";
|
|
7
|
-
import { spinner } from "../../index.js";
|
|
8
7
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
8
|
+
import { cliError } from "../helpers/cliError.js";
|
|
9
9
|
export function createAuditCommand(program) {
|
|
10
10
|
program
|
|
11
11
|
.command("audit")
|
|
@@ -20,20 +20,17 @@ Examples:
|
|
|
20
20
|
.action(async (collection, id, options) => {
|
|
21
21
|
try {
|
|
22
22
|
if (!collection) {
|
|
23
|
-
|
|
24
|
-
process.exit(EXIT_MISUSE);
|
|
23
|
+
cliError("Missing required argument: collection. Run a list or get command first, or provide it explicitly.", EXIT_MISUSE);
|
|
25
24
|
}
|
|
26
25
|
if (!id) {
|
|
27
|
-
|
|
28
|
-
process.exit(EXIT_MISUSE);
|
|
26
|
+
cliError("Missing required argument: id. Provide an entry ID explicitly.", EXIT_MISUSE);
|
|
29
27
|
}
|
|
30
28
|
const opts = { ...program.opts(), ...options };
|
|
31
29
|
const { data, content, result, meta } = await handleAuditOperation(collection, id, {
|
|
32
30
|
...opts,
|
|
33
31
|
});
|
|
34
32
|
if (!process.stdin.isTTY) {
|
|
35
|
-
|
|
36
|
-
process.exit(EXIT_MISUSE);
|
|
33
|
+
cliError("The audit command requires an interactive terminal for audit selection", EXIT_MISUSE);
|
|
37
34
|
}
|
|
38
35
|
const selectedAudit = await promptAudits(result);
|
|
39
36
|
const { singleData, singleContent, singleResult, singleMeta } = await handleSingleAuditOperation(collection, id, selectedAudit, {
|
|
@@ -42,8 +39,7 @@ Examples:
|
|
|
42
39
|
console.log(yaml.dump(singleContent));
|
|
43
40
|
}
|
|
44
41
|
catch (e) {
|
|
45
|
-
|
|
46
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
42
|
+
cliError(e.message || "An unexpected error occurred", EXIT_GENERAL_ERROR);
|
|
47
43
|
}
|
|
48
44
|
});
|
|
49
45
|
}
|
|
@@ -6,6 +6,7 @@ import { handleDeleteSingleOperation } from "../operations/handleDeleteSingleOpe
|
|
|
6
6
|
import { saveFile } from "../helpers/saveFile.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
|
async function readStdin() {
|
|
10
11
|
const chunks = [];
|
|
11
12
|
for await (const chunk of process.stdin) {
|
|
@@ -42,8 +43,7 @@ Examples:
|
|
|
42
43
|
idList.push(...stdinIds);
|
|
43
44
|
}
|
|
44
45
|
if (idList.length === 0) {
|
|
45
|
-
|
|
46
|
-
process.exit(EXIT_MISUSE);
|
|
46
|
+
cliError("No IDs provided", EXIT_MISUSE);
|
|
47
47
|
}
|
|
48
48
|
spinner.start({ text: `Fetching ${idList.length} entries from ${collection}...`, color: "magenta" });
|
|
49
49
|
const results = [];
|
|
@@ -69,8 +69,7 @@ Examples:
|
|
|
69
69
|
await saveFile("batch-get", opts, res);
|
|
70
70
|
}
|
|
71
71
|
catch (e) {
|
|
72
|
-
|
|
73
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
72
|
+
cliError(e.message || "Batch get failed", EXIT_GENERAL_ERROR);
|
|
74
73
|
}
|
|
75
74
|
});
|
|
76
75
|
// ay batch delete <collection> <ids>
|
|
@@ -93,8 +92,7 @@ Examples:
|
|
|
93
92
|
idList.push(...stdinIds);
|
|
94
93
|
}
|
|
95
94
|
if (idList.length === 0) {
|
|
96
|
-
|
|
97
|
-
process.exit(EXIT_MISUSE);
|
|
95
|
+
cliError("No IDs provided", EXIT_MISUSE);
|
|
98
96
|
}
|
|
99
97
|
// Confirmation
|
|
100
98
|
if (!opts.force && process.stdin.isTTY) {
|
|
@@ -130,8 +128,7 @@ Examples:
|
|
|
130
128
|
process.exit(EXIT_GENERAL_ERROR);
|
|
131
129
|
}
|
|
132
130
|
catch (e) {
|
|
133
|
-
|
|
134
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
131
|
+
cliError(e.message || "Batch delete failed", EXIT_GENERAL_ERROR);
|
|
135
132
|
}
|
|
136
133
|
});
|
|
137
134
|
// ay batch update <collection> --body-file <file>
|
|
@@ -158,8 +155,7 @@ Examples:
|
|
|
158
155
|
entries = JSON.parse(opts.body);
|
|
159
156
|
}
|
|
160
157
|
catch (_a) {
|
|
161
|
-
|
|
162
|
-
process.exit(EXIT_MISUSE);
|
|
158
|
+
cliError("Invalid JSON in --body", EXIT_MISUSE);
|
|
163
159
|
}
|
|
164
160
|
}
|
|
165
161
|
if (opts.bodyFile) {
|
|
@@ -169,8 +165,7 @@ Examples:
|
|
|
169
165
|
entries = JSON.parse(content);
|
|
170
166
|
}
|
|
171
167
|
catch (_b) {
|
|
172
|
-
|
|
173
|
-
process.exit(EXIT_MISUSE);
|
|
168
|
+
cliError(`Invalid JSON in file: ${opts.bodyFile}`, EXIT_MISUSE);
|
|
174
169
|
}
|
|
175
170
|
}
|
|
176
171
|
if (opts.bodyStdin && !process.stdin.isTTY) {
|
|
@@ -180,14 +175,12 @@ Examples:
|
|
|
180
175
|
entries = JSON.parse(stdinContent);
|
|
181
176
|
}
|
|
182
177
|
catch (_c) {
|
|
183
|
-
|
|
184
|
-
process.exit(EXIT_MISUSE);
|
|
178
|
+
cliError("Invalid JSON from stdin", EXIT_MISUSE);
|
|
185
179
|
}
|
|
186
180
|
}
|
|
187
181
|
}
|
|
188
182
|
if (!Array.isArray(entries) || entries.length === 0) {
|
|
189
|
-
|
|
190
|
-
process.exit(EXIT_MISUSE);
|
|
183
|
+
cliError("Provide a JSON array of entries with _id fields", EXIT_MISUSE);
|
|
191
184
|
}
|
|
192
185
|
spinner.start({ text: `Updating ${entries.length} entries in ${collection}...`, color: "magenta" });
|
|
193
186
|
let successCount = 0;
|
|
@@ -211,8 +204,7 @@ Examples:
|
|
|
211
204
|
process.exit(EXIT_GENERAL_ERROR);
|
|
212
205
|
}
|
|
213
206
|
catch (e) {
|
|
214
|
-
|
|
215
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
207
|
+
cliError(e.message || "Batch update failed", EXIT_GENERAL_ERROR);
|
|
216
208
|
}
|
|
217
209
|
});
|
|
218
210
|
// ay batch create <collection> --body-file <file>
|
|
@@ -238,8 +230,7 @@ Examples:
|
|
|
238
230
|
entries = JSON.parse(opts.body);
|
|
239
231
|
}
|
|
240
232
|
catch (_a) {
|
|
241
|
-
|
|
242
|
-
process.exit(EXIT_MISUSE);
|
|
233
|
+
cliError("Invalid JSON in --body", EXIT_MISUSE);
|
|
243
234
|
}
|
|
244
235
|
}
|
|
245
236
|
if (opts.bodyFile) {
|
|
@@ -249,8 +240,7 @@ Examples:
|
|
|
249
240
|
entries = JSON.parse(content);
|
|
250
241
|
}
|
|
251
242
|
catch (_b) {
|
|
252
|
-
|
|
253
|
-
process.exit(EXIT_MISUSE);
|
|
243
|
+
cliError(`Invalid JSON in file: ${opts.bodyFile}`, EXIT_MISUSE);
|
|
254
244
|
}
|
|
255
245
|
}
|
|
256
246
|
if (opts.bodyStdin && !process.stdin.isTTY) {
|
|
@@ -260,14 +250,12 @@ Examples:
|
|
|
260
250
|
entries = JSON.parse(stdinContent);
|
|
261
251
|
}
|
|
262
252
|
catch (_c) {
|
|
263
|
-
|
|
264
|
-
process.exit(EXIT_MISUSE);
|
|
253
|
+
cliError("Invalid JSON from stdin", EXIT_MISUSE);
|
|
265
254
|
}
|
|
266
255
|
}
|
|
267
256
|
}
|
|
268
257
|
if (!Array.isArray(entries) || entries.length === 0) {
|
|
269
|
-
|
|
270
|
-
process.exit(EXIT_MISUSE);
|
|
258
|
+
cliError("Provide a JSON array of entries to create", EXIT_MISUSE);
|
|
271
259
|
}
|
|
272
260
|
spinner.start({ text: `Creating ${entries.length} entries in ${collection}...`, color: "magenta" });
|
|
273
261
|
let successCount = 0;
|
|
@@ -297,8 +285,7 @@ Examples:
|
|
|
297
285
|
process.exit(EXIT_GENERAL_ERROR);
|
|
298
286
|
}
|
|
299
287
|
catch (e) {
|
|
300
|
-
|
|
301
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
288
|
+
cliError(e.message || "Batch create failed", EXIT_GENERAL_ERROR);
|
|
302
289
|
}
|
|
303
290
|
});
|
|
304
291
|
}
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { cliError } from "../helpers/cliError.js";
|
|
1
2
|
const BASH_COMPLETION = `###-begin-ay-completions-###
|
|
2
3
|
_ay_completions() {
|
|
3
4
|
local cur commands
|
|
4
5
|
COMPREPLY=()
|
|
5
6
|
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
6
|
-
commands="modules list get edit copy create describe audit stream events storage whoami login logout completions alias config actions exec ai services deploy monitor delete update batch search webhooks jobs export users sync permissions templates"
|
|
7
|
+
commands="modules list get edit copy create describe audit stream events storage whoami login logout completions alias config actions exec ai services deploy monitor delete update batch search webhooks jobs export users sync permissions templates context"
|
|
7
8
|
|
|
8
9
|
if [[ \${COMP_CWORD} -eq 1 ]]; then
|
|
9
10
|
COMPREPLY=( $(compgen -W "\${commands}" -- "\${cur}") )
|
|
@@ -49,6 +50,7 @@ _ay() {
|
|
|
49
50
|
'sync:Synchronize platform data across systems'
|
|
50
51
|
'permissions:Manage permissions and access requests'
|
|
51
52
|
'templates:Manage platform templates'
|
|
53
|
+
'context:Manage active entity context'
|
|
52
54
|
)
|
|
53
55
|
_describe 'command' commands
|
|
54
56
|
}
|
|
@@ -89,6 +91,7 @@ complete -c ay -n '__fish_use_subcommand' -a users -d 'Manage users, teams, and
|
|
|
89
91
|
complete -c ay -n '__fish_use_subcommand' -a sync -d 'Synchronize platform data across systems'
|
|
90
92
|
complete -c ay -n '__fish_use_subcommand' -a permissions -d 'Manage permissions and access requests'
|
|
91
93
|
complete -c ay -n '__fish_use_subcommand' -a templates -d 'Manage platform templates'
|
|
94
|
+
complete -c ay -n '__fish_use_subcommand' -a context -d 'Manage active entity context'
|
|
92
95
|
###-end-ay-completions-###`;
|
|
93
96
|
const POWERSHELL_COMPLETION = `###-begin-ay-completions-###
|
|
94
97
|
Register-ArgumentCompleter -CommandName ay -ScriptBlock {
|
|
@@ -128,6 +131,7 @@ Register-ArgumentCompleter -CommandName ay -ScriptBlock {
|
|
|
128
131
|
@{ Name = 'sync'; Description = 'Synchronize platform data across systems' }
|
|
129
132
|
@{ Name = 'permissions'; Description = 'Manage permissions and access requests' }
|
|
130
133
|
@{ Name = 'templates'; Description = 'Manage platform templates' }
|
|
134
|
+
@{ Name = 'context'; Description = 'Manage active entity context' }
|
|
131
135
|
)
|
|
132
136
|
$commands | Where-Object { $_.Name -like "$wordToComplete*" } | ForEach-Object {
|
|
133
137
|
[System.Management.Automation.CompletionResult]::new($_.Name, $_.Name, 'ParameterValue', $_.Description)
|
|
@@ -162,8 +166,7 @@ Examples:
|
|
|
162
166
|
console.log(POWERSHELL_COMPLETION);
|
|
163
167
|
break;
|
|
164
168
|
default:
|
|
165
|
-
|
|
166
|
-
process.exit(2);
|
|
169
|
+
cliError(`Unknown shell: ${shell}. Supported: bash, zsh, fish, powershell`, 2);
|
|
167
170
|
}
|
|
168
171
|
});
|
|
169
172
|
}
|
|
@@ -3,6 +3,7 @@ import inquirer from "inquirer";
|
|
|
3
3
|
import { loadConfig, saveConfig } from "../helpers/configLoader.js";
|
|
4
4
|
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../exitCodes.js";
|
|
5
5
|
import { spinner } from "../../index.js";
|
|
6
|
+
import { cliError } from "../helpers/cliError.js";
|
|
6
7
|
const SETTABLE_KEYS = {
|
|
7
8
|
responseFormat: { type: "string", choices: ["json", "csv", "yaml", "table"] },
|
|
8
9
|
verbosity: { type: "string", choices: ["default", "extended", "minimal"] },
|
|
@@ -113,8 +114,7 @@ Examples:
|
|
|
113
114
|
spinner.success({ text: "Defaults saved" });
|
|
114
115
|
}
|
|
115
116
|
catch (e) {
|
|
116
|
-
|
|
117
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
117
|
+
cliError(e.message || "Failed to save config", EXIT_GENERAL_ERROR);
|
|
118
118
|
}
|
|
119
119
|
});
|
|
120
120
|
config
|
|
@@ -125,20 +125,17 @@ Examples:
|
|
|
125
125
|
try {
|
|
126
126
|
const meta = SETTABLE_KEYS[key];
|
|
127
127
|
if (!meta) {
|
|
128
|
-
|
|
129
|
-
process.exit(EXIT_MISUSE);
|
|
128
|
+
cliError(`Unknown config key '${key}'. Valid keys: ${Object.keys(SETTABLE_KEYS).join(", ")}`, EXIT_MISUSE);
|
|
130
129
|
}
|
|
131
130
|
let parsed = value;
|
|
132
131
|
if (meta.type === "boolean") {
|
|
133
132
|
parsed = parseBoolean(value);
|
|
134
133
|
if (parsed === null) {
|
|
135
|
-
|
|
136
|
-
process.exit(EXIT_MISUSE);
|
|
134
|
+
cliError(`Invalid boolean value '${value}'. Use true/false, yes/no, 1/0, on/off`, EXIT_MISUSE);
|
|
137
135
|
}
|
|
138
136
|
}
|
|
139
137
|
else if (meta.choices && !meta.choices.includes(value)) {
|
|
140
|
-
|
|
141
|
-
process.exit(EXIT_MISUSE);
|
|
138
|
+
cliError(`Invalid value '${value}' for ${key}. Choices: ${meta.choices.join(", ")}`, EXIT_MISUSE);
|
|
142
139
|
}
|
|
143
140
|
const cfg = loadConfig();
|
|
144
141
|
cfg.defaults = (_a = cfg.defaults) !== null && _a !== void 0 ? _a : {};
|
|
@@ -147,8 +144,7 @@ Examples:
|
|
|
147
144
|
spinner.success({ text: `${key} set to '${parsed}'` });
|
|
148
145
|
}
|
|
149
146
|
catch (e) {
|
|
150
|
-
|
|
151
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
147
|
+
cliError(e.message || "Failed to save config", EXIT_GENERAL_ERROR);
|
|
152
148
|
}
|
|
153
149
|
});
|
|
154
150
|
config
|
|
@@ -157,8 +153,7 @@ Examples:
|
|
|
157
153
|
.action((key) => {
|
|
158
154
|
var _a;
|
|
159
155
|
if (!SETTABLE_KEYS[key]) {
|
|
160
|
-
|
|
161
|
-
process.exit(EXIT_MISUSE);
|
|
156
|
+
cliError(`Unknown config key '${key}'. Valid keys: ${Object.keys(SETTABLE_KEYS).join(", ")}`, EXIT_MISUSE);
|
|
162
157
|
}
|
|
163
158
|
const cfg = loadConfig();
|
|
164
159
|
const value = (_a = cfg.defaults) === null || _a === void 0 ? void 0 : _a[key];
|
|
@@ -201,8 +196,7 @@ Examples:
|
|
|
201
196
|
spinner.success({ text: "All defaults have been reset" });
|
|
202
197
|
}
|
|
203
198
|
catch (e) {
|
|
204
|
-
|
|
205
|
-
process.exit(EXIT_GENERAL_ERROR);
|
|
199
|
+
cliError(e.message || "Failed to reset config", EXIT_GENERAL_ERROR);
|
|
206
200
|
}
|
|
207
201
|
});
|
|
208
202
|
}
|