@tolinax/ayoune-cli 2026.2.3 → 2026.3.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.
@@ -0,0 +1,177 @@
1
+ import { apiCallHandler } from "../api/apiCallHandler.js";
2
+ import { handleResponseFormatOptions } from "../helpers/handleResponseFormatOptions.js";
3
+ import { spinner } from "../../index.js";
4
+ import { EXIT_GENERAL_ERROR } from "../exitCodes.js";
5
+ export function createSyncCommand(program) {
6
+ const sync = program
7
+ .command("sync")
8
+ .description("Synchronize platform data across systems");
9
+ // ay sync repos
10
+ sync
11
+ .command("repos")
12
+ .description("Sync repositories from connected providers")
13
+ .addHelpText("after", `
14
+ Examples:
15
+ ay sync repos Sync all repositories
16
+ ay sync repos --provider bitbucket Sync only Bitbucket repos
17
+ ay sync repos --id <repoId> Sync a specific repository`)
18
+ .option("--provider <provider>", "Filter by provider (bitbucket, github)")
19
+ .option("--id <repoId>", "Sync a specific repository by ID")
20
+ .action(async (options) => {
21
+ try {
22
+ const opts = { ...program.opts(), ...options };
23
+ if (opts.id) {
24
+ spinner.start({ text: `Syncing repository ${opts.id}...`, color: "magenta" });
25
+ const res = await apiCallHandler("devops", `repositories/${opts.id}/sync`, "post", null, { responseFormat: opts.responseFormat });
26
+ handleResponseFormatOptions(opts, res);
27
+ spinner.success({ text: `Repository ${opts.id} sync initiated` });
28
+ spinner.stop();
29
+ }
30
+ else {
31
+ spinner.start({ text: "Syncing repositories...", color: "magenta" });
32
+ const params = {
33
+ responseFormat: opts.responseFormat,
34
+ verbosity: opts.verbosity,
35
+ };
36
+ if (opts.provider)
37
+ params.provider = opts.provider;
38
+ // List repos first, then trigger sync
39
+ const listRes = await apiCallHandler("devops", "repositories", "get", null, {
40
+ ...params,
41
+ limit: 200,
42
+ });
43
+ const repos = Array.isArray(listRes === null || listRes === void 0 ? void 0 : listRes.payload) ? listRes.payload : [];
44
+ let syncCount = 0;
45
+ let errorCount = 0;
46
+ for (const repo of repos) {
47
+ if (opts.provider && repo.provider !== opts.provider)
48
+ continue;
49
+ try {
50
+ await apiCallHandler("devops", `repositories/${repo._id}/sync`, "post", null, { responseFormat: "json" });
51
+ syncCount++;
52
+ spinner.update({ text: `Syncing repositories... ${syncCount}/${repos.length}` });
53
+ }
54
+ catch (_a) {
55
+ errorCount++;
56
+ }
57
+ }
58
+ spinner.success({ text: `Synced ${syncCount}/${repos.length} repositories` });
59
+ spinner.stop();
60
+ if (errorCount > 0) {
61
+ console.error(` ${errorCount} repositories failed to sync`);
62
+ }
63
+ }
64
+ }
65
+ catch (e) {
66
+ spinner.error({ text: e.message || "Repository sync failed" });
67
+ process.exit(EXIT_GENERAL_ERROR);
68
+ }
69
+ });
70
+ // ay sync clusters
71
+ sync
72
+ .command("clusters")
73
+ .description("Sync Kubernetes cluster state")
74
+ .option("--id <clusterId>", "Sync a specific cluster by ID")
75
+ .action(async (options) => {
76
+ try {
77
+ const opts = { ...program.opts(), ...options };
78
+ if (opts.id) {
79
+ spinner.start({ text: `Syncing cluster ${opts.id}...`, color: "magenta" });
80
+ const res = await apiCallHandler("devops", `clusters/${opts.id}/sync`, "post", null, { responseFormat: opts.responseFormat });
81
+ handleResponseFormatOptions(opts, res);
82
+ spinner.success({ text: `Cluster ${opts.id} sync initiated` });
83
+ spinner.stop();
84
+ }
85
+ else {
86
+ spinner.start({ text: "Syncing all clusters...", color: "magenta" });
87
+ const listRes = await apiCallHandler("devops", "clusters", "get", null, {
88
+ limit: 100,
89
+ responseFormat: "json",
90
+ });
91
+ const clusters = Array.isArray(listRes === null || listRes === void 0 ? void 0 : listRes.payload) ? listRes.payload : [];
92
+ let syncCount = 0;
93
+ for (const cluster of clusters) {
94
+ try {
95
+ await apiCallHandler("devops", `clusters/${cluster._id}/sync`, "post", null, { responseFormat: "json" });
96
+ syncCount++;
97
+ }
98
+ catch (_a) {
99
+ // ignore individual failures
100
+ }
101
+ }
102
+ spinner.success({ text: `Synced ${syncCount}/${clusters.length} clusters` });
103
+ spinner.stop();
104
+ }
105
+ }
106
+ catch (e) {
107
+ spinner.error({ text: e.message || "Cluster sync failed" });
108
+ process.exit(EXIT_GENERAL_ERROR);
109
+ }
110
+ });
111
+ // ay sync pipelines
112
+ sync
113
+ .command("pipelines")
114
+ .description("Sync pipeline status from CI/CD providers")
115
+ .option("--provider <provider>", "Filter by provider (bitbucket, github)")
116
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
117
+ .action(async (options) => {
118
+ try {
119
+ const opts = { ...program.opts(), ...options };
120
+ spinner.start({ text: "Syncing pipeline status...", color: "magenta" });
121
+ const params = {
122
+ limit: opts.limit,
123
+ responseFormat: opts.responseFormat,
124
+ verbosity: opts.verbosity,
125
+ };
126
+ if (opts.provider)
127
+ params.provider = opts.provider;
128
+ const res = await apiCallHandler("devops", "pipelines/sync", "post", null, params);
129
+ handleResponseFormatOptions(opts, res);
130
+ spinner.success({ text: "Pipeline sync initiated" });
131
+ spinner.stop();
132
+ }
133
+ catch (e) {
134
+ spinner.error({ text: e.message || "Pipeline sync failed" });
135
+ process.exit(EXIT_GENERAL_ERROR);
136
+ }
137
+ });
138
+ // ay sync status
139
+ sync
140
+ .command("status")
141
+ .description("Show sync status across all systems")
142
+ .action(async (options) => {
143
+ var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
144
+ try {
145
+ const opts = { ...program.opts(), ...options };
146
+ spinner.start({ text: "Fetching sync status...", color: "magenta" });
147
+ // Gather status from multiple endpoints
148
+ const [reposRes, clustersRes, pipelinesRes] = await Promise.allSettled([
149
+ apiCallHandler("devops", "repositories", "get", null, { limit: 1, responseFormat: "json" }),
150
+ apiCallHandler("devops", "clusters", "get", null, { limit: 1, responseFormat: "json" }),
151
+ apiCallHandler("devops", "pipelines", "get", null, { limit: 1, responseFormat: "json" }),
152
+ ]);
153
+ const status = {
154
+ repositories: {
155
+ total: reposRes.status === "fulfilled" ? (_d = (_c = (_b = (_a = reposRes.value) === null || _a === void 0 ? void 0 : _a.meta) === null || _b === void 0 ? void 0 : _b.pageInfo) === null || _c === void 0 ? void 0 : _c.totalEntries) !== null && _d !== void 0 ? _d : 0 : "error",
156
+ },
157
+ clusters: {
158
+ total: clustersRes.status === "fulfilled" ? (_h = (_g = (_f = (_e = clustersRes.value) === null || _e === void 0 ? void 0 : _e.meta) === null || _f === void 0 ? void 0 : _f.pageInfo) === null || _g === void 0 ? void 0 : _g.totalEntries) !== null && _h !== void 0 ? _h : 0 : "error",
159
+ },
160
+ pipelines: {
161
+ total: pipelinesRes.status === "fulfilled" ? (_m = (_l = (_k = (_j = pipelinesRes.value) === null || _j === void 0 ? void 0 : _j.meta) === null || _k === void 0 ? void 0 : _k.pageInfo) === null || _l === void 0 ? void 0 : _l.totalEntries) !== null && _m !== void 0 ? _m : 0 : "error",
162
+ },
163
+ };
164
+ const res = {
165
+ payload: status,
166
+ meta: { pageInfo: { totalEntries: 1, page: 1, totalPages: 1 } },
167
+ };
168
+ handleResponseFormatOptions(opts, res);
169
+ spinner.success({ text: "Sync status retrieved" });
170
+ spinner.stop();
171
+ }
172
+ catch (e) {
173
+ spinner.error({ text: e.message || "Failed to get sync status" });
174
+ process.exit(EXIT_GENERAL_ERROR);
175
+ }
176
+ });
177
+ }
@@ -0,0 +1,238 @@
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 createTemplateCommand(program) {
7
+ const tmpl = program
8
+ .command("templates")
9
+ .alias("tmpl")
10
+ .description("Manage platform templates (email, notification, report, store)");
11
+ // ── EMAIL TEMPLATES ────────────────────────────────────
12
+ const email = tmpl
13
+ .command("email")
14
+ .description("Manage email templates");
15
+ // ay templates email list
16
+ email
17
+ .command("list")
18
+ .alias("ls")
19
+ .description("List email templates")
20
+ .option("--search <query>", "Search by name")
21
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
22
+ .option("-p, --page <number>", "Page number", parseInt, 1)
23
+ .action(async (options) => {
24
+ var _a, _b, _c;
25
+ try {
26
+ const opts = { ...program.opts(), ...options };
27
+ spinner.start({ text: "Fetching email templates...", color: "magenta" });
28
+ const params = {
29
+ page: opts.page,
30
+ limit: opts.limit,
31
+ responseFormat: opts.responseFormat,
32
+ verbosity: opts.verbosity,
33
+ };
34
+ if (opts.search)
35
+ params.q = opts.search;
36
+ const res = await apiCallHandler("marketing", "emailtemplates", "get", null, params);
37
+ handleResponseFormatOptions(opts, res);
38
+ 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;
39
+ spinner.success({ text: `Found ${total} email templates` });
40
+ spinner.stop();
41
+ if (opts.save)
42
+ await saveFile("email-templates", opts, res);
43
+ }
44
+ catch (e) {
45
+ spinner.error({ text: e.message || "Failed to list email templates" });
46
+ process.exit(EXIT_GENERAL_ERROR);
47
+ }
48
+ });
49
+ // ay templates email get <id>
50
+ email
51
+ .command("get <id>")
52
+ .description("Get email template details")
53
+ .action(async (id, options) => {
54
+ try {
55
+ const opts = { ...program.opts(), ...options };
56
+ spinner.start({ text: `Fetching email template ${id}...`, color: "magenta" });
57
+ const res = await apiCallHandler("marketing", `emailtemplates/${id}`, "get", null, {
58
+ responseFormat: opts.responseFormat,
59
+ verbosity: opts.verbosity,
60
+ });
61
+ handleResponseFormatOptions(opts, res);
62
+ spinner.success({ text: `Email template ${id} loaded` });
63
+ spinner.stop();
64
+ }
65
+ catch (e) {
66
+ spinner.error({ text: e.message || "Failed to get email template" });
67
+ process.exit(EXIT_GENERAL_ERROR);
68
+ }
69
+ });
70
+ // ── NOTIFICATION TEMPLATES ─────────────────────────────
71
+ const notify = tmpl
72
+ .command("notification")
73
+ .alias("notify")
74
+ .description("Manage notification templates");
75
+ // ay templates notification list
76
+ notify
77
+ .command("list")
78
+ .alias("ls")
79
+ .description("List notification templates")
80
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
81
+ .option("-p, --page <number>", "Page number", parseInt, 1)
82
+ .action(async (options) => {
83
+ var _a, _b, _c;
84
+ try {
85
+ const opts = { ...program.opts(), ...options };
86
+ spinner.start({ text: "Fetching notification templates...", color: "magenta" });
87
+ const res = await apiCallHandler("config", "notificationtemplates", "get", null, {
88
+ page: opts.page,
89
+ limit: opts.limit,
90
+ responseFormat: opts.responseFormat,
91
+ verbosity: opts.verbosity,
92
+ });
93
+ handleResponseFormatOptions(opts, res);
94
+ 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;
95
+ spinner.success({ text: `Found ${total} notification templates` });
96
+ spinner.stop();
97
+ if (opts.save)
98
+ await saveFile("notification-templates", opts, res);
99
+ }
100
+ catch (e) {
101
+ spinner.error({ text: e.message || "Failed to list notification templates" });
102
+ process.exit(EXIT_GENERAL_ERROR);
103
+ }
104
+ });
105
+ // ay templates notification get <id>
106
+ notify
107
+ .command("get <id>")
108
+ .description("Get notification template details")
109
+ .action(async (id, options) => {
110
+ try {
111
+ const opts = { ...program.opts(), ...options };
112
+ spinner.start({ text: `Fetching notification template ${id}...`, color: "magenta" });
113
+ const res = await apiCallHandler("config", `notificationtemplates/${id}`, "get", null, {
114
+ responseFormat: opts.responseFormat,
115
+ verbosity: opts.verbosity,
116
+ });
117
+ handleResponseFormatOptions(opts, res);
118
+ spinner.success({ text: `Notification template ${id} loaded` });
119
+ spinner.stop();
120
+ }
121
+ catch (e) {
122
+ spinner.error({ text: e.message || "Failed to get notification template" });
123
+ process.exit(EXIT_GENERAL_ERROR);
124
+ }
125
+ });
126
+ // ── REPORT TEMPLATES ───────────────────────────────────
127
+ const report = tmpl
128
+ .command("report")
129
+ .description("Manage report templates");
130
+ // ay templates report list
131
+ report
132
+ .command("list")
133
+ .alias("ls")
134
+ .description("List report templates")
135
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
136
+ .action(async (options) => {
137
+ var _a, _b, _c;
138
+ try {
139
+ const opts = { ...program.opts(), ...options };
140
+ spinner.start({ text: "Fetching report templates...", color: "magenta" });
141
+ const res = await apiCallHandler("reporting", "reporttemplates", "get", null, {
142
+ limit: opts.limit,
143
+ responseFormat: opts.responseFormat,
144
+ verbosity: opts.verbosity,
145
+ });
146
+ handleResponseFormatOptions(opts, res);
147
+ 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;
148
+ spinner.success({ text: `Found ${total} report templates` });
149
+ spinner.stop();
150
+ if (opts.save)
151
+ await saveFile("report-templates", opts, res);
152
+ }
153
+ catch (e) {
154
+ spinner.error({ text: e.message || "Failed to list report templates" });
155
+ process.exit(EXIT_GENERAL_ERROR);
156
+ }
157
+ });
158
+ // ── STORE TEMPLATES ────────────────────────────────────
159
+ const store = tmpl
160
+ .command("store")
161
+ .description("Browse template store / marketplace");
162
+ // ay templates store list
163
+ store
164
+ .command("list")
165
+ .alias("ls")
166
+ .description("List available store templates")
167
+ .option("--category <category>", "Filter by category")
168
+ .option("--search <query>", "Search templates")
169
+ .option("-l, --limit <number>", "Limit results", parseInt, 50)
170
+ .option("-p, --page <number>", "Page number", parseInt, 1)
171
+ .action(async (options) => {
172
+ var _a, _b, _c;
173
+ try {
174
+ const opts = { ...program.opts(), ...options };
175
+ spinner.start({ text: "Fetching store templates...", color: "magenta" });
176
+ const params = {
177
+ page: opts.page,
178
+ limit: opts.limit,
179
+ responseFormat: opts.responseFormat,
180
+ verbosity: opts.verbosity,
181
+ };
182
+ if (opts.category)
183
+ params.category = opts.category;
184
+ if (opts.search)
185
+ params.q = opts.search;
186
+ const res = await apiCallHandler("config", "templategroups", "get", null, params);
187
+ handleResponseFormatOptions(opts, res);
188
+ 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;
189
+ spinner.success({ text: `Found ${total} store templates` });
190
+ spinner.stop();
191
+ if (opts.save)
192
+ await saveFile("store-templates", opts, res);
193
+ }
194
+ catch (e) {
195
+ spinner.error({ text: e.message || "Failed to list store templates" });
196
+ process.exit(EXIT_GENERAL_ERROR);
197
+ }
198
+ });
199
+ // ay templates store get <id>
200
+ store
201
+ .command("get <id>")
202
+ .description("Get store template details")
203
+ .action(async (id, options) => {
204
+ try {
205
+ const opts = { ...program.opts(), ...options };
206
+ spinner.start({ text: `Fetching store template ${id}...`, color: "magenta" });
207
+ const res = await apiCallHandler("config", `templategroups/${id}`, "get", null, {
208
+ responseFormat: opts.responseFormat,
209
+ verbosity: opts.verbosity,
210
+ });
211
+ handleResponseFormatOptions(opts, res);
212
+ spinner.success({ text: `Store template ${id} loaded` });
213
+ spinner.stop();
214
+ }
215
+ catch (e) {
216
+ spinner.error({ text: e.message || "Failed to get store template" });
217
+ process.exit(EXIT_GENERAL_ERROR);
218
+ }
219
+ });
220
+ // ay templates store install <id>
221
+ store
222
+ .command("install <id>")
223
+ .description("Install a template from the store")
224
+ .action(async (id, options) => {
225
+ try {
226
+ const opts = { ...program.opts(), ...options };
227
+ spinner.start({ text: `Installing template ${id}...`, color: "magenta" });
228
+ const res = await apiCallHandler("config", `templategroups/${id}/install`, "post", null, { responseFormat: opts.responseFormat });
229
+ handleResponseFormatOptions(opts, res);
230
+ spinner.success({ text: `Template ${id} installed` });
231
+ spinner.stop();
232
+ }
233
+ catch (e) {
234
+ spinner.error({ text: e.message || "Failed to install template" });
235
+ process.exit(EXIT_GENERAL_ERROR);
236
+ }
237
+ });
238
+ }