@adobe-commerce/aio-toolkit 1.2.5 → 1.2.7
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/CHANGELOG.md +250 -0
- package/README.md +450 -1
- package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
- package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
- package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
- package/dist/index.d.mts +61 -6
- package/dist/index.d.ts +61 -6
- package/dist/index.js +600 -42
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +610 -38
- package/dist/index.mjs.map +1 -1
- package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
- package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
- package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
- package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
- package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
- package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
- package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
- package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
- package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
- package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
- package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
- package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
- package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
- package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
- package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
- package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
- package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
- package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
- package/package.json +4 -2
|
@@ -0,0 +1,2048 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
10
|
+
var __esm = (fn, res) => function __init() {
|
|
11
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
12
|
+
};
|
|
13
|
+
var __commonJS = (cb, mod) => function __require() {
|
|
14
|
+
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
15
|
+
};
|
|
16
|
+
var __export = (target, all) => {
|
|
17
|
+
for (var name in all)
|
|
18
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
19
|
+
};
|
|
20
|
+
var __copyProps = (to, from, except, desc) => {
|
|
21
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
22
|
+
for (let key of __getOwnPropNames(from))
|
|
23
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
24
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
25
|
+
}
|
|
26
|
+
return to;
|
|
27
|
+
};
|
|
28
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
29
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
30
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
31
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
32
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
33
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
34
|
+
mod
|
|
35
|
+
));
|
|
36
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
37
|
+
|
|
38
|
+
// src/commands/framework/command/registry/index.ts
|
|
39
|
+
var _CommandRegistry, CommandRegistry;
|
|
40
|
+
var init_registry = __esm({
|
|
41
|
+
"src/commands/framework/command/registry/index.ts"() {
|
|
42
|
+
"use strict";
|
|
43
|
+
_CommandRegistry = class _CommandRegistry {
|
|
44
|
+
/**
|
|
45
|
+
* Static method to get the commands - must be implemented by subclasses
|
|
46
|
+
*
|
|
47
|
+
* @returns {CommandDescriptor[]} The commands
|
|
48
|
+
*/
|
|
49
|
+
static getCommands() {
|
|
50
|
+
throw new Error("getCommands() must be implemented by subclass");
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Static execute method to execute a command
|
|
54
|
+
*
|
|
55
|
+
* @param {string} type - The name of the command to execute
|
|
56
|
+
* @param {...any} args - The arguments to pass to the command
|
|
57
|
+
* @returns {Promise<CommandResult>} The execution result
|
|
58
|
+
*/
|
|
59
|
+
static async execute(type = "help", ...args2) {
|
|
60
|
+
const command2 = this.getCommands().find((cmd) => cmd.name === type);
|
|
61
|
+
if (!command2) {
|
|
62
|
+
return {
|
|
63
|
+
success: false,
|
|
64
|
+
message: `Unknown command: ${type}`
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
return await command2.execute(...args2);
|
|
68
|
+
}
|
|
69
|
+
};
|
|
70
|
+
__name(_CommandRegistry, "CommandRegistry");
|
|
71
|
+
CommandRegistry = _CommandRegistry;
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// src/commands/framework/command/abstract/index.ts
|
|
76
|
+
var _CommandAbstract, CommandAbstract;
|
|
77
|
+
var init_abstract = __esm({
|
|
78
|
+
"src/commands/framework/command/abstract/index.ts"() {
|
|
79
|
+
"use strict";
|
|
80
|
+
_CommandAbstract = class _CommandAbstract {
|
|
81
|
+
/**
|
|
82
|
+
* Method to get the name of the command
|
|
83
|
+
* @returns {string} The name of the command
|
|
84
|
+
*/
|
|
85
|
+
static getName() {
|
|
86
|
+
throw new Error("getName() must be implemented by subclass");
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Method to get the description of the command
|
|
90
|
+
* @returns {string} The description of the command
|
|
91
|
+
*/
|
|
92
|
+
static getDescription() {
|
|
93
|
+
throw new Error("getDescription() must be implemented by subclass");
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Method to execute the command
|
|
97
|
+
* @param {...any} args - Command arguments
|
|
98
|
+
* @returns {Promise<CommandResult>} The execution result
|
|
99
|
+
*/
|
|
100
|
+
static execute(...args2) {
|
|
101
|
+
throw new Error(`execute() must be implemented by subclass: ${args2.join(", ")}`);
|
|
102
|
+
}
|
|
103
|
+
};
|
|
104
|
+
__name(_CommandAbstract, "CommandAbstract");
|
|
105
|
+
CommandAbstract = _CommandAbstract;
|
|
106
|
+
}
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
// src/commands/framework/command/base-help/index.ts
|
|
110
|
+
var _BaseHelpCommand, BaseHelpCommand;
|
|
111
|
+
var init_base_help = __esm({
|
|
112
|
+
"src/commands/framework/command/base-help/index.ts"() {
|
|
113
|
+
"use strict";
|
|
114
|
+
init_abstract();
|
|
115
|
+
_BaseHelpCommand = class _BaseHelpCommand extends CommandAbstract {
|
|
116
|
+
/**
|
|
117
|
+
* Method to get the description of the command
|
|
118
|
+
* @returns {string} The description of the command
|
|
119
|
+
*/
|
|
120
|
+
static getName() {
|
|
121
|
+
return this.NAME;
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Static method to get the commands - must be implemented by subclasses
|
|
125
|
+
*
|
|
126
|
+
* @returns {CommandDescriptor[]} The commands
|
|
127
|
+
*/
|
|
128
|
+
static getCliName() {
|
|
129
|
+
throw new Error("getCliName() must be implemented by subclass");
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Get the commands dynamically
|
|
133
|
+
*
|
|
134
|
+
* @returns {CommandDescriptor[]} The commands array
|
|
135
|
+
*/
|
|
136
|
+
static getCommands() {
|
|
137
|
+
throw new Error("getCommands() must be implemented by subclass");
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Method to execute the command
|
|
141
|
+
* @param {...any} _args - Command arguments (unused)
|
|
142
|
+
* @returns {Promise<CommandResult>} The execution result
|
|
143
|
+
*/
|
|
144
|
+
static execute(..._args) {
|
|
145
|
+
const helpText = [
|
|
146
|
+
this.getUsageSection(),
|
|
147
|
+
this.getCommandsSection(),
|
|
148
|
+
this.getExamplesSection(),
|
|
149
|
+
this.getFooterSection()
|
|
150
|
+
].join("\n");
|
|
151
|
+
return {
|
|
152
|
+
success: true,
|
|
153
|
+
message: helpText
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Get the usage section
|
|
158
|
+
*
|
|
159
|
+
* @returns {string} The usage section
|
|
160
|
+
*/
|
|
161
|
+
static getUsageSection() {
|
|
162
|
+
return `Usage: npx ${this.getCliName()} <command>`;
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get the commands section
|
|
166
|
+
*
|
|
167
|
+
* @returns {string} The commands section
|
|
168
|
+
*/
|
|
169
|
+
static getCommandsSection() {
|
|
170
|
+
const commands = this.getCommands();
|
|
171
|
+
const maxNameLength = Math.max(...commands.map((cmd) => cmd.name.length));
|
|
172
|
+
const commandsList = commands.map((cmd) => ` ${cmd.name.padEnd(maxNameLength + 2)}${cmd.description}`).join("\n");
|
|
173
|
+
return `
|
|
174
|
+
Commands:
|
|
175
|
+
${commandsList}`;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Get the examples section
|
|
179
|
+
*
|
|
180
|
+
* @returns {string} The examples section
|
|
181
|
+
*/
|
|
182
|
+
static getExamplesSection() {
|
|
183
|
+
const commands = this.getCommands();
|
|
184
|
+
const examples = commands.map((cmd) => ` npx ${this.getCliName()} ${cmd.name}`).join("\n");
|
|
185
|
+
return `
|
|
186
|
+
Examples:
|
|
187
|
+
${examples}`;
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Get the footer section with additional information
|
|
191
|
+
*
|
|
192
|
+
* @returns {string} The footer section
|
|
193
|
+
*/
|
|
194
|
+
static getFooterSection() {
|
|
195
|
+
return `
|
|
196
|
+
For more information, visit:
|
|
197
|
+
${this.repositoryUrl}
|
|
198
|
+
`;
|
|
199
|
+
}
|
|
200
|
+
};
|
|
201
|
+
__name(_BaseHelpCommand, "BaseHelpCommand");
|
|
202
|
+
/**
|
|
203
|
+
* Static command name
|
|
204
|
+
*/
|
|
205
|
+
_BaseHelpCommand.NAME = "help";
|
|
206
|
+
/**
|
|
207
|
+
* Static repository URL
|
|
208
|
+
*/
|
|
209
|
+
_BaseHelpCommand.repositoryUrl = "https://github.com/adobe-commerce/aio-toolkit";
|
|
210
|
+
BaseHelpCommand = _BaseHelpCommand;
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
// package.json
|
|
215
|
+
var require_package = __commonJS({
|
|
216
|
+
"package.json"(exports2, module2) {
|
|
217
|
+
module2.exports = {
|
|
218
|
+
name: "@adobe-commerce/aio-toolkit",
|
|
219
|
+
version: "1.2.7",
|
|
220
|
+
description: "A comprehensive TypeScript toolkit for Adobe App Builder applications providing standardized Adobe Commerce integrations, I/O Events orchestration, file storage utilities, authentication helpers, and robust backend development tools with 100% test coverage.",
|
|
221
|
+
main: "./dist/index.js",
|
|
222
|
+
module: "./dist/index.mjs",
|
|
223
|
+
types: "./dist/index.d.ts",
|
|
224
|
+
exports: {
|
|
225
|
+
".": {
|
|
226
|
+
types: "./dist/index.d.ts",
|
|
227
|
+
import: "./dist/index.mjs",
|
|
228
|
+
require: "./dist/index.js"
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
files: [
|
|
232
|
+
"dist/**/*",
|
|
233
|
+
"files/**/*",
|
|
234
|
+
"onboard.config.default.yaml",
|
|
235
|
+
"README.md",
|
|
236
|
+
"CHANGELOG.md",
|
|
237
|
+
"LICENSE"
|
|
238
|
+
],
|
|
239
|
+
bin: {
|
|
240
|
+
"aio-toolkit-cursor-context": "dist/aio-toolkit-cursor-context/bin/cli.js",
|
|
241
|
+
"aio-toolkit-onboard-events": "dist/aio-toolkit-onboard-events/bin/cli.js",
|
|
242
|
+
"aio-toolkit-cli-workflow": "dist/aio-toolkit-cli-workflow/bin/cli.js"
|
|
243
|
+
},
|
|
244
|
+
scripts: {
|
|
245
|
+
build: "tsup",
|
|
246
|
+
"build:watch": "tsup --watch",
|
|
247
|
+
clean: "rm -rf dist",
|
|
248
|
+
dev: "tsc --watch",
|
|
249
|
+
"type-check": "tsc --noEmit",
|
|
250
|
+
lint: "eslint src test --ext .ts",
|
|
251
|
+
"lint:fix": "eslint src test --ext .ts --fix",
|
|
252
|
+
format: 'prettier --write "src/**/*.ts" "test/**/*.ts"',
|
|
253
|
+
"format:check": 'prettier --check "src/**/*.ts" "test/**/*.ts"',
|
|
254
|
+
test: "jest --passWithNoTests",
|
|
255
|
+
"test:watch": "jest --watch",
|
|
256
|
+
"test:coverage": "jest --coverage",
|
|
257
|
+
"test:ci": "jest --ci --coverage --watchAll=false",
|
|
258
|
+
"test:fast": "jest --passWithNoTests --silent",
|
|
259
|
+
"pre-add": "echo '\u{1F528} Pre-add validation...' && npm run build && echo '\u2705 Ready to add files!'",
|
|
260
|
+
"safe-add": "npm run pre-add && git add",
|
|
261
|
+
"validate:commit": "npm run type-check && npm run lint:fix && npm run format && npm run test:fast",
|
|
262
|
+
"validate:push": "npm run format:check && npm run lint && npm run type-check && npm run test:ci && npm run build",
|
|
263
|
+
"security:audit": "npm audit --audit-level=moderate",
|
|
264
|
+
prepublishOnly: "npm run build",
|
|
265
|
+
prepare: "husky"
|
|
266
|
+
},
|
|
267
|
+
keywords: [
|
|
268
|
+
"adobe",
|
|
269
|
+
"app-builder",
|
|
270
|
+
"toolkit",
|
|
271
|
+
"backend",
|
|
272
|
+
"utilities",
|
|
273
|
+
"typescript",
|
|
274
|
+
"aio"
|
|
275
|
+
],
|
|
276
|
+
author: "Hitarth Pattani <hitarth@example.com>",
|
|
277
|
+
license: "SEE LICENSE IN LICENSE",
|
|
278
|
+
dependencies: {
|
|
279
|
+
"@adobe-commerce/aio-services-kit": "^1.0.0",
|
|
280
|
+
"@aws-sdk/client-sqs": "^3.1045.0",
|
|
281
|
+
amqplib: "^1.0.3",
|
|
282
|
+
cloudevents: "^8.0.2",
|
|
283
|
+
dotenv: "^17.3.1",
|
|
284
|
+
got: "^11.8.6",
|
|
285
|
+
"node-fetch": "^2.7.0",
|
|
286
|
+
"oauth-1.0a": "^2.2.6",
|
|
287
|
+
openwhisk: "^3.21.8",
|
|
288
|
+
uuid: "^10.0.0",
|
|
289
|
+
yaml: "^2.0.0"
|
|
290
|
+
},
|
|
291
|
+
"lint-staged": {
|
|
292
|
+
"*.ts": [
|
|
293
|
+
"eslint --fix",
|
|
294
|
+
"prettier --write"
|
|
295
|
+
]
|
|
296
|
+
},
|
|
297
|
+
devDependencies: {
|
|
298
|
+
"@adobe/aio-lib-db": "^1.0.1",
|
|
299
|
+
"@adobe/aio-lib-ims": "^7.0.2",
|
|
300
|
+
"@adobe/aio-lib-telemetry": "^1.1.3",
|
|
301
|
+
"@adobe/aio-sdk": "^6.0.0",
|
|
302
|
+
"@commitlint/cli": "^19.8.1",
|
|
303
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
304
|
+
"@opentelemetry/resources": "^2.0.0",
|
|
305
|
+
"@types/amqplib": "^0.10.8",
|
|
306
|
+
"@types/graphql": "^14.2.3",
|
|
307
|
+
"@types/jest": "^30.0.0",
|
|
308
|
+
"@types/node": "^20.10.0",
|
|
309
|
+
"@types/node-fetch": "^2.6.13",
|
|
310
|
+
"@types/uuid": "^10.0.0",
|
|
311
|
+
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
|
312
|
+
"@typescript-eslint/parser": "^6.13.0",
|
|
313
|
+
eslint: "^8.55.0",
|
|
314
|
+
"eslint-config-prettier": "^9.1.0",
|
|
315
|
+
"eslint-plugin-prettier": "^5.0.1",
|
|
316
|
+
graphql: "^16.11.0",
|
|
317
|
+
husky: "^9.1.7",
|
|
318
|
+
jest: "^30.1.3",
|
|
319
|
+
"lint-staged": "^16.1.6",
|
|
320
|
+
prettier: "^3.1.0",
|
|
321
|
+
"ts-jest": "^29.4.1",
|
|
322
|
+
tsup: "^8.5.0",
|
|
323
|
+
typescript: "^5.9.2"
|
|
324
|
+
},
|
|
325
|
+
peerDependencies: {
|
|
326
|
+
"@adobe/aio-lib-db": ">=1.0.0",
|
|
327
|
+
"@adobe/aio-lib-ims": ">=7.0.0",
|
|
328
|
+
"@adobe/aio-lib-telemetry": ">=1.0.0",
|
|
329
|
+
"@adobe/aio-sdk": ">=6.0.0",
|
|
330
|
+
"@opentelemetry/resources": ">=2.0.0",
|
|
331
|
+
graphql: ">=14.0.0",
|
|
332
|
+
typescript: ">=4.9.0"
|
|
333
|
+
},
|
|
334
|
+
engines: {
|
|
335
|
+
node: ">=18.0.0"
|
|
336
|
+
},
|
|
337
|
+
publishConfig: {
|
|
338
|
+
access: "public"
|
|
339
|
+
}
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
});
|
|
343
|
+
|
|
344
|
+
// src/commands/cli-workflow/lib/help/index.ts
|
|
345
|
+
var version, _CliWorkflowHelp, CliWorkflowHelp;
|
|
346
|
+
var init_help = __esm({
|
|
347
|
+
"src/commands/cli-workflow/lib/help/index.ts"() {
|
|
348
|
+
"use strict";
|
|
349
|
+
init_base_help();
|
|
350
|
+
({ version } = require_package());
|
|
351
|
+
_CliWorkflowHelp = class _CliWorkflowHelp extends BaseHelpCommand {
|
|
352
|
+
/**
|
|
353
|
+
* Returns the CLI executable name.
|
|
354
|
+
* @returns CLI name string
|
|
355
|
+
*/
|
|
356
|
+
static getCliName() {
|
|
357
|
+
return "aio-toolkit-cli-workflow";
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Returns the help command description.
|
|
361
|
+
* @returns Command description string
|
|
362
|
+
*/
|
|
363
|
+
static getDescription() {
|
|
364
|
+
return this.DESCRIPTION;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Returns registered commands (uses dynamic require to avoid circular dependencies).
|
|
368
|
+
* @returns Array of command descriptors
|
|
369
|
+
*/
|
|
370
|
+
static getCommands() {
|
|
371
|
+
const { CliWorkflowManager: CliWorkflowManager2 } = (init_lib(), __toCommonJS(lib_exports));
|
|
372
|
+
return CliWorkflowManager2.getCommands();
|
|
373
|
+
}
|
|
374
|
+
/**
|
|
375
|
+
* Renders the full help text with version and commands (including inline options).
|
|
376
|
+
*/
|
|
377
|
+
static execute(..._args) {
|
|
378
|
+
const cli = this.getCliName();
|
|
379
|
+
const commands = this.getCommands();
|
|
380
|
+
const maxNameLength = Math.max(...commands.map((cmd) => cmd.name.length));
|
|
381
|
+
const commandsList = commands.map((cmd) => {
|
|
382
|
+
const namePadded = cmd.name.padEnd(maxNameLength + 2);
|
|
383
|
+
let entry = ` ${namePadded}${cmd.description}`;
|
|
384
|
+
if (cmd.options && cmd.options.length > 0) {
|
|
385
|
+
const optionLines = cmd.options.map((opt) => ` ${opt.flag.padEnd(24)}${opt.description}`).join("\n");
|
|
386
|
+
entry += `
|
|
387
|
+
${optionLines}`;
|
|
388
|
+
}
|
|
389
|
+
return entry;
|
|
390
|
+
}).join("\n");
|
|
391
|
+
const helpText = [
|
|
392
|
+
`${cli} v${version}`,
|
|
393
|
+
`
|
|
394
|
+
Usage: npx ${cli} <command> [options]`,
|
|
395
|
+
`
|
|
396
|
+
Commands:
|
|
397
|
+
${commandsList}`,
|
|
398
|
+
`
|
|
399
|
+
For more information, visit:
|
|
400
|
+
https://github.com/adobe-commerce/aio-toolkit
|
|
401
|
+
`
|
|
402
|
+
].join("\n");
|
|
403
|
+
return { success: true, message: helpText };
|
|
404
|
+
}
|
|
405
|
+
};
|
|
406
|
+
__name(_CliWorkflowHelp, "CliWorkflowHelp");
|
|
407
|
+
/** Help command description */
|
|
408
|
+
_CliWorkflowHelp.DESCRIPTION = "Show help for the cli-workflow commands";
|
|
409
|
+
CliWorkflowHelp = _CliWorkflowHelp;
|
|
410
|
+
}
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// src/commands/framework/helpers/aio-cli-detector/index.ts
|
|
414
|
+
var import_child_process, INSTALL_DOCS_URL, AIO_CLI_PACKAGE, _AioCliDetector, AioCliDetector;
|
|
415
|
+
var init_aio_cli_detector = __esm({
|
|
416
|
+
"src/commands/framework/helpers/aio-cli-detector/index.ts"() {
|
|
417
|
+
"use strict";
|
|
418
|
+
import_child_process = require("child_process");
|
|
419
|
+
INSTALL_DOCS_URL = "https://developer.adobe.com/app-builder/docs/guides/runtime_guides/tools/cli-install";
|
|
420
|
+
AIO_CLI_PACKAGE = "@adobe/aio-cli";
|
|
421
|
+
_AioCliDetector = class _AioCliDetector {
|
|
422
|
+
/**
|
|
423
|
+
* Returns the full status of the aio CLI installation.
|
|
424
|
+
*
|
|
425
|
+
* @param commandsToCheck - Optional list of aio sub-commands to probe (e.g. ['app', 'rt'])
|
|
426
|
+
*/
|
|
427
|
+
static getStatus(commandsToCheck = []) {
|
|
428
|
+
const installed = this.isInstalled();
|
|
429
|
+
const version2 = installed ? this.getVersion() : null;
|
|
430
|
+
const commands = {};
|
|
431
|
+
if (installed) {
|
|
432
|
+
for (const cmd of commandsToCheck) {
|
|
433
|
+
commands[cmd] = this.isCommandAvailable(cmd);
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
return { installed, version: version2, commands };
|
|
437
|
+
}
|
|
438
|
+
/**
|
|
439
|
+
* Returns true if the `aio` binary is resolvable on the current PATH.
|
|
440
|
+
*/
|
|
441
|
+
static isInstalled() {
|
|
442
|
+
try {
|
|
443
|
+
const result = (0, import_child_process.spawnSync)("aio", ["--version"], {
|
|
444
|
+
encoding: "utf8",
|
|
445
|
+
shell: false,
|
|
446
|
+
timeout: 5e3
|
|
447
|
+
});
|
|
448
|
+
return result.error?.message?.includes("ENOENT") !== true && result.pid !== 0;
|
|
449
|
+
} catch {
|
|
450
|
+
return false;
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Returns the installed `aio` version string, or null if unavailable.
|
|
455
|
+
*/
|
|
456
|
+
static getVersion() {
|
|
457
|
+
try {
|
|
458
|
+
const result = (0, import_child_process.spawnSync)("aio", ["--version"], {
|
|
459
|
+
encoding: "utf8",
|
|
460
|
+
shell: false,
|
|
461
|
+
timeout: 5e3
|
|
462
|
+
});
|
|
463
|
+
const output = (result.stdout ?? "").trim();
|
|
464
|
+
return output.length > 0 ? output : null;
|
|
465
|
+
} catch {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* Returns true if the given aio sub-command is available (exit code 0 on --help).
|
|
471
|
+
*
|
|
472
|
+
* @param command - Sub-command name, e.g. 'app', 'rt', 'event'
|
|
473
|
+
*/
|
|
474
|
+
static isCommandAvailable(command2) {
|
|
475
|
+
try {
|
|
476
|
+
const result = (0, import_child_process.spawnSync)("aio", [command2, "--help"], {
|
|
477
|
+
encoding: "utf8",
|
|
478
|
+
shell: false,
|
|
479
|
+
timeout: 5e3
|
|
480
|
+
});
|
|
481
|
+
return result.status === 0;
|
|
482
|
+
} catch {
|
|
483
|
+
return false;
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
/**
|
|
487
|
+
* Returns a formatted, human-readable installation guide for the aio CLI.
|
|
488
|
+
*/
|
|
489
|
+
static getInstallMessage() {
|
|
490
|
+
return `\u274C Adobe I/O CLI (aio) is not installed or not found on your PATH.
|
|
491
|
+
|
|
492
|
+
To install it, run:
|
|
493
|
+
|
|
494
|
+
npm install -g ${AIO_CLI_PACKAGE}
|
|
495
|
+
|
|
496
|
+
After installation, verify it is working:
|
|
497
|
+
|
|
498
|
+
aio help
|
|
499
|
+
|
|
500
|
+
For full setup instructions, see:
|
|
501
|
+
${INSTALL_DOCS_URL}`;
|
|
502
|
+
}
|
|
503
|
+
/**
|
|
504
|
+
* Returns a formatted message for one or more missing aio sub-commands.
|
|
505
|
+
*
|
|
506
|
+
* @param missingCommands - Sub-commands that were not found
|
|
507
|
+
*/
|
|
508
|
+
static getMissingCommandsMessage(missingCommands) {
|
|
509
|
+
const list = missingCommands.map((cmd) => ` - aio ${cmd}`).join("\n");
|
|
510
|
+
return `\u26A0\uFE0F The following aio command(s) are required but not available:
|
|
511
|
+
|
|
512
|
+
${list}
|
|
513
|
+
|
|
514
|
+
Make sure the relevant aio plugin(s) are installed. To see all plugins:
|
|
515
|
+
|
|
516
|
+
aio plugins
|
|
517
|
+
|
|
518
|
+
To install a missing plugin:
|
|
519
|
+
|
|
520
|
+
aio plugins:install <plugin-name>
|
|
521
|
+
|
|
522
|
+
For more information, see:
|
|
523
|
+
${INSTALL_DOCS_URL}`;
|
|
524
|
+
}
|
|
525
|
+
};
|
|
526
|
+
__name(_AioCliDetector, "AioCliDetector");
|
|
527
|
+
AioCliDetector = _AioCliDetector;
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
|
|
531
|
+
// src/commands/framework/helpers/parse-cli-flag/index.ts
|
|
532
|
+
var _ParseCliFlag, ParseCliFlag;
|
|
533
|
+
var init_parse_cli_flag = __esm({
|
|
534
|
+
"src/commands/framework/helpers/parse-cli-flag/index.ts"() {
|
|
535
|
+
"use strict";
|
|
536
|
+
_ParseCliFlag = class _ParseCliFlag {
|
|
537
|
+
/**
|
|
538
|
+
* Returns the value of a named flag from a CLI args array, or `null` if absent.
|
|
539
|
+
*
|
|
540
|
+
* Supports both `--flag=<value>` and `--flag <value>` syntaxes.
|
|
541
|
+
* Returns `null` when the flag is absent or has an empty value.
|
|
542
|
+
*
|
|
543
|
+
* @param args - Raw CLI arguments after the command name
|
|
544
|
+
* @param flag - Flag name without leading dashes (e.g. `"env"`, `"config-file"`)
|
|
545
|
+
* @returns The flag value, or `null` if the flag was not provided
|
|
546
|
+
*/
|
|
547
|
+
static parse(args2, flag) {
|
|
548
|
+
const prefix = `--${flag}=`;
|
|
549
|
+
for (let i = 0; i < args2.length; i++) {
|
|
550
|
+
const arg = args2[i];
|
|
551
|
+
if (arg.startsWith(prefix)) {
|
|
552
|
+
return arg.slice(prefix.length) || null;
|
|
553
|
+
}
|
|
554
|
+
if (arg === `--${flag}` && i + 1 < args2.length) {
|
|
555
|
+
return args2[i + 1];
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
return null;
|
|
559
|
+
}
|
|
560
|
+
};
|
|
561
|
+
__name(_ParseCliFlag, "ParseCliFlag");
|
|
562
|
+
ParseCliFlag = _ParseCliFlag;
|
|
563
|
+
}
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
// src/commands/cli-workflow/lib/env-setup/index.ts
|
|
567
|
+
var fs, path, readline, import_child_process2, _CliWorkflowEnvSetup, CliWorkflowEnvSetup;
|
|
568
|
+
var init_env_setup = __esm({
|
|
569
|
+
"src/commands/cli-workflow/lib/env-setup/index.ts"() {
|
|
570
|
+
"use strict";
|
|
571
|
+
fs = __toESM(require("fs"));
|
|
572
|
+
path = __toESM(require("path"));
|
|
573
|
+
readline = __toESM(require("readline"));
|
|
574
|
+
import_child_process2 = require("child_process");
|
|
575
|
+
init_abstract();
|
|
576
|
+
init_aio_cli_detector();
|
|
577
|
+
init_parse_cli_flag();
|
|
578
|
+
_CliWorkflowEnvSetup = class _CliWorkflowEnvSetup extends CommandAbstract {
|
|
579
|
+
/**
|
|
580
|
+
* Returns the command name.
|
|
581
|
+
* @returns Command name string
|
|
582
|
+
*/
|
|
583
|
+
static getName() {
|
|
584
|
+
return this.NAME;
|
|
585
|
+
}
|
|
586
|
+
/**
|
|
587
|
+
* Returns the command description.
|
|
588
|
+
* @returns Command description string
|
|
589
|
+
*/
|
|
590
|
+
static getDescription() {
|
|
591
|
+
return this.DESCRIPTION;
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Returns the options/flags accepted by this command.
|
|
595
|
+
* @returns Array of CommandOption descriptors
|
|
596
|
+
*/
|
|
597
|
+
static getOptions() {
|
|
598
|
+
return [
|
|
599
|
+
{
|
|
600
|
+
flag: "--config-file <path>",
|
|
601
|
+
description: "[optional] Path to workspace config file; skips the interactive prompt"
|
|
602
|
+
}
|
|
603
|
+
];
|
|
604
|
+
}
|
|
605
|
+
/**
|
|
606
|
+
* Creates a readline interface bound to the current process stdio.
|
|
607
|
+
*/
|
|
608
|
+
static createRl() {
|
|
609
|
+
return readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
610
|
+
}
|
|
611
|
+
/**
|
|
612
|
+
* Asks a yes/no question and returns true for "yes", false for "no".
|
|
613
|
+
* Keeps re-prompting until a valid answer is given.
|
|
614
|
+
*
|
|
615
|
+
* @param question - The question text to display
|
|
616
|
+
*/
|
|
617
|
+
static askYesNo(question) {
|
|
618
|
+
return new Promise((resolve2) => {
|
|
619
|
+
const rl = this.createRl();
|
|
620
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
621
|
+
rl.question(`${question} (yes/no): `, (answer) => {
|
|
622
|
+
const normalised = answer.trim().toLowerCase();
|
|
623
|
+
if (normalised === "yes" || normalised === "y") {
|
|
624
|
+
rl.close();
|
|
625
|
+
resolve2(true);
|
|
626
|
+
} else if (normalised === "no" || normalised === "n") {
|
|
627
|
+
rl.close();
|
|
628
|
+
resolve2(false);
|
|
629
|
+
} else {
|
|
630
|
+
console.log(' Please enter "yes" or "no".');
|
|
631
|
+
prompt();
|
|
632
|
+
}
|
|
633
|
+
});
|
|
634
|
+
}, "prompt");
|
|
635
|
+
prompt();
|
|
636
|
+
});
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Asks for a file path, resolves it against the current working directory,
|
|
640
|
+
* and validates that it points to an existing file.
|
|
641
|
+
* Keeps re-prompting on invalid input.
|
|
642
|
+
*
|
|
643
|
+
* @param question - The question text to display
|
|
644
|
+
* @returns Absolute resolved path to the file
|
|
645
|
+
*/
|
|
646
|
+
static askFilePath(question) {
|
|
647
|
+
return new Promise((resolve2) => {
|
|
648
|
+
const rl = this.createRl();
|
|
649
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
650
|
+
rl.question(`${question}: `, (input) => {
|
|
651
|
+
const trimmed = input.trim();
|
|
652
|
+
if (!trimmed) {
|
|
653
|
+
console.log(" Path cannot be empty. Please try again.");
|
|
654
|
+
prompt();
|
|
655
|
+
return;
|
|
656
|
+
}
|
|
657
|
+
const resolved = path.resolve(process.cwd(), trimmed);
|
|
658
|
+
if (!fs.existsSync(resolved)) {
|
|
659
|
+
console.log(` File not found: ${resolved}`);
|
|
660
|
+
console.log(" Please provide a valid path and try again.");
|
|
661
|
+
prompt();
|
|
662
|
+
return;
|
|
663
|
+
}
|
|
664
|
+
if (!fs.statSync(resolved).isFile()) {
|
|
665
|
+
console.log(` Path is not a file: ${resolved}`);
|
|
666
|
+
console.log(" Please provide a path to a file, not a directory.");
|
|
667
|
+
prompt();
|
|
668
|
+
return;
|
|
669
|
+
}
|
|
670
|
+
rl.close();
|
|
671
|
+
resolve2(resolved);
|
|
672
|
+
});
|
|
673
|
+
}, "prompt");
|
|
674
|
+
prompt();
|
|
675
|
+
});
|
|
676
|
+
}
|
|
677
|
+
/**
|
|
678
|
+
* Runs a single `aio` sub-command interactively, inheriting stdio so the
|
|
679
|
+
* user can respond to selection prompts directly in the terminal.
|
|
680
|
+
*
|
|
681
|
+
* @param args - Arguments to pass to the `aio` binary (no user-controlled input)
|
|
682
|
+
* @returns Resolved exit code (0 = success)
|
|
683
|
+
*/
|
|
684
|
+
static runAioInteractive(args2) {
|
|
685
|
+
return new Promise((resolve2, reject) => {
|
|
686
|
+
const child = (0, import_child_process2.spawn)("aio", args2, {
|
|
687
|
+
stdio: "inherit",
|
|
688
|
+
shell: false
|
|
689
|
+
});
|
|
690
|
+
child.on("close", (code) => resolve2(code ?? 1));
|
|
691
|
+
child.on("error", (err) => reject(err));
|
|
692
|
+
});
|
|
693
|
+
}
|
|
694
|
+
/**
|
|
695
|
+
* Executes the env:setup workflow.
|
|
696
|
+
*
|
|
697
|
+
* When `--config-file=<path>` (or `--config-file <path>`) is passed the
|
|
698
|
+
* interactive prompt is skipped and `aio app use <file>` is run directly.
|
|
699
|
+
* Without the flag the user is asked whether they have a config file.
|
|
700
|
+
*
|
|
701
|
+
* @param args - Raw CLI arguments forwarded from bin/cli.ts
|
|
702
|
+
* @returns Promise resolving to a CommandResult with success status and message
|
|
703
|
+
*/
|
|
704
|
+
static async execute(...args2) {
|
|
705
|
+
try {
|
|
706
|
+
console.log("\u{1F680} Setting up AIO Console environment...\n");
|
|
707
|
+
const flagValue = ParseCliFlag.parse(args2, "config-file");
|
|
708
|
+
if (flagValue !== null) {
|
|
709
|
+
const resolved = path.resolve(process.cwd(), flagValue);
|
|
710
|
+
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) {
|
|
711
|
+
return {
|
|
712
|
+
success: false,
|
|
713
|
+
message: `\u274C Config file not found: ${resolved}
|
|
714
|
+
|
|
715
|
+
Please provide a valid path to a workspace config file.
|
|
716
|
+
Usage: --config-file=<path> or --config-file <path>`
|
|
717
|
+
};
|
|
718
|
+
}
|
|
719
|
+
return await this.executeWithConfigFile(resolved);
|
|
720
|
+
}
|
|
721
|
+
const hasConfigFile = await this.askYesNo("Do you have a workspace config file?");
|
|
722
|
+
if (hasConfigFile) {
|
|
723
|
+
return await this.executeWithConfigFile();
|
|
724
|
+
}
|
|
725
|
+
return await this.executeWithInteractiveSelection();
|
|
726
|
+
} catch (error) {
|
|
727
|
+
return {
|
|
728
|
+
success: false,
|
|
729
|
+
message: `\u274C Unexpected error during environment setup.
|
|
730
|
+
Details: ${error.message}
|
|
731
|
+
|
|
732
|
+
Please check the error above and try again.`
|
|
733
|
+
};
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
/**
|
|
737
|
+
* Runs `aio app use <file>` with the workspace config file.
|
|
738
|
+
*
|
|
739
|
+
* @param preResolvedPath - Absolute path from `--config-file` flag; when
|
|
740
|
+
* omitted the user is prompted interactively.
|
|
741
|
+
*/
|
|
742
|
+
static async executeWithConfigFile(preResolvedPath) {
|
|
743
|
+
const workspaceConfigPath = preResolvedPath ?? await this.askFilePath("Enter the path to your workspace config file");
|
|
744
|
+
if (!preResolvedPath) {
|
|
745
|
+
console.log(`
|
|
746
|
+
\u2705 Workspace config file found: ${workspaceConfigPath}
|
|
747
|
+
`);
|
|
748
|
+
}
|
|
749
|
+
console.log("\u25B6 Applying workspace config");
|
|
750
|
+
console.log(` Running: aio app use ${workspaceConfigPath}
|
|
751
|
+
`);
|
|
752
|
+
const exitCode = await this.runAioInteractive(["app", "use", workspaceConfigPath]);
|
|
753
|
+
if (exitCode !== 0) {
|
|
754
|
+
return {
|
|
755
|
+
success: false,
|
|
756
|
+
message: `\u274C Setup failed: could not apply workspace config file.
|
|
757
|
+
Command: aio app use ${workspaceConfigPath}
|
|
758
|
+
Exit code: ${exitCode}
|
|
759
|
+
|
|
760
|
+
Please check the file is a valid workspace config and try again.`
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
return {
|
|
764
|
+
success: true,
|
|
765
|
+
message: `\u2705 Environment setup complete!
|
|
766
|
+
|
|
767
|
+
Your AIO Console context has been configured via workspace config file:
|
|
768
|
+
- Config file: ${workspaceConfigPath}
|
|
769
|
+
|
|
770
|
+
You can verify the active context by running:
|
|
771
|
+
aio console where`
|
|
772
|
+
};
|
|
773
|
+
}
|
|
774
|
+
/**
|
|
775
|
+
* Runs `aio console org select`, `aio console project select`, and
|
|
776
|
+
* `aio console workspace select` interactively in sequence.
|
|
777
|
+
*/
|
|
778
|
+
static async executeWithInteractiveSelection() {
|
|
779
|
+
if (!AioCliDetector.isCommandAvailable("console")) {
|
|
780
|
+
return {
|
|
781
|
+
success: false,
|
|
782
|
+
message: AioCliDetector.getMissingCommandsMessage(["console"])
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
console.log(" No config file provided \u2014 continuing with interactive selection.\n");
|
|
786
|
+
for (const step of this.SETUP_STEPS) {
|
|
787
|
+
console.log(`\u25B6 ${step.label}`);
|
|
788
|
+
console.log(` Running: aio ${step.args.join(" ")}
|
|
789
|
+
`);
|
|
790
|
+
const exitCode = await this.runAioInteractive(step.args);
|
|
791
|
+
if (exitCode !== 0) {
|
|
792
|
+
return {
|
|
793
|
+
success: false,
|
|
794
|
+
message: `\u274C Setup failed at step: ${step.label}
|
|
795
|
+
Command: aio ${step.args.join(" ")}
|
|
796
|
+
Exit code: ${exitCode}
|
|
797
|
+
|
|
798
|
+
Please resolve the issue above and run the command again.`
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
console.log(`
|
|
802
|
+
\u2705 ${step.label} complete
|
|
803
|
+
`);
|
|
804
|
+
}
|
|
805
|
+
return {
|
|
806
|
+
success: true,
|
|
807
|
+
message: "\u2705 Environment setup complete!\n\nYour AIO Console context has been configured:\n - Organization selected\n - Project selected\n - Workspace selected\n\nYou can verify the active context by running:\n aio console where"
|
|
808
|
+
};
|
|
809
|
+
}
|
|
810
|
+
};
|
|
811
|
+
__name(_CliWorkflowEnvSetup, "CliWorkflowEnvSetup");
|
|
812
|
+
/** Command name identifier */
|
|
813
|
+
_CliWorkflowEnvSetup.NAME = "env:setup";
|
|
814
|
+
/** Command description shown in help text */
|
|
815
|
+
_CliWorkflowEnvSetup.DESCRIPTION = "Select AIO Console org, project, and workspace [--config-file=<path>]";
|
|
816
|
+
/** Ordered list of aio console selection steps */
|
|
817
|
+
_CliWorkflowEnvSetup.SETUP_STEPS = [
|
|
818
|
+
{ label: "Select Organization", args: ["console", "org", "select"] },
|
|
819
|
+
{ label: "Select Project", args: ["console", "project", "select"] },
|
|
820
|
+
{ label: "Select Workspace", args: ["console", "workspace", "select"] }
|
|
821
|
+
];
|
|
822
|
+
CliWorkflowEnvSetup = _CliWorkflowEnvSetup;
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
// src/commands/cli-workflow/lib/env-reset/types.ts
|
|
827
|
+
var VALID_ENVS;
|
|
828
|
+
var init_types = __esm({
|
|
829
|
+
"src/commands/cli-workflow/lib/env-reset/types.ts"() {
|
|
830
|
+
"use strict";
|
|
831
|
+
VALID_ENVS = ["prod", "stage"];
|
|
832
|
+
}
|
|
833
|
+
});
|
|
834
|
+
|
|
835
|
+
// src/commands/cli-workflow/lib/env-reset/index.ts
|
|
836
|
+
var import_child_process3, _CliWorkflowEnvReset, CliWorkflowEnvReset;
|
|
837
|
+
var init_env_reset = __esm({
|
|
838
|
+
"src/commands/cli-workflow/lib/env-reset/index.ts"() {
|
|
839
|
+
"use strict";
|
|
840
|
+
import_child_process3 = require("child_process");
|
|
841
|
+
init_abstract();
|
|
842
|
+
init_aio_cli_detector();
|
|
843
|
+
init_parse_cli_flag();
|
|
844
|
+
init_types();
|
|
845
|
+
_CliWorkflowEnvReset = class _CliWorkflowEnvReset extends CommandAbstract {
|
|
846
|
+
/**
|
|
847
|
+
* Returns the command name.
|
|
848
|
+
* @returns Command name string
|
|
849
|
+
*/
|
|
850
|
+
static getName() {
|
|
851
|
+
return this.NAME;
|
|
852
|
+
}
|
|
853
|
+
/**
|
|
854
|
+
* Returns the command description.
|
|
855
|
+
* @returns Command description string
|
|
856
|
+
*/
|
|
857
|
+
static getDescription() {
|
|
858
|
+
return this.DESCRIPTION;
|
|
859
|
+
}
|
|
860
|
+
/**
|
|
861
|
+
* Returns the options/flags accepted by this command.
|
|
862
|
+
* @returns Array of CommandOption descriptors
|
|
863
|
+
*/
|
|
864
|
+
static getOptions() {
|
|
865
|
+
return [
|
|
866
|
+
{
|
|
867
|
+
flag: "--env <prod|stage>",
|
|
868
|
+
description: `[optional] Target environment to reset (default: ${this.DEFAULT_ENV})`
|
|
869
|
+
}
|
|
870
|
+
];
|
|
871
|
+
}
|
|
872
|
+
/**
|
|
873
|
+
* Runs a single `aio` sub-command with stdio inherited so the user sees
|
|
874
|
+
* all output and can respond to interactive prompts (e.g. `aio auth login`).
|
|
875
|
+
*
|
|
876
|
+
* @param args - Arguments passed to the `aio` binary (no user-controlled input)
|
|
877
|
+
* @returns Resolved exit code (0 = success)
|
|
878
|
+
*/
|
|
879
|
+
static runAioInteractive(args2) {
|
|
880
|
+
return new Promise((resolve2, reject) => {
|
|
881
|
+
const child = (0, import_child_process3.spawn)("aio", args2, { stdio: "inherit", shell: false });
|
|
882
|
+
child.on("close", (code) => resolve2(code ?? 1));
|
|
883
|
+
child.on("error", (err) => reject(err));
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
/**
|
|
887
|
+
* Returns the ordered reset steps shared by both environments.
|
|
888
|
+
* The `env` parameter is forwarded to the `Set CLI environment` step.
|
|
889
|
+
*/
|
|
890
|
+
static getResetSteps() {
|
|
891
|
+
return [
|
|
892
|
+
{
|
|
893
|
+
label: "Log out of current session",
|
|
894
|
+
run: /* @__PURE__ */ __name(() => this.runAioInteractive(["auth", "logout"]), "run")
|
|
895
|
+
},
|
|
896
|
+
{
|
|
897
|
+
label: "Clear local CLI config",
|
|
898
|
+
run: /* @__PURE__ */ __name(() => this.runAioInteractive(["config", "clear", "-f"]), "run")
|
|
899
|
+
},
|
|
900
|
+
{
|
|
901
|
+
label: "Clear global CLI config",
|
|
902
|
+
run: /* @__PURE__ */ __name(() => this.runAioInteractive(["config", "clear", "-g", "-f"]), "run")
|
|
903
|
+
},
|
|
904
|
+
{
|
|
905
|
+
label: "Disable telemetry",
|
|
906
|
+
run: /* @__PURE__ */ __name(() => this.runAioInteractive(["telemetry", "off", "--no-telemetry"]), "run")
|
|
907
|
+
},
|
|
908
|
+
{
|
|
909
|
+
label: "Set CLI environment",
|
|
910
|
+
run: /* @__PURE__ */ __name((env) => this.runAioInteractive(["config", "set", "cli.env", env]), "run")
|
|
911
|
+
},
|
|
912
|
+
{
|
|
913
|
+
label: "Export AIO_CLI_ENV for current process",
|
|
914
|
+
run: /* @__PURE__ */ __name((env) => {
|
|
915
|
+
process.env.AIO_CLI_ENV = env;
|
|
916
|
+
return Promise.resolve(0);
|
|
917
|
+
}, "run")
|
|
918
|
+
},
|
|
919
|
+
{
|
|
920
|
+
label: "Log in to new session",
|
|
921
|
+
run: /* @__PURE__ */ __name(() => this.runAioInteractive(["auth", "login"]), "run")
|
|
922
|
+
},
|
|
923
|
+
{
|
|
924
|
+
label: "Enable telemetry",
|
|
925
|
+
run: /* @__PURE__ */ __name(() => this.runAioInteractive(["telemetry", "on"]), "run")
|
|
926
|
+
}
|
|
927
|
+
];
|
|
928
|
+
}
|
|
929
|
+
/**
|
|
930
|
+
* Executes the env:reset workflow.
|
|
931
|
+
*
|
|
932
|
+
* @param args - Raw CLI arguments forwarded from bin/cli.ts
|
|
933
|
+
* @returns Promise resolving to a CommandResult with success status and message
|
|
934
|
+
*/
|
|
935
|
+
static async execute(...args2) {
|
|
936
|
+
try {
|
|
937
|
+
const rawEnv = ParseCliFlag.parse(args2, "env") ?? this.DEFAULT_ENV;
|
|
938
|
+
if (!VALID_ENVS.includes(rawEnv)) {
|
|
939
|
+
return {
|
|
940
|
+
success: false,
|
|
941
|
+
message: `\u274C Invalid value for --env: "${rawEnv}"
|
|
942
|
+
|
|
943
|
+
Accepted values: ${VALID_ENVS.join(", ")}
|
|
944
|
+
Usage: npx aio-toolkit-cli-workflow env:reset --env <prod|stage>`
|
|
945
|
+
};
|
|
946
|
+
}
|
|
947
|
+
const env = rawEnv;
|
|
948
|
+
if (!AioCliDetector.isInstalled()) {
|
|
949
|
+
return {
|
|
950
|
+
success: false,
|
|
951
|
+
message: AioCliDetector.getInstallMessage()
|
|
952
|
+
};
|
|
953
|
+
}
|
|
954
|
+
console.log(`\u{1F504} Resetting AIO CLI environment to: ${env}
|
|
955
|
+
`);
|
|
956
|
+
for (const step of this.getResetSteps()) {
|
|
957
|
+
console.log(`\u25B6 ${step.label}`);
|
|
958
|
+
const exitCode = await step.run(env);
|
|
959
|
+
if (exitCode !== 0) {
|
|
960
|
+
return {
|
|
961
|
+
success: false,
|
|
962
|
+
message: `\u274C Reset failed at step: ${step.label}
|
|
963
|
+
Exit code: ${exitCode}
|
|
964
|
+
|
|
965
|
+
Please resolve the issue above and run the command again.`
|
|
966
|
+
};
|
|
967
|
+
}
|
|
968
|
+
console.log(`\u2705 ${step.label} complete
|
|
969
|
+
`);
|
|
970
|
+
}
|
|
971
|
+
return {
|
|
972
|
+
success: true,
|
|
973
|
+
message: `\u2705 Environment reset complete!
|
|
974
|
+
|
|
975
|
+
AIO CLI has been reset to: ${env}
|
|
976
|
+
|
|
977
|
+
Completed steps:
|
|
978
|
+
- Logged out of previous session
|
|
979
|
+
- Cleared local and global CLI config
|
|
980
|
+
- Telemetry disabled then re-enabled
|
|
981
|
+
- CLI environment set to: ${env}
|
|
982
|
+
- Logged in to new session
|
|
983
|
+
|
|
984
|
+
You can verify the active environment by running:
|
|
985
|
+
aio config get cli.env
|
|
986
|
+
aio console where`
|
|
987
|
+
};
|
|
988
|
+
} catch (error) {
|
|
989
|
+
return {
|
|
990
|
+
success: false,
|
|
991
|
+
message: `\u274C Unexpected error during environment reset.
|
|
992
|
+
Details: ${error.message}
|
|
993
|
+
|
|
994
|
+
Please check the error above and try again.`
|
|
995
|
+
};
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
};
|
|
999
|
+
__name(_CliWorkflowEnvReset, "CliWorkflowEnvReset");
|
|
1000
|
+
/** Command name identifier */
|
|
1001
|
+
_CliWorkflowEnvReset.NAME = "env:reset";
|
|
1002
|
+
/** Command description shown in help text */
|
|
1003
|
+
_CliWorkflowEnvReset.DESCRIPTION = "Reset AIO CLI environment (logout, clear config, re-login)";
|
|
1004
|
+
/** Default target environment when --env is not provided */
|
|
1005
|
+
_CliWorkflowEnvReset.DEFAULT_ENV = "prod";
|
|
1006
|
+
CliWorkflowEnvReset = _CliWorkflowEnvReset;
|
|
1007
|
+
}
|
|
1008
|
+
});
|
|
1009
|
+
|
|
1010
|
+
// src/commands/cli-workflow/lib/cron-delete/index.ts
|
|
1011
|
+
var readline2, import_child_process4, _CliWorkflowCronDelete, CliWorkflowCronDelete;
|
|
1012
|
+
var init_cron_delete = __esm({
|
|
1013
|
+
"src/commands/cli-workflow/lib/cron-delete/index.ts"() {
|
|
1014
|
+
"use strict";
|
|
1015
|
+
readline2 = __toESM(require("readline"));
|
|
1016
|
+
import_child_process4 = require("child_process");
|
|
1017
|
+
init_abstract();
|
|
1018
|
+
init_aio_cli_detector();
|
|
1019
|
+
_CliWorkflowCronDelete = class _CliWorkflowCronDelete extends CommandAbstract {
|
|
1020
|
+
static getName() {
|
|
1021
|
+
return this.NAME;
|
|
1022
|
+
}
|
|
1023
|
+
static getDescription() {
|
|
1024
|
+
return this.DESCRIPTION;
|
|
1025
|
+
}
|
|
1026
|
+
// ── Private helpers ──────────────────────────────────────────────────────
|
|
1027
|
+
/**
|
|
1028
|
+
* Creates a readline interface bound to the current process stdio.
|
|
1029
|
+
*/
|
|
1030
|
+
static createRl() {
|
|
1031
|
+
return readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Asks a yes/no question and returns true for "yes", false for "no".
|
|
1035
|
+
* Keeps re-prompting until a valid answer is given.
|
|
1036
|
+
*
|
|
1037
|
+
* @param question - The question text to display
|
|
1038
|
+
*/
|
|
1039
|
+
static askYesNo(question) {
|
|
1040
|
+
return new Promise((resolve2) => {
|
|
1041
|
+
const rl = this.createRl();
|
|
1042
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
1043
|
+
rl.question(`${question} (yes/no): `, (answer) => {
|
|
1044
|
+
const normalised = answer.trim().toLowerCase();
|
|
1045
|
+
if (normalised === "yes" || normalised === "y") {
|
|
1046
|
+
rl.close();
|
|
1047
|
+
resolve2(true);
|
|
1048
|
+
} else if (normalised === "no" || normalised === "n") {
|
|
1049
|
+
rl.close();
|
|
1050
|
+
resolve2(false);
|
|
1051
|
+
} else {
|
|
1052
|
+
console.log(' Please enter "yes" or "no".');
|
|
1053
|
+
prompt();
|
|
1054
|
+
}
|
|
1055
|
+
});
|
|
1056
|
+
}, "prompt");
|
|
1057
|
+
prompt();
|
|
1058
|
+
});
|
|
1059
|
+
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Shows a numbered list of rules (with their associated trigger names) and
|
|
1062
|
+
* prompts the user to enter a comma-separated list of rule numbers.
|
|
1063
|
+
* Re-prompts on invalid input.
|
|
1064
|
+
*
|
|
1065
|
+
* @param rules - Rule references to display
|
|
1066
|
+
* @returns Selected rule references
|
|
1067
|
+
*/
|
|
1068
|
+
static askRuleSelection(rules) {
|
|
1069
|
+
return new Promise((resolve2) => {
|
|
1070
|
+
const rl = this.createRl();
|
|
1071
|
+
console.log("\nAvailable rules:");
|
|
1072
|
+
rules.forEach((rule, i) => {
|
|
1073
|
+
const trigger = rule.triggerName ? ` (trigger: ${rule.triggerName})` : "";
|
|
1074
|
+
console.log(` ${i + 1}. ${rule.name}${trigger}`);
|
|
1075
|
+
});
|
|
1076
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
1077
|
+
rl.question("\nEnter rule numbers to delete (comma-separated, e.g. 1,3): ", (input) => {
|
|
1078
|
+
const trimmed = input.trim();
|
|
1079
|
+
if (!trimmed) {
|
|
1080
|
+
console.log(" Please enter at least one rule number.");
|
|
1081
|
+
prompt();
|
|
1082
|
+
return;
|
|
1083
|
+
}
|
|
1084
|
+
const indices = trimmed.split(",").map((s) => Number(s.trim()) - 1);
|
|
1085
|
+
const invalid = indices.filter((i) => !Number.isInteger(i) || i < 0 || i >= rules.length);
|
|
1086
|
+
if (invalid.length > 0) {
|
|
1087
|
+
console.log(` Invalid selection. Choose numbers between 1 and ${rules.length}.`);
|
|
1088
|
+
prompt();
|
|
1089
|
+
return;
|
|
1090
|
+
}
|
|
1091
|
+
rl.close();
|
|
1092
|
+
resolve2(indices.map((i) => rules[i]));
|
|
1093
|
+
});
|
|
1094
|
+
}, "prompt");
|
|
1095
|
+
prompt();
|
|
1096
|
+
});
|
|
1097
|
+
}
|
|
1098
|
+
/**
|
|
1099
|
+
* Returns the current AIO workspace name (lowercased), or null if it cannot
|
|
1100
|
+
* be determined. Rejects placeholder values such as "<no workspace selected>".
|
|
1101
|
+
*/
|
|
1102
|
+
static getWorkspace() {
|
|
1103
|
+
const result = (0, import_child_process4.spawnSync)("aio", ["where"], {
|
|
1104
|
+
encoding: "utf8",
|
|
1105
|
+
shell: false,
|
|
1106
|
+
timeout: 5e3
|
|
1107
|
+
});
|
|
1108
|
+
const lines = (result.stdout ?? "").split("\n");
|
|
1109
|
+
const wsLine = lines.find((l) => /workspace/i.test(l));
|
|
1110
|
+
if (!wsLine) return null;
|
|
1111
|
+
const name = wsLine.replace(/.*:\s*/, "").trim();
|
|
1112
|
+
if (!name || /^<.*>$/.test(name)) return null;
|
|
1113
|
+
return name.toLowerCase();
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Returns all rules with their associated trigger names from
|
|
1117
|
+
* `aio rt rule list --json`. The list response includes trigger details, so
|
|
1118
|
+
* no additional per-rule fetch is required.
|
|
1119
|
+
* Returns an empty array on empty output or JSON parse errors.
|
|
1120
|
+
*/
|
|
1121
|
+
static getRules() {
|
|
1122
|
+
const result = (0, import_child_process4.spawnSync)("aio", ["rt", "rule", "list", "--json"], {
|
|
1123
|
+
encoding: "utf8",
|
|
1124
|
+
shell: false,
|
|
1125
|
+
timeout: 1e4
|
|
1126
|
+
});
|
|
1127
|
+
const stdout = (result.stdout ?? "").trim();
|
|
1128
|
+
if (!stdout) return [];
|
|
1129
|
+
try {
|
|
1130
|
+
const data = JSON.parse(stdout);
|
|
1131
|
+
return data.map((entry) => ({
|
|
1132
|
+
name: String(entry.name ?? ""),
|
|
1133
|
+
triggerName: entry.trigger?.name ? String(entry.trigger.name) : null
|
|
1134
|
+
})).filter((r) => r.name);
|
|
1135
|
+
} catch {
|
|
1136
|
+
return [];
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
/**
|
|
1140
|
+
* Runs `aio rt trigger delete <triggerName>` interactively, inheriting stdio
|
|
1141
|
+
* so the user sees any prompts from the AIO CLI.
|
|
1142
|
+
*
|
|
1143
|
+
* @param triggerName - Trigger to delete (not from direct user input)
|
|
1144
|
+
* @returns Resolved exit code (0 = success)
|
|
1145
|
+
*/
|
|
1146
|
+
static runDeleteTrigger(triggerName) {
|
|
1147
|
+
return new Promise((resolve2, reject) => {
|
|
1148
|
+
const child = (0, import_child_process4.spawn)("aio", ["rt", "trigger", "delete", triggerName], {
|
|
1149
|
+
stdio: "inherit",
|
|
1150
|
+
shell: false
|
|
1151
|
+
});
|
|
1152
|
+
child.on("close", (code) => resolve2(code ?? 1));
|
|
1153
|
+
child.on("error", (err) => reject(err));
|
|
1154
|
+
});
|
|
1155
|
+
}
|
|
1156
|
+
/**
|
|
1157
|
+
* Runs `aio rt rule delete <ruleName>` interactively, inheriting stdio so
|
|
1158
|
+
* the user sees any prompts from the AIO CLI.
|
|
1159
|
+
*
|
|
1160
|
+
* @param ruleName - Rule to delete (not from direct user input)
|
|
1161
|
+
* @returns Resolved exit code (0 = success)
|
|
1162
|
+
*/
|
|
1163
|
+
static runDeleteRule(ruleName) {
|
|
1164
|
+
return new Promise((resolve2, reject) => {
|
|
1165
|
+
const child = (0, import_child_process4.spawn)("aio", ["rt", "rule", "delete", ruleName], {
|
|
1166
|
+
stdio: "inherit",
|
|
1167
|
+
shell: false
|
|
1168
|
+
});
|
|
1169
|
+
child.on("close", (code) => resolve2(code ?? 1));
|
|
1170
|
+
child.on("error", (err) => reject(err));
|
|
1171
|
+
});
|
|
1172
|
+
}
|
|
1173
|
+
// ── execute ──────────────────────────────────────────────────────────────
|
|
1174
|
+
/**
|
|
1175
|
+
* Executes the cron:delete workflow.
|
|
1176
|
+
*
|
|
1177
|
+
* @returns Promise resolving to a CommandResult with success status and message
|
|
1178
|
+
*/
|
|
1179
|
+
static async execute() {
|
|
1180
|
+
try {
|
|
1181
|
+
if (!AioCliDetector.isInstalled()) {
|
|
1182
|
+
return { success: false, message: AioCliDetector.getInstallMessage() };
|
|
1183
|
+
}
|
|
1184
|
+
const workspace = this.getWorkspace();
|
|
1185
|
+
if (!workspace) {
|
|
1186
|
+
return {
|
|
1187
|
+
success: false,
|
|
1188
|
+
message: "\u274C Could not determine the current AIO workspace.\n\nRun `aio where` to check your current context, or set one up with:\n npx aio-toolkit-cli-workflow env:setup"
|
|
1189
|
+
};
|
|
1190
|
+
}
|
|
1191
|
+
const proceed = await this.askYesNo(`Proceed with workspace "${workspace}"?`);
|
|
1192
|
+
if (!proceed) {
|
|
1193
|
+
return { success: false, message: "\u26A0\uFE0F Aborted \u2014 no rules were deleted." };
|
|
1194
|
+
}
|
|
1195
|
+
const rules = this.getRules();
|
|
1196
|
+
if (rules.length === 0) {
|
|
1197
|
+
return {
|
|
1198
|
+
success: true,
|
|
1199
|
+
message: `\u2139\uFE0F No rules found in workspace "${workspace}".`
|
|
1200
|
+
};
|
|
1201
|
+
}
|
|
1202
|
+
const toDelete = await this.askRuleSelection(rules);
|
|
1203
|
+
console.log(`
|
|
1204
|
+
Deleting ${toDelete.length} rule(s) from workspace "${workspace}"...
|
|
1205
|
+
`);
|
|
1206
|
+
const deleted = [];
|
|
1207
|
+
for (const rule of toDelete) {
|
|
1208
|
+
if (rule.triggerName) {
|
|
1209
|
+
console.log(` \u{1F5D1}\uFE0F Deleting trigger "${rule.triggerName}"...`);
|
|
1210
|
+
const triggerCode = await this.runDeleteTrigger(rule.triggerName);
|
|
1211
|
+
if (triggerCode !== 0) {
|
|
1212
|
+
return {
|
|
1213
|
+
success: false,
|
|
1214
|
+
message: `\u274C Failed to delete trigger "${rule.triggerName}" (exit code ${triggerCode}).`
|
|
1215
|
+
};
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
console.log(` \u{1F5D1}\uFE0F Deleting rule "${rule.name}"...`);
|
|
1219
|
+
const ruleCode = await this.runDeleteRule(rule.name);
|
|
1220
|
+
if (ruleCode !== 0) {
|
|
1221
|
+
return {
|
|
1222
|
+
success: false,
|
|
1223
|
+
message: `\u274C Failed to delete rule "${rule.name}" (exit code ${ruleCode}).`
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
deleted.push(rule.name);
|
|
1227
|
+
}
|
|
1228
|
+
return {
|
|
1229
|
+
success: true,
|
|
1230
|
+
message: `
|
|
1231
|
+
\u2705 ${deleted.length} rule(s) deleted from workspace "${workspace}":
|
|
1232
|
+
${deleted.map((r) => ` \u2022 ${r}`).join("\n")}`
|
|
1233
|
+
};
|
|
1234
|
+
} catch (error) {
|
|
1235
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1236
|
+
return { success: false, message: `\u274C Unexpected error: ${message}` };
|
|
1237
|
+
}
|
|
1238
|
+
}
|
|
1239
|
+
};
|
|
1240
|
+
__name(_CliWorkflowCronDelete, "CliWorkflowCronDelete");
|
|
1241
|
+
_CliWorkflowCronDelete.NAME = "cron:delete";
|
|
1242
|
+
_CliWorkflowCronDelete.DESCRIPTION = "Delete AIO Runtime cron rules (and their triggers) in the current workspace";
|
|
1243
|
+
CliWorkflowCronDelete = _CliWorkflowCronDelete;
|
|
1244
|
+
}
|
|
1245
|
+
});
|
|
1246
|
+
|
|
1247
|
+
// src/commands/cli-workflow/lib/cron-disable/index.ts
|
|
1248
|
+
var readline3, import_child_process5, _CliWorkflowCronDisable, CliWorkflowCronDisable;
|
|
1249
|
+
var init_cron_disable = __esm({
|
|
1250
|
+
"src/commands/cli-workflow/lib/cron-disable/index.ts"() {
|
|
1251
|
+
"use strict";
|
|
1252
|
+
readline3 = __toESM(require("readline"));
|
|
1253
|
+
import_child_process5 = require("child_process");
|
|
1254
|
+
init_abstract();
|
|
1255
|
+
init_aio_cli_detector();
|
|
1256
|
+
_CliWorkflowCronDisable = class _CliWorkflowCronDisable extends CommandAbstract {
|
|
1257
|
+
static getName() {
|
|
1258
|
+
return this.NAME;
|
|
1259
|
+
}
|
|
1260
|
+
static getDescription() {
|
|
1261
|
+
return this.DESCRIPTION;
|
|
1262
|
+
}
|
|
1263
|
+
static getOptions() {
|
|
1264
|
+
return [
|
|
1265
|
+
{
|
|
1266
|
+
flag: "--all",
|
|
1267
|
+
description: "[optional] Disable all cron rules without prompting for selection"
|
|
1268
|
+
}
|
|
1269
|
+
];
|
|
1270
|
+
}
|
|
1271
|
+
/**
|
|
1272
|
+
* Creates a readline interface bound to the current process stdio.
|
|
1273
|
+
*/
|
|
1274
|
+
static createRl() {
|
|
1275
|
+
return readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
1276
|
+
}
|
|
1277
|
+
/**
|
|
1278
|
+
* Asks a yes/no question and returns true for "yes", false for "no".
|
|
1279
|
+
* Keeps re-prompting until a valid answer is given.
|
|
1280
|
+
*
|
|
1281
|
+
* @param question - The question text to display
|
|
1282
|
+
*/
|
|
1283
|
+
static askYesNo(question) {
|
|
1284
|
+
return new Promise((resolve2) => {
|
|
1285
|
+
const rl = this.createRl();
|
|
1286
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
1287
|
+
rl.question(`${question} (yes/no): `, (answer) => {
|
|
1288
|
+
const normalised = answer.trim().toLowerCase();
|
|
1289
|
+
if (normalised === "yes" || normalised === "y") {
|
|
1290
|
+
rl.close();
|
|
1291
|
+
resolve2(true);
|
|
1292
|
+
} else if (normalised === "no" || normalised === "n") {
|
|
1293
|
+
rl.close();
|
|
1294
|
+
resolve2(false);
|
|
1295
|
+
} else {
|
|
1296
|
+
console.log(' Please enter "yes" or "no".');
|
|
1297
|
+
prompt();
|
|
1298
|
+
}
|
|
1299
|
+
});
|
|
1300
|
+
}, "prompt");
|
|
1301
|
+
prompt();
|
|
1302
|
+
});
|
|
1303
|
+
}
|
|
1304
|
+
/**
|
|
1305
|
+
* Shows a numbered list of rules and prompts the user to enter a
|
|
1306
|
+
* comma-separated list of rule numbers. Re-prompts on invalid input.
|
|
1307
|
+
*
|
|
1308
|
+
* @param rules - Rule names to display
|
|
1309
|
+
* @returns Selected rule names
|
|
1310
|
+
*/
|
|
1311
|
+
static askRuleSelection(rules) {
|
|
1312
|
+
return new Promise((resolve2) => {
|
|
1313
|
+
const rl = this.createRl();
|
|
1314
|
+
console.log("\nAvailable rules:");
|
|
1315
|
+
rules.forEach((rule, i) => console.log(` ${i + 1}. ${rule}`));
|
|
1316
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
1317
|
+
rl.question("\nEnter rule numbers to disable (comma-separated, e.g. 1,3): ", (input) => {
|
|
1318
|
+
const trimmed = input.trim();
|
|
1319
|
+
if (!trimmed) {
|
|
1320
|
+
console.log(" Please enter at least one rule number.");
|
|
1321
|
+
prompt();
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
const indices = trimmed.split(",").map((s) => Number(s.trim()) - 1);
|
|
1325
|
+
const invalid = indices.filter((i) => !Number.isInteger(i) || i < 0 || i >= rules.length);
|
|
1326
|
+
if (invalid.length > 0) {
|
|
1327
|
+
console.log(` Invalid selection. Choose numbers between 1 and ${rules.length}.`);
|
|
1328
|
+
prompt();
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
rl.close();
|
|
1332
|
+
resolve2(indices.map((i) => rules[i]));
|
|
1333
|
+
});
|
|
1334
|
+
}, "prompt");
|
|
1335
|
+
prompt();
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
/**
|
|
1339
|
+
* Returns the current AIO workspace name (lowercased), or null if it cannot
|
|
1340
|
+
* be determined. Uses `aio where` with captured stdout — no user input involved.
|
|
1341
|
+
*/
|
|
1342
|
+
static getWorkspace() {
|
|
1343
|
+
const result = (0, import_child_process5.spawnSync)("aio", ["where"], {
|
|
1344
|
+
encoding: "utf8",
|
|
1345
|
+
shell: false,
|
|
1346
|
+
timeout: 5e3
|
|
1347
|
+
});
|
|
1348
|
+
const lines = (result.stdout ?? "").split("\n");
|
|
1349
|
+
const wsLine = lines.find((l) => /workspace/i.test(l));
|
|
1350
|
+
if (!wsLine) return null;
|
|
1351
|
+
const name = wsLine.replace(/.*:\s*/, "").trim();
|
|
1352
|
+
if (!name || /^<.*>$/.test(name)) return null;
|
|
1353
|
+
return name.toLowerCase();
|
|
1354
|
+
}
|
|
1355
|
+
/**
|
|
1356
|
+
* Returns all rule names from `aio rt rule list --json`.
|
|
1357
|
+
* Uses the JSON flag for reliable structured output, avoiding fragile
|
|
1358
|
+
* text-column parsing that varies across CLI versions and environments.
|
|
1359
|
+
* Returns an empty array on empty output or JSON parse errors.
|
|
1360
|
+
*/
|
|
1361
|
+
static getRules() {
|
|
1362
|
+
const result = (0, import_child_process5.spawnSync)("aio", ["rt", "rule", "list", "--json"], {
|
|
1363
|
+
encoding: "utf8",
|
|
1364
|
+
shell: false,
|
|
1365
|
+
timeout: 1e4
|
|
1366
|
+
});
|
|
1367
|
+
const stdout = (result.stdout ?? "").trim();
|
|
1368
|
+
if (!stdout) return [];
|
|
1369
|
+
try {
|
|
1370
|
+
const data = JSON.parse(stdout);
|
|
1371
|
+
return data.map((entry) => String(entry.name ?? "")).filter(Boolean);
|
|
1372
|
+
} catch {
|
|
1373
|
+
return [];
|
|
1374
|
+
}
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Runs `aio rt rule disable <ruleName>` interactively, inheriting stdio so
|
|
1378
|
+
* the user sees the command output.
|
|
1379
|
+
*
|
|
1380
|
+
* @param ruleName - The rule to disable (not from direct user input)
|
|
1381
|
+
* @returns Resolved exit code (0 = success)
|
|
1382
|
+
*/
|
|
1383
|
+
static runDisableRule(ruleName) {
|
|
1384
|
+
return new Promise((resolve2, reject) => {
|
|
1385
|
+
const child = (0, import_child_process5.spawn)("aio", ["rt", "rule", "disable", ruleName], {
|
|
1386
|
+
stdio: "inherit",
|
|
1387
|
+
shell: false
|
|
1388
|
+
});
|
|
1389
|
+
child.on("close", (code) => resolve2(code ?? 1));
|
|
1390
|
+
child.on("error", (err) => reject(err));
|
|
1391
|
+
});
|
|
1392
|
+
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Executes the cron:disable workflow.
|
|
1395
|
+
*
|
|
1396
|
+
* @param args - Raw CLI arguments forwarded from bin/cli.ts
|
|
1397
|
+
* @returns Promise resolving to a CommandResult with success status and message
|
|
1398
|
+
*/
|
|
1399
|
+
static async execute(...args2) {
|
|
1400
|
+
try {
|
|
1401
|
+
if (!AioCliDetector.isInstalled()) {
|
|
1402
|
+
return { success: false, message: AioCliDetector.getInstallMessage() };
|
|
1403
|
+
}
|
|
1404
|
+
const workspace = this.getWorkspace();
|
|
1405
|
+
if (!workspace) {
|
|
1406
|
+
return {
|
|
1407
|
+
success: false,
|
|
1408
|
+
message: "\u274C Could not determine the current AIO workspace.\n\nRun `aio where` to check your current context, or set one up with:\n npx aio-toolkit-cli-workflow env:setup"
|
|
1409
|
+
};
|
|
1410
|
+
}
|
|
1411
|
+
const proceed = await this.askYesNo(`Proceed with workspace "${workspace}"?`);
|
|
1412
|
+
if (!proceed) {
|
|
1413
|
+
return { success: false, message: "\u26A0\uFE0F Aborted \u2014 no rules were disabled." };
|
|
1414
|
+
}
|
|
1415
|
+
const rules = this.getRules();
|
|
1416
|
+
if (rules.length === 0) {
|
|
1417
|
+
return {
|
|
1418
|
+
success: true,
|
|
1419
|
+
message: `\u2139\uFE0F No rules found in workspace "${workspace}".`
|
|
1420
|
+
};
|
|
1421
|
+
}
|
|
1422
|
+
const disableAll = args2.includes("--all");
|
|
1423
|
+
const toDisable = disableAll ? rules : await this.askRuleSelection(rules);
|
|
1424
|
+
console.log(`
|
|
1425
|
+
Disabling ${toDisable.length} rule(s) in workspace "${workspace}"...
|
|
1426
|
+
`);
|
|
1427
|
+
for (const rule of toDisable) {
|
|
1428
|
+
console.log(` \u2192 ${rule}`);
|
|
1429
|
+
const code = await this.runDisableRule(rule);
|
|
1430
|
+
if (code !== 0) {
|
|
1431
|
+
return {
|
|
1432
|
+
success: false,
|
|
1433
|
+
message: `\u274C Failed to disable rule "${rule}" (exit code ${code}).`
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
return {
|
|
1438
|
+
success: true,
|
|
1439
|
+
message: `
|
|
1440
|
+
\u2705 ${toDisable.length} rule(s) disabled in workspace "${workspace}":
|
|
1441
|
+
${toDisable.map((r) => ` \u2022 ${r}`).join("\n")}`
|
|
1442
|
+
};
|
|
1443
|
+
} catch (error) {
|
|
1444
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1445
|
+
return { success: false, message: `\u274C Unexpected error: ${message}` };
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
__name(_CliWorkflowCronDisable, "CliWorkflowCronDisable");
|
|
1450
|
+
_CliWorkflowCronDisable.NAME = "cron:disable";
|
|
1451
|
+
_CliWorkflowCronDisable.DESCRIPTION = "Disable AIO Runtime cron rules in the current workspace";
|
|
1452
|
+
CliWorkflowCronDisable = _CliWorkflowCronDisable;
|
|
1453
|
+
}
|
|
1454
|
+
});
|
|
1455
|
+
|
|
1456
|
+
// src/commands/cli-workflow/lib/cron-enable/index.ts
|
|
1457
|
+
var readline4, import_child_process6, _CliWorkflowCronEnable, CliWorkflowCronEnable;
|
|
1458
|
+
var init_cron_enable = __esm({
|
|
1459
|
+
"src/commands/cli-workflow/lib/cron-enable/index.ts"() {
|
|
1460
|
+
"use strict";
|
|
1461
|
+
readline4 = __toESM(require("readline"));
|
|
1462
|
+
import_child_process6 = require("child_process");
|
|
1463
|
+
init_abstract();
|
|
1464
|
+
init_aio_cli_detector();
|
|
1465
|
+
_CliWorkflowCronEnable = class _CliWorkflowCronEnable extends CommandAbstract {
|
|
1466
|
+
static getName() {
|
|
1467
|
+
return this.NAME;
|
|
1468
|
+
}
|
|
1469
|
+
static getDescription() {
|
|
1470
|
+
return this.DESCRIPTION;
|
|
1471
|
+
}
|
|
1472
|
+
static getOptions() {
|
|
1473
|
+
return [
|
|
1474
|
+
{
|
|
1475
|
+
flag: "--all",
|
|
1476
|
+
description: "[optional] Enable all cron rules without prompting for selection"
|
|
1477
|
+
}
|
|
1478
|
+
];
|
|
1479
|
+
}
|
|
1480
|
+
/**
|
|
1481
|
+
* Creates a readline interface bound to the current process stdio.
|
|
1482
|
+
*/
|
|
1483
|
+
static createRl() {
|
|
1484
|
+
return readline4.createInterface({ input: process.stdin, output: process.stdout });
|
|
1485
|
+
}
|
|
1486
|
+
/**
|
|
1487
|
+
* Asks a yes/no question and returns true for "yes", false for "no".
|
|
1488
|
+
* Keeps re-prompting until a valid answer is given.
|
|
1489
|
+
*
|
|
1490
|
+
* @param question - The question text to display
|
|
1491
|
+
*/
|
|
1492
|
+
static askYesNo(question) {
|
|
1493
|
+
return new Promise((resolve2) => {
|
|
1494
|
+
const rl = this.createRl();
|
|
1495
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
1496
|
+
rl.question(`${question} (yes/no): `, (answer) => {
|
|
1497
|
+
const normalised = answer.trim().toLowerCase();
|
|
1498
|
+
if (normalised === "yes" || normalised === "y") {
|
|
1499
|
+
rl.close();
|
|
1500
|
+
resolve2(true);
|
|
1501
|
+
} else if (normalised === "no" || normalised === "n") {
|
|
1502
|
+
rl.close();
|
|
1503
|
+
resolve2(false);
|
|
1504
|
+
} else {
|
|
1505
|
+
console.log(' Please enter "yes" or "no".');
|
|
1506
|
+
prompt();
|
|
1507
|
+
}
|
|
1508
|
+
});
|
|
1509
|
+
}, "prompt");
|
|
1510
|
+
prompt();
|
|
1511
|
+
});
|
|
1512
|
+
}
|
|
1513
|
+
/**
|
|
1514
|
+
* Shows a numbered list of rules and prompts the user to enter a
|
|
1515
|
+
* comma-separated list of rule numbers. Re-prompts on invalid input.
|
|
1516
|
+
*
|
|
1517
|
+
* @param rules - Rule names to display
|
|
1518
|
+
* @returns Selected rule names
|
|
1519
|
+
*/
|
|
1520
|
+
static askRuleSelection(rules) {
|
|
1521
|
+
return new Promise((resolve2) => {
|
|
1522
|
+
const rl = this.createRl();
|
|
1523
|
+
console.log("\nAvailable rules:");
|
|
1524
|
+
rules.forEach((rule, i) => console.log(` ${i + 1}. ${rule}`));
|
|
1525
|
+
const prompt = /* @__PURE__ */ __name(() => {
|
|
1526
|
+
rl.question("\nEnter rule numbers to enable (comma-separated, e.g. 1,3): ", (input) => {
|
|
1527
|
+
const trimmed = input.trim();
|
|
1528
|
+
if (!trimmed) {
|
|
1529
|
+
console.log(" Please enter at least one rule number.");
|
|
1530
|
+
prompt();
|
|
1531
|
+
return;
|
|
1532
|
+
}
|
|
1533
|
+
const indices = trimmed.split(",").map((s) => Number(s.trim()) - 1);
|
|
1534
|
+
const invalid = indices.filter((i) => !Number.isInteger(i) || i < 0 || i >= rules.length);
|
|
1535
|
+
if (invalid.length > 0) {
|
|
1536
|
+
console.log(` Invalid selection. Choose numbers between 1 and ${rules.length}.`);
|
|
1537
|
+
prompt();
|
|
1538
|
+
return;
|
|
1539
|
+
}
|
|
1540
|
+
rl.close();
|
|
1541
|
+
resolve2(indices.map((i) => rules[i]));
|
|
1542
|
+
});
|
|
1543
|
+
}, "prompt");
|
|
1544
|
+
prompt();
|
|
1545
|
+
});
|
|
1546
|
+
}
|
|
1547
|
+
/**
|
|
1548
|
+
* Returns the current AIO workspace name (lowercased), or null if it cannot
|
|
1549
|
+
* be determined. Uses `aio where` with captured stdout — no user input involved.
|
|
1550
|
+
*/
|
|
1551
|
+
static getWorkspace() {
|
|
1552
|
+
const result = (0, import_child_process6.spawnSync)("aio", ["where"], {
|
|
1553
|
+
encoding: "utf8",
|
|
1554
|
+
shell: false,
|
|
1555
|
+
timeout: 5e3
|
|
1556
|
+
});
|
|
1557
|
+
const lines = (result.stdout ?? "").split("\n");
|
|
1558
|
+
const wsLine = lines.find((l) => /workspace/i.test(l));
|
|
1559
|
+
if (!wsLine) return null;
|
|
1560
|
+
const name = wsLine.replace(/.*:\s*/, "").trim();
|
|
1561
|
+
if (!name || /^<.*>$/.test(name)) return null;
|
|
1562
|
+
return name.toLowerCase();
|
|
1563
|
+
}
|
|
1564
|
+
/**
|
|
1565
|
+
* Returns all rule names from `aio rt rule list --json`.
|
|
1566
|
+
* Uses the JSON flag for reliable structured output, avoiding fragile
|
|
1567
|
+
* text-column parsing that varies across CLI versions and environments.
|
|
1568
|
+
* Returns an empty array on empty output or JSON parse errors.
|
|
1569
|
+
*/
|
|
1570
|
+
static getRules() {
|
|
1571
|
+
const result = (0, import_child_process6.spawnSync)("aio", ["rt", "rule", "list", "--json"], {
|
|
1572
|
+
encoding: "utf8",
|
|
1573
|
+
shell: false,
|
|
1574
|
+
timeout: 1e4
|
|
1575
|
+
});
|
|
1576
|
+
const stdout = (result.stdout ?? "").trim();
|
|
1577
|
+
if (!stdout) return [];
|
|
1578
|
+
try {
|
|
1579
|
+
const data = JSON.parse(stdout);
|
|
1580
|
+
return data.map((entry) => String(entry.name ?? "")).filter(Boolean);
|
|
1581
|
+
} catch {
|
|
1582
|
+
return [];
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
/**
|
|
1586
|
+
* Runs `aio rt rule enable <ruleName>` interactively, inheriting stdio so the
|
|
1587
|
+
* user sees the command output.
|
|
1588
|
+
*
|
|
1589
|
+
* @param ruleName - The rule to enable (no user-controlled input)
|
|
1590
|
+
* @returns Resolved exit code (0 = success)
|
|
1591
|
+
*/
|
|
1592
|
+
static runEnableRule(ruleName) {
|
|
1593
|
+
return new Promise((resolve2, reject) => {
|
|
1594
|
+
const child = (0, import_child_process6.spawn)("aio", ["rt", "rule", "enable", ruleName], {
|
|
1595
|
+
stdio: "inherit",
|
|
1596
|
+
shell: false
|
|
1597
|
+
});
|
|
1598
|
+
child.on("close", (code) => resolve2(code ?? 1));
|
|
1599
|
+
child.on("error", (err) => reject(err));
|
|
1600
|
+
});
|
|
1601
|
+
}
|
|
1602
|
+
/**
|
|
1603
|
+
* Executes the cron:enable workflow.
|
|
1604
|
+
*
|
|
1605
|
+
* @param args - Raw CLI arguments forwarded from bin/cli.ts
|
|
1606
|
+
* @returns Promise resolving to a CommandResult with success status and message
|
|
1607
|
+
*/
|
|
1608
|
+
static async execute(...args2) {
|
|
1609
|
+
try {
|
|
1610
|
+
if (!AioCliDetector.isInstalled()) {
|
|
1611
|
+
return { success: false, message: AioCliDetector.getInstallMessage() };
|
|
1612
|
+
}
|
|
1613
|
+
const workspace = this.getWorkspace();
|
|
1614
|
+
if (!workspace) {
|
|
1615
|
+
return {
|
|
1616
|
+
success: false,
|
|
1617
|
+
message: "\u274C Could not determine the current AIO workspace.\n\nRun `aio where` to check your current context, or set one up with:\n npx aio-toolkit-cli-workflow env:setup"
|
|
1618
|
+
};
|
|
1619
|
+
}
|
|
1620
|
+
const proceed = await this.askYesNo(`Proceed with workspace "${workspace}"?`);
|
|
1621
|
+
if (!proceed) {
|
|
1622
|
+
return { success: false, message: "\u26A0\uFE0F Aborted \u2014 no rules were enabled." };
|
|
1623
|
+
}
|
|
1624
|
+
const rules = this.getRules();
|
|
1625
|
+
if (rules.length === 0) {
|
|
1626
|
+
return {
|
|
1627
|
+
success: true,
|
|
1628
|
+
message: `\u2139\uFE0F No rules found in workspace "${workspace}".`
|
|
1629
|
+
};
|
|
1630
|
+
}
|
|
1631
|
+
const enableAll = args2.includes("--all");
|
|
1632
|
+
const toEnable = enableAll ? rules : await this.askRuleSelection(rules);
|
|
1633
|
+
console.log(`
|
|
1634
|
+
Enabling ${toEnable.length} rule(s) in workspace "${workspace}"...
|
|
1635
|
+
`);
|
|
1636
|
+
for (const rule of toEnable) {
|
|
1637
|
+
console.log(` \u2192 ${rule}`);
|
|
1638
|
+
const code = await this.runEnableRule(rule);
|
|
1639
|
+
if (code !== 0) {
|
|
1640
|
+
return {
|
|
1641
|
+
success: false,
|
|
1642
|
+
message: `\u274C Failed to enable rule "${rule}" (exit code ${code}).`
|
|
1643
|
+
};
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
return {
|
|
1647
|
+
success: true,
|
|
1648
|
+
message: `
|
|
1649
|
+
\u2705 ${toEnable.length} rule(s) enabled in workspace "${workspace}":
|
|
1650
|
+
${toEnable.map((r) => ` \u2022 ${r}`).join("\n")}`
|
|
1651
|
+
};
|
|
1652
|
+
} catch (error) {
|
|
1653
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1654
|
+
return { success: false, message: `\u274C Unexpected error: ${message}` };
|
|
1655
|
+
}
|
|
1656
|
+
}
|
|
1657
|
+
};
|
|
1658
|
+
__name(_CliWorkflowCronEnable, "CliWorkflowCronEnable");
|
|
1659
|
+
_CliWorkflowCronEnable.NAME = "cron:enable";
|
|
1660
|
+
_CliWorkflowCronEnable.DESCRIPTION = "Enable AIO Runtime cron rules in the current workspace";
|
|
1661
|
+
CliWorkflowCronEnable = _CliWorkflowCronEnable;
|
|
1662
|
+
}
|
|
1663
|
+
});
|
|
1664
|
+
|
|
1665
|
+
// src/commands/cli-workflow/lib/cron-status/index.ts
|
|
1666
|
+
var import_child_process7, _CliWorkflowCronStatus, CliWorkflowCronStatus;
|
|
1667
|
+
var init_cron_status = __esm({
|
|
1668
|
+
"src/commands/cli-workflow/lib/cron-status/index.ts"() {
|
|
1669
|
+
"use strict";
|
|
1670
|
+
import_child_process7 = require("child_process");
|
|
1671
|
+
init_abstract();
|
|
1672
|
+
init_aio_cli_detector();
|
|
1673
|
+
init_parse_cli_flag();
|
|
1674
|
+
_CliWorkflowCronStatus = class _CliWorkflowCronStatus extends CommandAbstract {
|
|
1675
|
+
static getName() {
|
|
1676
|
+
return this.NAME;
|
|
1677
|
+
}
|
|
1678
|
+
static getDescription() {
|
|
1679
|
+
return this.DESCRIPTION;
|
|
1680
|
+
}
|
|
1681
|
+
static getOptions() {
|
|
1682
|
+
return [
|
|
1683
|
+
{
|
|
1684
|
+
flag: "--name [RULE_NAME]",
|
|
1685
|
+
description: "Optional rule name. When provided, fetches only that specific rule instead of listing all rules."
|
|
1686
|
+
}
|
|
1687
|
+
];
|
|
1688
|
+
}
|
|
1689
|
+
/**
|
|
1690
|
+
* Extracts and parses JSON from a spawnSync result, handling:
|
|
1691
|
+
* - stdout-only output (normal case)
|
|
1692
|
+
* - stderr fallback (some AIO CLI versions route --json to stderr)
|
|
1693
|
+
* - ANSI escape codes that can corrupt JSON parsing
|
|
1694
|
+
* - oclif `--json` wrapper: `{ "result": <payload>, "warnings": [] }`
|
|
1695
|
+
* - prefix text before the JSON (e.g. progress lines in non-TTY mode)
|
|
1696
|
+
*
|
|
1697
|
+
* Each output stream is tried independently so that non-JSON content on
|
|
1698
|
+
* stdout does not shadow JSON that arrives on stderr.
|
|
1699
|
+
*
|
|
1700
|
+
* Returns the unwrapped payload, or null on failure.
|
|
1701
|
+
*/
|
|
1702
|
+
static parseJsonOutput(result) {
|
|
1703
|
+
const sources = [(result.stdout ?? "").trim(), (result.stderr ?? "").trim()];
|
|
1704
|
+
for (const source of sources) {
|
|
1705
|
+
if (!source) continue;
|
|
1706
|
+
const clean = source.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
|
|
1707
|
+
const full = this.tryParse(clean);
|
|
1708
|
+
if (full !== void 0) return full;
|
|
1709
|
+
const objAt = clean.indexOf("{");
|
|
1710
|
+
const arrAt = clean.indexOf("[");
|
|
1711
|
+
const start = objAt === -1 ? arrAt : arrAt === -1 ? objAt : Math.min(objAt, arrAt);
|
|
1712
|
+
if (start !== -1) {
|
|
1713
|
+
const sliced = this.tryParse(clean.slice(start));
|
|
1714
|
+
if (sliced !== void 0) return sliced;
|
|
1715
|
+
}
|
|
1716
|
+
}
|
|
1717
|
+
return null;
|
|
1718
|
+
}
|
|
1719
|
+
/**
|
|
1720
|
+
* Tries to parse a JSON string and unwrap the oclif envelope if present.
|
|
1721
|
+
* Returns `undefined` (not `null`) on failure so callers can distinguish
|
|
1722
|
+
* "parse failed" from a valid JSON `null`.
|
|
1723
|
+
*/
|
|
1724
|
+
static tryParse(text) {
|
|
1725
|
+
try {
|
|
1726
|
+
const parsed = JSON.parse(text);
|
|
1727
|
+
if (parsed !== null && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
1728
|
+
const obj = parsed;
|
|
1729
|
+
if ("result" in obj) return obj["result"];
|
|
1730
|
+
}
|
|
1731
|
+
return parsed;
|
|
1732
|
+
} catch {
|
|
1733
|
+
return void 0;
|
|
1734
|
+
}
|
|
1735
|
+
}
|
|
1736
|
+
/**
|
|
1737
|
+
* Returns the current AIO workspace name (lowercased), or null if it cannot
|
|
1738
|
+
* be determined. Rejects placeholder values such as "<no workspace selected>".
|
|
1739
|
+
*/
|
|
1740
|
+
static getWorkspace() {
|
|
1741
|
+
const result = (0, import_child_process7.spawnSync)("aio", ["where"], {
|
|
1742
|
+
encoding: "utf8",
|
|
1743
|
+
shell: false,
|
|
1744
|
+
timeout: 5e3
|
|
1745
|
+
});
|
|
1746
|
+
const lines = (result.stdout ?? "").split("\n");
|
|
1747
|
+
const wsLine = lines.find((l) => /workspace/i.test(l));
|
|
1748
|
+
if (!wsLine) return null;
|
|
1749
|
+
const name = wsLine.replace(/.*:\s*/, "").trim();
|
|
1750
|
+
if (!name || /^<.*>$/.test(name)) return null;
|
|
1751
|
+
return name.toLowerCase();
|
|
1752
|
+
}
|
|
1753
|
+
/**
|
|
1754
|
+
* Returns all rules with their full details from `aio rt rule list --json`.
|
|
1755
|
+
* The list response includes the same fields as `aio rt rule get`, so no
|
|
1756
|
+
* individual per-rule fetches are needed.
|
|
1757
|
+
* Returns an empty array on empty output or JSON parse errors.
|
|
1758
|
+
*/
|
|
1759
|
+
static getRuleList() {
|
|
1760
|
+
const result = (0, import_child_process7.spawnSync)("aio", ["rt", "rule", "list", "--json"], {
|
|
1761
|
+
encoding: "utf8",
|
|
1762
|
+
shell: false,
|
|
1763
|
+
timeout: 1e4
|
|
1764
|
+
});
|
|
1765
|
+
const data = this.parseJsonOutput(result);
|
|
1766
|
+
if (!Array.isArray(data)) return [];
|
|
1767
|
+
return data.filter(
|
|
1768
|
+
(entry) => entry !== null && typeof entry === "object" && !Array.isArray(entry)
|
|
1769
|
+
);
|
|
1770
|
+
}
|
|
1771
|
+
/**
|
|
1772
|
+
* Fetches the full rule object for a single rule via
|
|
1773
|
+
* `aio rt rule get <name> --json`. Returns null on any error.
|
|
1774
|
+
*
|
|
1775
|
+
* @param name - Rule name (from the list output — not user input)
|
|
1776
|
+
*/
|
|
1777
|
+
static getRuleDetail(name) {
|
|
1778
|
+
const result = (0, import_child_process7.spawnSync)("aio", ["rt", "rule", "get", name, "--json"], {
|
|
1779
|
+
encoding: "utf8",
|
|
1780
|
+
shell: false,
|
|
1781
|
+
timeout: 1e4
|
|
1782
|
+
});
|
|
1783
|
+
const data = this.parseJsonOutput(result);
|
|
1784
|
+
if (!data || typeof data !== "object" || Array.isArray(data)) return null;
|
|
1785
|
+
return data;
|
|
1786
|
+
}
|
|
1787
|
+
/**
|
|
1788
|
+
* Returns the cron schedule expression for the given trigger by calling
|
|
1789
|
+
* `aio rt trigger get <name> --json` and extracting the `cron` parameter.
|
|
1790
|
+
* Returns `'—'` when the value cannot be resolved.
|
|
1791
|
+
*
|
|
1792
|
+
* @param triggerName - Trigger name (from rule response — not user input)
|
|
1793
|
+
*/
|
|
1794
|
+
static getCronSchedule(triggerName) {
|
|
1795
|
+
const result = (0, import_child_process7.spawnSync)("aio", ["rt", "trigger", "get", triggerName], {
|
|
1796
|
+
encoding: "utf8",
|
|
1797
|
+
shell: false,
|
|
1798
|
+
timeout: 1e4
|
|
1799
|
+
});
|
|
1800
|
+
const data = this.parseJsonOutput(result);
|
|
1801
|
+
if (!data) return "\u2014";
|
|
1802
|
+
const cronParam = data.parameters?.find((p) => p.key === "cron");
|
|
1803
|
+
return cronParam ? String(cronParam.value) : "\u2014";
|
|
1804
|
+
}
|
|
1805
|
+
/**
|
|
1806
|
+
* Formats a list of rule details into a human-readable display block.
|
|
1807
|
+
*
|
|
1808
|
+
* @param workspace - Current workspace name
|
|
1809
|
+
* @param rules - Parsed rule details
|
|
1810
|
+
*/
|
|
1811
|
+
static formatOutput(workspace, rules) {
|
|
1812
|
+
const activeCount = rules.filter((r) => r.status === "active").length;
|
|
1813
|
+
const inactiveCount = rules.length - activeCount;
|
|
1814
|
+
const entries = rules.map((r) => {
|
|
1815
|
+
const icon = r.status === "active" ? "\u2705" : "\u274C";
|
|
1816
|
+
return [
|
|
1817
|
+
` \u2022 ${r.name}`,
|
|
1818
|
+
` Status: ${icon} ${r.status}`,
|
|
1819
|
+
` Published: ${r.published}`,
|
|
1820
|
+
` Schedule: ${r.cronSchedule}`,
|
|
1821
|
+
` Action: ${r.actionName}`,
|
|
1822
|
+
` Trigger: ${r.triggerName}`,
|
|
1823
|
+
` Version: ${r.version}`
|
|
1824
|
+
].join("\n");
|
|
1825
|
+
}).join("\n\n");
|
|
1826
|
+
return `Cron rules in workspace "${workspace}":
|
|
1827
|
+
|
|
1828
|
+
${entries}
|
|
1829
|
+
|
|
1830
|
+
Summary: ${activeCount} active, ${inactiveCount} inactive (${rules.length} total)`;
|
|
1831
|
+
}
|
|
1832
|
+
/**
|
|
1833
|
+
* Executes the cron:status workflow.
|
|
1834
|
+
*
|
|
1835
|
+
* @returns Promise resolving to a CommandResult with success status and message
|
|
1836
|
+
*/
|
|
1837
|
+
static async execute() {
|
|
1838
|
+
try {
|
|
1839
|
+
if (!AioCliDetector.isInstalled()) {
|
|
1840
|
+
return { success: false, message: AioCliDetector.getInstallMessage() };
|
|
1841
|
+
}
|
|
1842
|
+
const workspace = this.getWorkspace();
|
|
1843
|
+
if (!workspace) {
|
|
1844
|
+
return {
|
|
1845
|
+
success: false,
|
|
1846
|
+
message: "\u274C Could not determine the current AIO workspace.\n\nRun `aio where` to check your current context, or set one up with:\n npx aio-toolkit-cli-workflow env:setup"
|
|
1847
|
+
};
|
|
1848
|
+
}
|
|
1849
|
+
const ruleName = ParseCliFlag.parse(process.argv.slice(2), "name");
|
|
1850
|
+
if (ruleName) {
|
|
1851
|
+
return this.executeSingleRule(workspace, ruleName);
|
|
1852
|
+
}
|
|
1853
|
+
return this.executeAllRules(workspace);
|
|
1854
|
+
} catch (error) {
|
|
1855
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
1856
|
+
return { success: false, message: `\u274C Unexpected error: ${message}` };
|
|
1857
|
+
}
|
|
1858
|
+
}
|
|
1859
|
+
/**
|
|
1860
|
+
* Fetches and displays the status of a single named rule.
|
|
1861
|
+
*/
|
|
1862
|
+
static async executeSingleRule(workspace, ruleName) {
|
|
1863
|
+
console.log(`
|
|
1864
|
+
\u{1F50D} Fetching rule "${ruleName}" in workspace "${workspace}"...
|
|
1865
|
+
`);
|
|
1866
|
+
const rule = this.getRuleDetail(ruleName);
|
|
1867
|
+
if (!rule) {
|
|
1868
|
+
return {
|
|
1869
|
+
success: false,
|
|
1870
|
+
message: `\u274C Could not fetch details for rule "${ruleName}". Check the rule name and try again.`
|
|
1871
|
+
};
|
|
1872
|
+
}
|
|
1873
|
+
const name = rule.name ? String(rule.name) : ruleName;
|
|
1874
|
+
const triggerName = rule.trigger?.name ? String(rule.trigger.name) : "\u2014";
|
|
1875
|
+
let cronSchedule = "\u2014";
|
|
1876
|
+
if (triggerName !== "\u2014") {
|
|
1877
|
+
console.log(` \u23F0 Fetching schedule from trigger "${triggerName}"...`);
|
|
1878
|
+
cronSchedule = this.getCronSchedule(triggerName);
|
|
1879
|
+
}
|
|
1880
|
+
const detail = {
|
|
1881
|
+
name,
|
|
1882
|
+
status: rule.status ? String(rule.status) : "unknown",
|
|
1883
|
+
published: rule.publish === true,
|
|
1884
|
+
actionName: rule.action?.name ? String(rule.action.name) : "\u2014",
|
|
1885
|
+
triggerName,
|
|
1886
|
+
cronSchedule,
|
|
1887
|
+
version: rule.version ? String(rule.version) : "\u2014"
|
|
1888
|
+
};
|
|
1889
|
+
return { success: true, message: this.formatOutput(workspace, [detail]) };
|
|
1890
|
+
}
|
|
1891
|
+
/**
|
|
1892
|
+
* Fetches and displays the status of all rules via `aio rt rule list --json`.
|
|
1893
|
+
*/
|
|
1894
|
+
static async executeAllRules(workspace) {
|
|
1895
|
+
console.log(`
|
|
1896
|
+
\u{1F50D} Fetching cron rules for workspace "${workspace}"...
|
|
1897
|
+
`);
|
|
1898
|
+
const ruleList = this.getRuleList();
|
|
1899
|
+
if (ruleList.length === 0) {
|
|
1900
|
+
return {
|
|
1901
|
+
success: true,
|
|
1902
|
+
message: `\u2139\uFE0F No rules found in workspace "${workspace}".`
|
|
1903
|
+
};
|
|
1904
|
+
}
|
|
1905
|
+
console.log(`\u{1F4CB} Found ${ruleList.length} rule(s). Fetching trigger schedules...
|
|
1906
|
+
`);
|
|
1907
|
+
const details = [];
|
|
1908
|
+
for (const rule of ruleList) {
|
|
1909
|
+
const name = rule.name ? String(rule.name) : "";
|
|
1910
|
+
if (!name) continue;
|
|
1911
|
+
const triggerName = rule.trigger?.name ? String(rule.trigger.name) : "\u2014";
|
|
1912
|
+
let cronSchedule = "\u2014";
|
|
1913
|
+
if (triggerName !== "\u2014") {
|
|
1914
|
+
console.log(` \u23F0 ${name} \u2192 fetching schedule from "${triggerName}"...`);
|
|
1915
|
+
cronSchedule = this.getCronSchedule(triggerName);
|
|
1916
|
+
}
|
|
1917
|
+
details.push({
|
|
1918
|
+
name,
|
|
1919
|
+
status: rule.status ? String(rule.status) : "unknown",
|
|
1920
|
+
published: rule.publish === true,
|
|
1921
|
+
actionName: rule.action?.name ? String(rule.action.name) : "\u2014",
|
|
1922
|
+
triggerName,
|
|
1923
|
+
cronSchedule,
|
|
1924
|
+
version: rule.version ? String(rule.version) : "\u2014"
|
|
1925
|
+
});
|
|
1926
|
+
}
|
|
1927
|
+
if (details.length === 0) {
|
|
1928
|
+
return {
|
|
1929
|
+
success: true,
|
|
1930
|
+
message: `\u2139\uFE0F No rules found in workspace "${workspace}".`
|
|
1931
|
+
};
|
|
1932
|
+
}
|
|
1933
|
+
return { success: true, message: this.formatOutput(workspace, details) };
|
|
1934
|
+
}
|
|
1935
|
+
};
|
|
1936
|
+
__name(_CliWorkflowCronStatus, "CliWorkflowCronStatus");
|
|
1937
|
+
_CliWorkflowCronStatus.NAME = "cron:status";
|
|
1938
|
+
_CliWorkflowCronStatus.DESCRIPTION = "Display the detailed status of AIO Runtime cron rules in the current workspace";
|
|
1939
|
+
CliWorkflowCronStatus = _CliWorkflowCronStatus;
|
|
1940
|
+
}
|
|
1941
|
+
});
|
|
1942
|
+
|
|
1943
|
+
// src/commands/cli-workflow/lib/index.ts
|
|
1944
|
+
var lib_exports = {};
|
|
1945
|
+
__export(lib_exports, {
|
|
1946
|
+
CliWorkflowManager: () => CliWorkflowManager
|
|
1947
|
+
});
|
|
1948
|
+
var _CliWorkflowManager, CliWorkflowManager;
|
|
1949
|
+
var init_lib = __esm({
|
|
1950
|
+
"src/commands/cli-workflow/lib/index.ts"() {
|
|
1951
|
+
"use strict";
|
|
1952
|
+
init_registry();
|
|
1953
|
+
init_help();
|
|
1954
|
+
init_env_setup();
|
|
1955
|
+
init_env_reset();
|
|
1956
|
+
init_cron_delete();
|
|
1957
|
+
init_cron_disable();
|
|
1958
|
+
init_cron_enable();
|
|
1959
|
+
init_cron_status();
|
|
1960
|
+
_CliWorkflowManager = class _CliWorkflowManager extends CommandRegistry {
|
|
1961
|
+
/**
|
|
1962
|
+
* Returns registered cli-workflow commands.
|
|
1963
|
+
*
|
|
1964
|
+
* @returns Array of command descriptors with name, description, and execute handler
|
|
1965
|
+
*/
|
|
1966
|
+
static getCommands() {
|
|
1967
|
+
return [
|
|
1968
|
+
{
|
|
1969
|
+
name: CliWorkflowHelp.getName(),
|
|
1970
|
+
description: CliWorkflowHelp.getDescription(),
|
|
1971
|
+
execute: CliWorkflowHelp.execute.bind(CliWorkflowHelp)
|
|
1972
|
+
},
|
|
1973
|
+
{
|
|
1974
|
+
name: CliWorkflowEnvSetup.getName(),
|
|
1975
|
+
description: CliWorkflowEnvSetup.getDescription(),
|
|
1976
|
+
execute: CliWorkflowEnvSetup.execute.bind(CliWorkflowEnvSetup),
|
|
1977
|
+
options: CliWorkflowEnvSetup.getOptions()
|
|
1978
|
+
},
|
|
1979
|
+
{
|
|
1980
|
+
name: CliWorkflowEnvReset.getName(),
|
|
1981
|
+
description: CliWorkflowEnvReset.getDescription(),
|
|
1982
|
+
execute: CliWorkflowEnvReset.execute.bind(CliWorkflowEnvReset),
|
|
1983
|
+
options: CliWorkflowEnvReset.getOptions()
|
|
1984
|
+
},
|
|
1985
|
+
{
|
|
1986
|
+
name: CliWorkflowCronEnable.getName(),
|
|
1987
|
+
description: CliWorkflowCronEnable.getDescription(),
|
|
1988
|
+
execute: CliWorkflowCronEnable.execute.bind(CliWorkflowCronEnable),
|
|
1989
|
+
options: CliWorkflowCronEnable.getOptions()
|
|
1990
|
+
},
|
|
1991
|
+
{
|
|
1992
|
+
name: CliWorkflowCronDelete.getName(),
|
|
1993
|
+
description: CliWorkflowCronDelete.getDescription(),
|
|
1994
|
+
execute: CliWorkflowCronDelete.execute.bind(CliWorkflowCronDelete)
|
|
1995
|
+
},
|
|
1996
|
+
{
|
|
1997
|
+
name: CliWorkflowCronDisable.getName(),
|
|
1998
|
+
description: CliWorkflowCronDisable.getDescription(),
|
|
1999
|
+
execute: CliWorkflowCronDisable.execute.bind(CliWorkflowCronDisable),
|
|
2000
|
+
options: CliWorkflowCronDisable.getOptions()
|
|
2001
|
+
},
|
|
2002
|
+
{
|
|
2003
|
+
name: CliWorkflowCronStatus.getName(),
|
|
2004
|
+
description: CliWorkflowCronStatus.getDescription(),
|
|
2005
|
+
execute: CliWorkflowCronStatus.execute.bind(CliWorkflowCronStatus),
|
|
2006
|
+
options: CliWorkflowCronStatus.getOptions()
|
|
2007
|
+
}
|
|
2008
|
+
];
|
|
2009
|
+
}
|
|
2010
|
+
};
|
|
2011
|
+
__name(_CliWorkflowManager, "CliWorkflowManager");
|
|
2012
|
+
CliWorkflowManager = _CliWorkflowManager;
|
|
2013
|
+
}
|
|
2014
|
+
});
|
|
2015
|
+
|
|
2016
|
+
// src/commands/cli-workflow/bin/cli.ts
|
|
2017
|
+
init_lib();
|
|
2018
|
+
init_aio_cli_detector();
|
|
2019
|
+
var AIO_EXEMPT_COMMANDS = ["help"];
|
|
2020
|
+
var command = process.argv[2] || "help";
|
|
2021
|
+
var args = process.argv.slice(3);
|
|
2022
|
+
function checkAioCli() {
|
|
2023
|
+
if (AIO_EXEMPT_COMMANDS.includes(command)) {
|
|
2024
|
+
return true;
|
|
2025
|
+
}
|
|
2026
|
+
if (!AioCliDetector.isInstalled()) {
|
|
2027
|
+
console.error(AioCliDetector.getInstallMessage());
|
|
2028
|
+
return false;
|
|
2029
|
+
}
|
|
2030
|
+
return true;
|
|
2031
|
+
}
|
|
2032
|
+
__name(checkAioCli, "checkAioCli");
|
|
2033
|
+
async function main() {
|
|
2034
|
+
if (!checkAioCli()) {
|
|
2035
|
+
process.exit(1);
|
|
2036
|
+
}
|
|
2037
|
+
const result = await CliWorkflowManager.execute(command, ...args);
|
|
2038
|
+
console.log(result.message);
|
|
2039
|
+
if (!result.success) {
|
|
2040
|
+
process.exit(1);
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
__name(main, "main");
|
|
2044
|
+
main().catch((error) => {
|
|
2045
|
+
console.error("Error:", error.message);
|
|
2046
|
+
process.exit(1);
|
|
2047
|
+
});
|
|
2048
|
+
//# sourceMappingURL=cli.js.map
|