@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.
Files changed (31) hide show
  1. package/CHANGELOG.md +250 -0
  2. package/README.md +450 -1
  3. package/dist/aio-toolkit-cli-workflow/bin/cli.js +2048 -0
  4. package/dist/aio-toolkit-cli-workflow/bin/cli.js.map +1 -0
  5. package/dist/aio-toolkit-cursor-context/bin/cli.js +16 -0
  6. package/dist/aio-toolkit-cursor-context/bin/cli.js.map +1 -1
  7. package/dist/index.d.mts +61 -6
  8. package/dist/index.d.ts +61 -6
  9. package/dist/index.js +600 -42
  10. package/dist/index.js.map +1 -1
  11. package/dist/index.mjs +610 -38
  12. package/dist/index.mjs.map +1 -1
  13. package/files/cursor-context/commands/aio-toolkit-analyze-adobe-commerce-module.md +612 -0
  14. package/files/cursor-context/commands/aio-toolkit-create-amazon-sqs-consumer.md +445 -0
  15. package/files/cursor-context/commands/aio-toolkit-create-event-consumer-action.md +6 -0
  16. package/files/cursor-context/commands/aio-toolkit-create-graphql-action.md +21 -7
  17. package/files/cursor-context/commands/aio-toolkit-create-openwhisk-action.md +326 -0
  18. package/files/cursor-context/commands/aio-toolkit-create-runtime-action.md +15 -5
  19. package/files/cursor-context/commands/aio-toolkit-create-shipping-carrier.md +681 -0
  20. package/files/cursor-context/commands/aio-toolkit-create-webhook-action.md +22 -9
  21. package/files/cursor-context/rules/aio-toolkit-create-adobe-commerce-client.mdc +252 -116
  22. package/files/cursor-context/rules/aio-toolkit-oop-best-practices.mdc +10 -4
  23. package/files/cursor-context/rules/aio-toolkit-setup-new-relic-telemetry.mdc +167 -2
  24. package/files/cursor-context/rules/aio-toolkit-use-abdb-collection.mdc +610 -0
  25. package/files/cursor-context/rules/aio-toolkit-use-abdb-repository.mdc +705 -0
  26. package/files/cursor-context/rules/aio-toolkit-use-adobe-auth.mdc +442 -0
  27. package/files/cursor-context/rules/aio-toolkit-use-amazon-sqs-publish.mdc +397 -0
  28. package/files/cursor-context/rules/aio-toolkit-use-file-repository.mdc +502 -0
  29. package/files/cursor-context/rules/aio-toolkit-use-publish-event.mdc +510 -0
  30. package/files/cursor-context/rules/aio-toolkit-use-runtime-api-gateway-service.mdc +542 -0
  31. 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