@tolinax/ayoune-cli 2026.8.2 → 2026.10.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/lib/api/apiCallHandler.js +1 -1
- package/lib/api/apiClient.js +74 -62
- package/lib/commands/_registry.js +296 -0
- package/lib/commands/aggregate/_shared.js +21 -0
- package/lib/commands/aggregate/_stageBuilders.js +295 -0
- package/lib/commands/aggregate/exec.js +51 -0
- package/lib/commands/aggregate/index.js +38 -0
- package/lib/commands/aggregate/list.js +43 -0
- package/lib/commands/aggregate/models.js +43 -0
- package/lib/commands/aggregate/run.js +53 -0
- package/lib/commands/aggregate/save.js +53 -0
- package/lib/commands/aggregate/validate.js +47 -0
- package/lib/commands/aggregate/wizard.js +174 -0
- package/lib/commands/createAggregateCommand.js +5 -658
- package/lib/commands/createDeployCommand.js +5 -642
- package/lib/commands/createProgram.js +251 -161
- package/lib/commands/createSelfHostUpdateCommand.js +1 -20
- package/lib/commands/createServicesCommand.js +4 -5
- package/lib/commands/createSetupCommand.js +57 -5
- package/lib/commands/createWhoAmICommand.js +5 -5
- package/lib/commands/deploy/_token.js +8 -0
- package/lib/commands/deploy/alerts.js +43 -0
- package/lib/commands/deploy/clusters.js +62 -0
- package/lib/commands/deploy/dashboard.js +31 -0
- package/lib/commands/deploy/deployments.js +216 -0
- package/lib/commands/deploy/index.js +31 -0
- package/lib/commands/deploy/pipelines.js +82 -0
- package/lib/commands/deploy/plans.js +147 -0
- package/lib/commands/deploy/pods.js +70 -0
- package/lib/commands/deploy/repos.js +63 -0
- package/lib/commands/functions/_shared.js +38 -0
- package/lib/commands/functions/_validateSource.js +50 -0
- package/lib/commands/functions/create.js +109 -0
- package/lib/commands/functions/delete.js +40 -0
- package/lib/commands/functions/deploy.js +91 -0
- package/lib/commands/functions/get.js +31 -0
- package/lib/commands/functions/index.js +48 -0
- package/lib/commands/functions/invoke.js +75 -0
- package/lib/commands/functions/list.js +41 -0
- package/lib/commands/functions/logs.js +76 -0
- package/lib/commands/functions/rollback.js +44 -0
- package/lib/commands/functions/versions.js +32 -0
- package/lib/commands/local/_context.js +42 -0
- package/lib/commands/local/down.js +50 -0
- package/lib/commands/local/exec.js +45 -0
- package/lib/commands/local/index.js +40 -0
- package/lib/commands/local/logs.js +38 -0
- package/lib/commands/local/ps.js +41 -0
- package/lib/commands/local/pull.js +40 -0
- package/lib/commands/local/restart.js +31 -0
- package/lib/commands/local/up.js +80 -0
- package/lib/commands/provision/_detectTools.js +52 -0
- package/lib/commands/provision/_stateFile.js +36 -0
- package/lib/commands/provision/_wizard.js +60 -0
- package/lib/commands/provision/aws.js +107 -0
- package/lib/commands/provision/azure.js +113 -0
- package/lib/commands/provision/destroy.js +119 -0
- package/lib/commands/provision/digitalocean.js +82 -0
- package/lib/commands/provision/gcp.js +118 -0
- package/lib/commands/provision/hetzner.js +220 -0
- package/lib/commands/provision/index.js +44 -0
- package/lib/commands/provision/status.js +44 -0
- package/lib/helpers/dateFormat.js +119 -0
- package/lib/helpers/dockerCompose.js +143 -0
- package/lib/helpers/formatDocument.js +4 -5
- package/lib/helpers/logo.js +86 -13
- package/lib/helpers/saveFile.js +4 -9
- package/lib/models/getModelsInModules.js +6 -8
- package/lib/models/getModuleFromCollection.js +2 -2
- package/lib/operations/handleCollectionOperation.js +2 -3
- package/package.json +2 -12
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
// `ay aggregate wizard` — interactive pipeline builder.
|
|
2
|
+
//
|
|
3
|
+
// 5-step flow:
|
|
4
|
+
// 1. List + select target model
|
|
5
|
+
// 2. Fetch + display fields for that model (preview)
|
|
6
|
+
// 3. Loop: pick stage type → run the stage builder → append to pipeline
|
|
7
|
+
// until the user picks "Done"
|
|
8
|
+
// 4. Run a 5-row preview of the assembled pipeline so the user sees real
|
|
9
|
+
// output before committing
|
|
10
|
+
// 5. Choose: execute / save / both / print / cancel
|
|
11
|
+
//
|
|
12
|
+
// The stage-builder helpers are in `_stageBuilders.ts` so this file stays
|
|
13
|
+
// focused on the orchestration. Wizard requires a TTY — exits with EXIT_MISUSE
|
|
14
|
+
// otherwise.
|
|
15
|
+
import chalk from "chalk";
|
|
16
|
+
import inquirer from "inquirer";
|
|
17
|
+
import { apiCallHandler } from "../../api/apiCallHandler.js";
|
|
18
|
+
import { handleResponseFormatOptions } from "../../helpers/handleResponseFormatOptions.js";
|
|
19
|
+
import { spinner } from "../../../index.js";
|
|
20
|
+
import { EXIT_GENERAL_ERROR, EXIT_MISUSE } from "../../exitCodes.js";
|
|
21
|
+
import { cliError } from "../../helpers/cliError.js";
|
|
22
|
+
import { initializeSettings } from "../../helpers/initializeSettings.js";
|
|
23
|
+
import { wrapAggResult } from "./_shared.js";
|
|
24
|
+
import { buildStage } from "./_stageBuilders.js";
|
|
25
|
+
export function addWizardSubcommand(agg, rootProgram) {
|
|
26
|
+
agg
|
|
27
|
+
.command("wizard")
|
|
28
|
+
.alias("wiz")
|
|
29
|
+
.description("Interactive pipeline builder wizard")
|
|
30
|
+
.action(async (options) => {
|
|
31
|
+
var _a, _b, _c, _d, _e;
|
|
32
|
+
try {
|
|
33
|
+
const opts = { ...rootProgram.opts(), ...options };
|
|
34
|
+
if (!process.stdin.isTTY) {
|
|
35
|
+
cliError("Wizard requires an interactive terminal (TTY)", EXIT_MISUSE);
|
|
36
|
+
}
|
|
37
|
+
// Step 1: Select model
|
|
38
|
+
initializeSettings();
|
|
39
|
+
spinner.start({ text: "Loading models...", color: "magenta" });
|
|
40
|
+
const modelsRes = await apiCallHandler("aggregation", "models", "get");
|
|
41
|
+
spinner.stop();
|
|
42
|
+
const modelChoices = (modelsRes.payload || []).map((m) => ({
|
|
43
|
+
name: `${m.name} ${chalk.dim(`(${m.module})`)}`,
|
|
44
|
+
value: m.name,
|
|
45
|
+
}));
|
|
46
|
+
const { selectedModel } = await inquirer.prompt([
|
|
47
|
+
{
|
|
48
|
+
type: "search-list",
|
|
49
|
+
name: "selectedModel",
|
|
50
|
+
message: "Select a model:",
|
|
51
|
+
choices: modelChoices,
|
|
52
|
+
},
|
|
53
|
+
]);
|
|
54
|
+
// Step 2: Fetch and display fields
|
|
55
|
+
spinner.start({ text: `Loading fields for ${selectedModel}...`, color: "magenta" });
|
|
56
|
+
const fieldsRes = await apiCallHandler("aggregation", `models/${selectedModel}/fields`, "get");
|
|
57
|
+
spinner.stop();
|
|
58
|
+
const fields = ((_a = fieldsRes.payload) === null || _a === void 0 ? void 0 : _a.fields) || [];
|
|
59
|
+
const fieldNames = fields.map((f) => f.field);
|
|
60
|
+
console.log(chalk.cyan(`\n Fields for ${selectedModel}:\n`));
|
|
61
|
+
for (const f of fields) {
|
|
62
|
+
const ref = f.ref ? chalk.dim(` -> ${f.ref}`) : "";
|
|
63
|
+
const req = f.required ? chalk.yellow(" *") : "";
|
|
64
|
+
console.log(` ${chalk.white(f.field)} ${chalk.dim(`(${f.type})`)}${ref}${req}`);
|
|
65
|
+
}
|
|
66
|
+
console.log();
|
|
67
|
+
// Step 3: Build stages iteratively
|
|
68
|
+
const pipeline = [];
|
|
69
|
+
let addMore = true;
|
|
70
|
+
while (addMore) {
|
|
71
|
+
const { stageType } = await inquirer.prompt([
|
|
72
|
+
{
|
|
73
|
+
type: "list",
|
|
74
|
+
name: "stageType",
|
|
75
|
+
message: `Add stage ${pipeline.length + 1}:`,
|
|
76
|
+
choices: [
|
|
77
|
+
{ name: "$match — Filter documents", value: "$match" },
|
|
78
|
+
{ name: "$group — Group and aggregate", value: "$group" },
|
|
79
|
+
{ name: "$sort — Sort results", value: "$sort" },
|
|
80
|
+
{ name: "$project — Include/exclude fields", value: "$project" },
|
|
81
|
+
{ name: "$unwind — Deconstruct array field", value: "$unwind" },
|
|
82
|
+
{ name: "$lookup — Join with another collection", value: "$lookup" },
|
|
83
|
+
{ name: "$limit — Limit results", value: "$limit" },
|
|
84
|
+
{ name: "$skip — Skip results", value: "$skip" },
|
|
85
|
+
{ name: "$count — Count documents", value: "$count" },
|
|
86
|
+
{ name: "$addFields — Add computed fields", value: "$addFields" },
|
|
87
|
+
new inquirer.Separator(),
|
|
88
|
+
{ name: "Raw JSON stage", value: "$raw" },
|
|
89
|
+
new inquirer.Separator(),
|
|
90
|
+
{ name: chalk.green("Done — preview and execute"), value: "$done" },
|
|
91
|
+
],
|
|
92
|
+
},
|
|
93
|
+
]);
|
|
94
|
+
if (stageType === "$done") {
|
|
95
|
+
addMore = false;
|
|
96
|
+
break;
|
|
97
|
+
}
|
|
98
|
+
const stage = await buildStage(stageType, fieldNames, fields);
|
|
99
|
+
if (stage) {
|
|
100
|
+
pipeline.push(stage);
|
|
101
|
+
console.log(chalk.dim(` Added: ${JSON.stringify(stage)}\n`));
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (pipeline.length === 0) {
|
|
105
|
+
cliError("Pipeline is empty — add at least one stage", EXIT_MISUSE);
|
|
106
|
+
}
|
|
107
|
+
// Step 4: Preview
|
|
108
|
+
console.log(chalk.cyan("\n Pipeline:\n"));
|
|
109
|
+
console.log(chalk.dim(" " + JSON.stringify(pipeline, null, 2).split("\n").join("\n ")));
|
|
110
|
+
console.log();
|
|
111
|
+
spinner.start({ text: "Running preview (first 5 results)...", color: "magenta" });
|
|
112
|
+
const previewPipeline = [...pipeline, { $limit: 5 }];
|
|
113
|
+
const previewRes = await apiCallHandler("aggregation", selectedModel, "post", previewPipeline);
|
|
114
|
+
spinner.stop();
|
|
115
|
+
const previewWrapped = wrapAggResult(previewRes);
|
|
116
|
+
handleResponseFormatOptions({ ...opts, responseFormat: "yaml" }, previewWrapped);
|
|
117
|
+
// Step 5: Action choice
|
|
118
|
+
const { action } = await inquirer.prompt([
|
|
119
|
+
{
|
|
120
|
+
type: "list",
|
|
121
|
+
name: "action",
|
|
122
|
+
message: "What would you like to do?",
|
|
123
|
+
choices: [
|
|
124
|
+
{ name: "Execute full pipeline", value: "execute" },
|
|
125
|
+
{ name: "Save as reusable query", value: "save" },
|
|
126
|
+
{ name: "Execute and save", value: "both" },
|
|
127
|
+
{ name: "Print pipeline JSON", value: "print" },
|
|
128
|
+
{ name: "Cancel", value: "cancel" },
|
|
129
|
+
],
|
|
130
|
+
},
|
|
131
|
+
]);
|
|
132
|
+
if (action === "execute" || action === "both") {
|
|
133
|
+
spinner.start({ text: "Executing full pipeline...", color: "magenta" });
|
|
134
|
+
const res = await apiCallHandler("aggregation", selectedModel, "post", pipeline);
|
|
135
|
+
const wrapped = wrapAggResult(res);
|
|
136
|
+
handleResponseFormatOptions(opts, wrapped);
|
|
137
|
+
spinner.success({
|
|
138
|
+
text: `Pipeline returned ${(_c = (_b = wrapped.meta) === null || _b === void 0 ? void 0 : _b.resultCount) !== null && _c !== void 0 ? _c : "?"} results`,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (action === "save" || action === "both") {
|
|
142
|
+
const { queryName } = await inquirer.prompt([
|
|
143
|
+
{
|
|
144
|
+
type: "input",
|
|
145
|
+
name: "queryName",
|
|
146
|
+
message: "Query name:",
|
|
147
|
+
validate: (v) => v.length > 0 || "Name is required",
|
|
148
|
+
},
|
|
149
|
+
]);
|
|
150
|
+
spinner.start({ text: "Saving query...", color: "magenta" });
|
|
151
|
+
const body = {
|
|
152
|
+
name: queryName,
|
|
153
|
+
dataSource: {
|
|
154
|
+
source: "aggregation",
|
|
155
|
+
aggregationModel: selectedModel,
|
|
156
|
+
aggregationPipeline: JSON.stringify(pipeline),
|
|
157
|
+
},
|
|
158
|
+
cache: { enabled: false },
|
|
159
|
+
};
|
|
160
|
+
const saveRes = await apiCallHandler("config", "queries", "post", body, {
|
|
161
|
+
responseFormat: "json",
|
|
162
|
+
});
|
|
163
|
+
const slug = ((_d = saveRes.payload) === null || _d === void 0 ? void 0 : _d.slug) || ((_e = saveRes.payload) === null || _e === void 0 ? void 0 : _e.name) || queryName;
|
|
164
|
+
spinner.success({ text: `Query saved — run with: ay agg exec ${slug}` });
|
|
165
|
+
}
|
|
166
|
+
if (action === "print") {
|
|
167
|
+
console.log(JSON.stringify(pipeline, null, 2));
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
catch (e) {
|
|
171
|
+
cliError(e.message || "Wizard failed", EXIT_GENERAL_ERROR);
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
}
|