@expressots/cli 3.0.0 → 4.0.0-preview.2

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 (180) hide show
  1. package/README.md +41 -95
  2. package/bin/cicd/cli.d.ts +6 -0
  3. package/bin/cicd/cli.js +126 -0
  4. package/bin/cicd/form.d.ts +29 -0
  5. package/bin/cicd/form.js +345 -0
  6. package/bin/cicd/generators/azure-devops.d.ts +2 -0
  7. package/bin/cicd/generators/azure-devops.js +370 -0
  8. package/bin/cicd/generators/bitbucket.d.ts +2 -0
  9. package/bin/cicd/generators/bitbucket.js +217 -0
  10. package/bin/cicd/generators/circleci.d.ts +2 -0
  11. package/bin/cicd/generators/circleci.js +274 -0
  12. package/bin/cicd/generators/github-actions.d.ts +14 -0
  13. package/bin/cicd/generators/github-actions.js +426 -0
  14. package/bin/cicd/generators/gitlab-ci.d.ts +2 -0
  15. package/bin/cicd/generators/gitlab-ci.js +237 -0
  16. package/bin/cicd/generators/index.d.ts +6 -0
  17. package/bin/cicd/generators/index.js +15 -0
  18. package/bin/cicd/generators/jenkins.d.ts +2 -0
  19. package/bin/cicd/generators/jenkins.js +248 -0
  20. package/bin/cicd/generators/template-loader.d.ts +17 -0
  21. package/bin/cicd/generators/template-loader.js +128 -0
  22. package/bin/cicd/index.d.ts +1 -0
  23. package/bin/cicd/index.js +5 -0
  24. package/bin/cli.d.ts +1 -1
  25. package/bin/cli.js +18 -3
  26. package/bin/commands/project.commands.d.ts +19 -6
  27. package/bin/commands/project.commands.js +390 -61
  28. package/bin/config/index.d.ts +5 -0
  29. package/bin/config/index.js +10 -0
  30. package/bin/config/manager.d.ts +98 -0
  31. package/bin/config/manager.js +222 -0
  32. package/bin/containerize/analyzers/bootstrap-analyzer.d.ts +46 -0
  33. package/bin/containerize/analyzers/bootstrap-analyzer.js +187 -0
  34. package/bin/containerize/analyzers/project-analyzer.d.ts +20 -0
  35. package/bin/containerize/analyzers/project-analyzer.js +150 -0
  36. package/bin/containerize/cli.d.ts +4 -0
  37. package/bin/containerize/cli.js +113 -0
  38. package/bin/containerize/form.d.ts +15 -0
  39. package/bin/containerize/form.js +154 -0
  40. package/bin/containerize/generators/ci-generator.d.ts +31 -0
  41. package/bin/containerize/generators/ci-generator.js +936 -0
  42. package/bin/containerize/generators/docker-compose-generator.d.ts +8 -0
  43. package/bin/containerize/generators/docker-compose-generator.js +186 -0
  44. package/bin/containerize/generators/dockerfile-generator.d.ts +8 -0
  45. package/bin/containerize/generators/dockerfile-generator.js +635 -0
  46. package/bin/containerize/generators/kubernetes-generator.d.ts +8 -0
  47. package/bin/containerize/generators/kubernetes-generator.js +133 -0
  48. package/bin/containerize/generators/template-loader.d.ts +36 -0
  49. package/bin/containerize/generators/template-loader.js +129 -0
  50. package/bin/containerize/index.d.ts +4 -0
  51. package/bin/containerize/index.js +13 -0
  52. package/bin/containerize/presets/preset-registry.d.ts +20 -0
  53. package/bin/containerize/presets/preset-registry.js +102 -0
  54. package/bin/costs/cli.d.ts +5 -0
  55. package/bin/costs/cli.js +183 -0
  56. package/bin/costs/form.d.ts +44 -0
  57. package/bin/costs/form.js +412 -0
  58. package/bin/costs/index.d.ts +4 -0
  59. package/bin/costs/index.js +25 -0
  60. package/bin/costs/pricing-manager.d.ts +84 -0
  61. package/bin/costs/pricing-manager.js +342 -0
  62. package/bin/costs/providers/index.d.ts +32 -0
  63. package/bin/costs/providers/index.js +153 -0
  64. package/bin/costs/sources/api-source.d.ts +10 -0
  65. package/bin/costs/sources/api-source.js +32 -0
  66. package/bin/costs/sources/index.d.ts +6 -0
  67. package/bin/costs/sources/index.js +15 -0
  68. package/bin/costs/sources/local-json-source.d.ts +23 -0
  69. package/bin/costs/sources/local-json-source.js +59 -0
  70. package/bin/costs/sources/remote-json-source.d.ts +11 -0
  71. package/bin/costs/sources/remote-json-source.js +53 -0
  72. package/bin/costs/types.d.ts +53 -0
  73. package/bin/costs/types.js +5 -0
  74. package/bin/dev/cli.d.ts +4 -0
  75. package/bin/dev/cli.js +134 -0
  76. package/bin/dev/form.d.ts +36 -0
  77. package/bin/dev/form.js +254 -0
  78. package/bin/dev/index.d.ts +1 -0
  79. package/bin/dev/index.js +5 -0
  80. package/bin/generate/cli.js +29 -2
  81. package/bin/generate/form.d.ts +5 -1
  82. package/bin/generate/form.js +3 -3
  83. package/bin/generate/templates/nonopinionated/config.tpl +12 -0
  84. package/bin/generate/templates/nonopinionated/event.tpl +10 -0
  85. package/bin/generate/templates/nonopinionated/guard.tpl +18 -0
  86. package/bin/generate/templates/nonopinionated/handler.tpl +12 -0
  87. package/bin/generate/templates/nonopinionated/interceptor.tpl +27 -0
  88. package/bin/generate/templates/opinionated/config.tpl +47 -0
  89. package/bin/generate/templates/opinionated/entity.tpl +1 -8
  90. package/bin/generate/templates/opinionated/event.tpl +15 -0
  91. package/bin/generate/templates/opinionated/guard.tpl +41 -0
  92. package/bin/generate/templates/opinionated/handler.tpl +23 -0
  93. package/bin/generate/templates/opinionated/interceptor.tpl +50 -0
  94. package/bin/generate/utils/command-utils.d.ts +7 -3
  95. package/bin/generate/utils/command-utils.js +95 -31
  96. package/bin/generate/utils/nonopininated-cmd.d.ts +10 -1
  97. package/bin/generate/utils/nonopininated-cmd.js +100 -1
  98. package/bin/generate/utils/opinionated-cmd.d.ts +10 -1
  99. package/bin/generate/utils/opinionated-cmd.js +112 -7
  100. package/bin/generate/utils/string-utils.d.ts +6 -0
  101. package/bin/generate/utils/string-utils.js +13 -1
  102. package/bin/help/form.js +11 -3
  103. package/bin/migrate/analyzers/platform-detector.d.ts +14 -0
  104. package/bin/migrate/analyzers/platform-detector.js +116 -0
  105. package/bin/migrate/cli.d.ts +6 -0
  106. package/bin/migrate/cli.js +96 -0
  107. package/bin/migrate/form.d.ts +25 -0
  108. package/bin/migrate/form.js +347 -0
  109. package/bin/migrate/generators/compose-to-k8s.d.ts +2 -0
  110. package/bin/migrate/generators/compose-to-k8s.js +324 -0
  111. package/bin/migrate/generators/compose-to-railway.d.ts +2 -0
  112. package/bin/migrate/generators/compose-to-railway.js +138 -0
  113. package/bin/migrate/generators/compose-to-render.d.ts +2 -0
  114. package/bin/migrate/generators/compose-to-render.js +148 -0
  115. package/bin/migrate/generators/generic-migration.d.ts +9 -0
  116. package/bin/migrate/generators/generic-migration.js +221 -0
  117. package/bin/migrate/generators/heroku-to-fly.d.ts +2 -0
  118. package/bin/migrate/generators/heroku-to-fly.js +291 -0
  119. package/bin/migrate/generators/heroku-to-railway.d.ts +2 -0
  120. package/bin/migrate/generators/heroku-to-railway.js +283 -0
  121. package/bin/migrate/generators/heroku-to-render.d.ts +2 -0
  122. package/bin/migrate/generators/heroku-to-render.js +148 -0
  123. package/bin/migrate/generators/index.d.ts +7 -0
  124. package/bin/migrate/generators/index.js +17 -0
  125. package/bin/migrate/generators/template-loader.d.ts +21 -0
  126. package/bin/migrate/generators/template-loader.js +59 -0
  127. package/bin/migrate/index.d.ts +1 -0
  128. package/bin/migrate/index.js +5 -0
  129. package/bin/new/cli.js +21 -6
  130. package/bin/new/form.d.ts +25 -4
  131. package/bin/new/form.js +285 -70
  132. package/bin/profile/analyzers/dockerfile-analyzer.d.ts +27 -0
  133. package/bin/profile/analyzers/dockerfile-analyzer.js +122 -0
  134. package/bin/profile/analyzers/image-analyzer.d.ts +19 -0
  135. package/bin/profile/analyzers/image-analyzer.js +85 -0
  136. package/bin/profile/cli.d.ts +4 -0
  137. package/bin/profile/cli.js +92 -0
  138. package/bin/profile/form.d.ts +56 -0
  139. package/bin/profile/form.js +400 -0
  140. package/bin/profile/index.d.ts +1 -0
  141. package/bin/profile/index.js +5 -0
  142. package/bin/profile/optimizers/index.d.ts +19 -0
  143. package/bin/profile/optimizers/index.js +137 -0
  144. package/bin/providers/add/form.d.ts +1 -1
  145. package/bin/providers/add/form.js +27 -6
  146. package/bin/providers/create/form.js +2 -1
  147. package/bin/scripts/form.js +27 -5
  148. package/bin/studio/cli.d.ts +15 -0
  149. package/bin/studio/cli.js +166 -0
  150. package/bin/studio/index.d.ts +5 -0
  151. package/bin/studio/index.js +9 -0
  152. package/bin/templates/cache.d.ts +54 -0
  153. package/bin/templates/cache.js +180 -0
  154. package/bin/templates/cli.d.ts +8 -0
  155. package/bin/templates/cli.js +292 -0
  156. package/bin/templates/fetcher.d.ts +49 -0
  157. package/bin/templates/fetcher.js +208 -0
  158. package/bin/templates/index.d.ts +11 -0
  159. package/bin/templates/index.js +37 -0
  160. package/bin/templates/manager.d.ts +116 -0
  161. package/bin/templates/manager.js +323 -0
  162. package/bin/templates/renderer.d.ts +49 -0
  163. package/bin/templates/renderer.js +204 -0
  164. package/bin/templates/types.d.ts +51 -0
  165. package/bin/templates/types.js +5 -0
  166. package/bin/utils/add-module-to-container.d.ts +2 -2
  167. package/bin/utils/add-module-to-container.js +15 -5
  168. package/bin/utils/cli-ui.d.ts +30 -3
  169. package/bin/utils/cli-ui.js +95 -13
  170. package/bin/utils/index.d.ts +4 -0
  171. package/bin/utils/index.js +4 -0
  172. package/bin/utils/input-validation.d.ts +50 -0
  173. package/bin/utils/input-validation.js +143 -0
  174. package/bin/utils/package-manager-commands.d.ts +24 -0
  175. package/bin/utils/package-manager-commands.js +50 -0
  176. package/bin/utils/safe-spawn.d.ts +35 -0
  177. package/bin/utils/safe-spawn.js +51 -0
  178. package/bin/utils/update-tsconfig-paths.d.ts +35 -0
  179. package/bin/utils/update-tsconfig-paths.js +286 -0
  180. package/package.json +154 -154
@@ -0,0 +1,180 @@
1
+ "use strict";
2
+ /**
3
+ * Template cache management
4
+ * Stores templates locally for offline access and performance
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.getTemplateCache = exports.TemplateCache = void 0;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const path_1 = __importDefault(require("path"));
13
+ const os_1 = __importDefault(require("os"));
14
+ const DEFAULT_CACHE_DIR = path_1.default.join(os_1.default.homedir(), ".expressots", "cache", "templates");
15
+ const DEFAULT_TTL = 86400; // 24 hours in seconds
16
+ class TemplateCache {
17
+ constructor(config) {
18
+ this.config = {
19
+ directory: config?.directory || DEFAULT_CACHE_DIR,
20
+ ttl: config?.ttl || DEFAULT_TTL,
21
+ };
22
+ this.ensureCacheDir();
23
+ }
24
+ /**
25
+ * Ensure cache directory exists
26
+ */
27
+ ensureCacheDir() {
28
+ if (!fs_1.default.existsSync(this.config.directory)) {
29
+ fs_1.default.mkdirSync(this.config.directory, { recursive: true });
30
+ }
31
+ }
32
+ /**
33
+ * Generate cache key from template identifier
34
+ */
35
+ getCacheKey(category, platform, variant) {
36
+ const parts = [category, platform];
37
+ if (variant)
38
+ parts.push(variant);
39
+ return parts.join("-") + ".cache.json";
40
+ }
41
+ /**
42
+ * Get cache file path
43
+ */
44
+ getCachePath(key) {
45
+ return path_1.default.join(this.config.directory, key);
46
+ }
47
+ /**
48
+ * Check if cache entry is valid (not expired)
49
+ */
50
+ isValid(entry) {
51
+ const now = Date.now();
52
+ const expiresAt = entry.timestamp + entry.ttl * 1000;
53
+ return now < expiresAt;
54
+ }
55
+ /**
56
+ * Get cached template content
57
+ */
58
+ get(category, platform, variant) {
59
+ const key = this.getCacheKey(category, platform, variant);
60
+ const cachePath = this.getCachePath(key);
61
+ try {
62
+ if (!fs_1.default.existsSync(cachePath)) {
63
+ return null;
64
+ }
65
+ const content = fs_1.default.readFileSync(cachePath, "utf-8");
66
+ const entry = JSON.parse(content);
67
+ if (!this.isValid(entry)) {
68
+ // Cache expired, remove it
69
+ this.delete(category, platform, variant);
70
+ return null;
71
+ }
72
+ return entry.data;
73
+ }
74
+ catch {
75
+ return null;
76
+ }
77
+ }
78
+ /**
79
+ * Set cached template content
80
+ */
81
+ set(category, platform, data, variant, ttl) {
82
+ const key = this.getCacheKey(category, platform, variant);
83
+ const cachePath = this.getCachePath(key);
84
+ const entry = {
85
+ data,
86
+ timestamp: Date.now(),
87
+ ttl: ttl || this.config.ttl,
88
+ };
89
+ try {
90
+ fs_1.default.writeFileSync(cachePath, JSON.stringify(entry, null, 2), "utf-8");
91
+ }
92
+ catch (error) {
93
+ // Silently fail - cache is optional
94
+ console.error("Failed to write cache:", error);
95
+ }
96
+ }
97
+ /**
98
+ * Delete cached template
99
+ */
100
+ delete(category, platform, variant) {
101
+ const key = this.getCacheKey(category, platform, variant);
102
+ const cachePath = this.getCachePath(key);
103
+ try {
104
+ if (fs_1.default.existsSync(cachePath)) {
105
+ fs_1.default.unlinkSync(cachePath);
106
+ }
107
+ }
108
+ catch {
109
+ // Ignore deletion errors
110
+ }
111
+ }
112
+ /**
113
+ * Clear all cached templates
114
+ */
115
+ clear() {
116
+ try {
117
+ const files = fs_1.default.readdirSync(this.config.directory);
118
+ for (const file of files) {
119
+ if (file.endsWith(".cache.json")) {
120
+ fs_1.default.unlinkSync(path_1.default.join(this.config.directory, file));
121
+ }
122
+ }
123
+ }
124
+ catch {
125
+ // Ignore errors
126
+ }
127
+ }
128
+ /**
129
+ * Get cache statistics
130
+ */
131
+ getStats() {
132
+ let files = 0;
133
+ let totalSize = 0;
134
+ let oldestTimestamp = Infinity;
135
+ try {
136
+ const entries = fs_1.default.readdirSync(this.config.directory);
137
+ for (const file of entries) {
138
+ if (!file.endsWith(".cache.json"))
139
+ continue;
140
+ const filePath = path_1.default.join(this.config.directory, file);
141
+ const stat = fs_1.default.statSync(filePath);
142
+ files++;
143
+ totalSize += stat.size;
144
+ try {
145
+ const content = JSON.parse(fs_1.default.readFileSync(filePath, "utf-8"));
146
+ if (content.timestamp < oldestTimestamp) {
147
+ oldestTimestamp = content.timestamp;
148
+ }
149
+ }
150
+ catch {
151
+ // Skip invalid cache files
152
+ }
153
+ }
154
+ }
155
+ catch {
156
+ // Directory doesn't exist or can't be read
157
+ }
158
+ return {
159
+ files,
160
+ totalSize,
161
+ oldestEntry: oldestTimestamp === Infinity ? null : new Date(oldestTimestamp),
162
+ };
163
+ }
164
+ /**
165
+ * Get cache directory path
166
+ */
167
+ getCacheDirectory() {
168
+ return this.config.directory;
169
+ }
170
+ }
171
+ exports.TemplateCache = TemplateCache;
172
+ // Singleton instance
173
+ let cacheInstance = null;
174
+ function getTemplateCache(config) {
175
+ if (!cacheInstance) {
176
+ cacheInstance = new TemplateCache(config);
177
+ }
178
+ return cacheInstance;
179
+ }
180
+ exports.getTemplateCache = getTemplateCache;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Templates CLI command
3
+ * Manage template sources, cache, and configuration
4
+ */
5
+ import { CommandModule } from "yargs";
6
+ type CommandModuleArgs = Record<string, never>;
7
+ declare const templatesCommand: () => CommandModule<CommandModuleArgs, any>;
8
+ export { templatesCommand };
@@ -0,0 +1,292 @@
1
+ "use strict";
2
+ /**
3
+ * Templates CLI command
4
+ * Manage template sources, cache, and configuration
5
+ */
6
+ var __importDefault = (this && this.__importDefault) || function (mod) {
7
+ return (mod && mod.__esModule) ? mod : { "default": mod };
8
+ };
9
+ Object.defineProperty(exports, "__esModule", { value: true });
10
+ exports.templatesCommand = void 0;
11
+ const chalk_1 = __importDefault(require("chalk"));
12
+ const manager_1 = require("./manager");
13
+ const config_1 = require("../config");
14
+ const templatesCommand = () => {
15
+ return {
16
+ command: "templates <action> [args...]",
17
+ describe: "Manage CLI templates for CI/CD, Docker, and Kubernetes.",
18
+ aliases: ["tpl"],
19
+ builder: (yargs) => {
20
+ yargs.positional("action", {
21
+ choices: [
22
+ "list",
23
+ "update",
24
+ "clear",
25
+ "info",
26
+ "repo",
27
+ "status",
28
+ ],
29
+ describe: "Action to perform",
30
+ type: "string",
31
+ demandOption: true,
32
+ });
33
+ yargs.positional("args", {
34
+ describe: "Additional arguments for the action",
35
+ type: "string",
36
+ array: true,
37
+ });
38
+ yargs.option("category", {
39
+ alias: "c",
40
+ type: "string",
41
+ describe: "Filter by category (cicd, docker, kubernetes, migrations)",
42
+ });
43
+ yargs.option("platform", {
44
+ alias: "p",
45
+ type: "string",
46
+ describe: "Filter by platform (github, gitlab, etc.)",
47
+ });
48
+ yargs.example("$0 templates list", "List all available templates");
49
+ yargs.example("$0 templates update", "Update template cache from remote");
50
+ yargs.example("$0 templates clear", "Clear local template cache");
51
+ yargs.example("$0 templates info cicd github", "Show template info");
52
+ yargs.example("$0 templates repo set https://github.com/myorg/templates", "Set custom repository");
53
+ yargs.example("$0 templates repo reset", "Reset to default repository");
54
+ yargs.example("$0 templates status", "Show template system status");
55
+ return yargs;
56
+ },
57
+ handler: async (argv) => {
58
+ const action = argv.action;
59
+ const args = argv.args || [];
60
+ switch (action) {
61
+ case "list":
62
+ await listTemplates(argv.category, argv.platform);
63
+ break;
64
+ case "update":
65
+ await updateTemplates();
66
+ break;
67
+ case "clear":
68
+ await clearCache();
69
+ break;
70
+ case "info":
71
+ await showTemplateInfo(args[0], args[1]);
72
+ break;
73
+ case "repo":
74
+ await manageRepository(args);
75
+ break;
76
+ case "status":
77
+ await showStatus();
78
+ break;
79
+ default:
80
+ console.log(chalk_1.default.red(`Unknown action: ${action}`));
81
+ console.log(chalk_1.default.gray("Run 'expressots templates --help' for usage."));
82
+ }
83
+ },
84
+ };
85
+ };
86
+ exports.templatesCommand = templatesCommand;
87
+ /**
88
+ * List available templates
89
+ */
90
+ async function listTemplates(category, platform) {
91
+ console.log(chalk_1.default.cyan("\nšŸ“‹ Available Templates\n"));
92
+ const manager = (0, manager_1.getTemplateManager)();
93
+ const templates = await manager.listTemplates();
94
+ // Show template source
95
+ const sourceLabel = templates.source === "remote"
96
+ ? chalk_1.default.green("(from remote repository)")
97
+ : chalk_1.default.yellow("(embedded fallback)");
98
+ console.log(chalk_1.default.gray(` Source: ${sourceLabel}\n`));
99
+ if (Object.keys(templates.cicd).length === 0 &&
100
+ templates.docker.length === 0 &&
101
+ templates.kubernetes.length === 0) {
102
+ console.log(chalk_1.default.yellow("No templates available. Run 'expressots templates update' to fetch templates."));
103
+ return;
104
+ }
105
+ // CI/CD Templates
106
+ if (!category || category === "cicd") {
107
+ console.log(chalk_1.default.bold("CI/CD Pipelines:"));
108
+ if (Object.keys(templates.cicd).length === 0) {
109
+ console.log(chalk_1.default.gray(" No CI/CD templates available"));
110
+ }
111
+ else {
112
+ for (const [plat, strategies] of Object.entries(templates.cicd)) {
113
+ if (!platform || platform === plat) {
114
+ console.log(` ${chalk_1.default.yellow(plat)}: ${strategies.join(", ")}`);
115
+ }
116
+ }
117
+ }
118
+ console.log();
119
+ }
120
+ // Docker Templates
121
+ if (!category || category === "docker") {
122
+ console.log(chalk_1.default.bold("Docker:"));
123
+ if (templates.docker.length === 0) {
124
+ console.log(chalk_1.default.gray(" No Docker templates available"));
125
+ }
126
+ else {
127
+ for (const tpl of templates.docker) {
128
+ console.log(` ${chalk_1.default.cyan(tpl)}`);
129
+ }
130
+ }
131
+ console.log();
132
+ }
133
+ // Kubernetes Templates
134
+ if (!category || category === "kubernetes") {
135
+ console.log(chalk_1.default.bold("Kubernetes:"));
136
+ if (templates.kubernetes.length === 0) {
137
+ console.log(chalk_1.default.gray(" No Kubernetes templates available"));
138
+ }
139
+ else {
140
+ for (const tpl of templates.kubernetes) {
141
+ console.log(` ${chalk_1.default.green(tpl)}`);
142
+ }
143
+ }
144
+ console.log();
145
+ }
146
+ // Migration Templates
147
+ if (!category || category === "migrations") {
148
+ console.log(chalk_1.default.bold("Migrations:"));
149
+ if (templates.migrations.length === 0) {
150
+ console.log(chalk_1.default.gray(" No migration templates available"));
151
+ }
152
+ else {
153
+ for (const tpl of templates.migrations) {
154
+ console.log(` ${chalk_1.default.magenta(tpl)}`);
155
+ }
156
+ }
157
+ console.log();
158
+ }
159
+ }
160
+ /**
161
+ * Update template cache
162
+ */
163
+ async function updateTemplates() {
164
+ console.log(chalk_1.default.cyan("\nšŸ”„ Updating Templates...\n"));
165
+ const manager = (0, manager_1.getTemplateManager)();
166
+ const result = await manager.updateCache();
167
+ if (result.updated > 0) {
168
+ console.log(chalk_1.default.green(`āœ“ Updated ${result.updated} templates`));
169
+ }
170
+ if (result.errors.length > 0) {
171
+ console.log(chalk_1.default.yellow(`\nāš ļø ${result.errors.length} errors occurred:`));
172
+ for (const error of result.errors) {
173
+ console.log(chalk_1.default.gray(` - ${error}`));
174
+ }
175
+ }
176
+ if (result.updated === 0 && result.errors.length === 0) {
177
+ console.log(chalk_1.default.yellow("No templates were updated. Check your network connection."));
178
+ }
179
+ console.log();
180
+ }
181
+ /**
182
+ * Clear template cache
183
+ */
184
+ async function clearCache() {
185
+ console.log(chalk_1.default.cyan("\nšŸ—‘ļø Clearing Template Cache...\n"));
186
+ const manager = (0, manager_1.getTemplateManager)();
187
+ const stats = manager.getCacheStats();
188
+ manager.clearCache();
189
+ console.log(chalk_1.default.green(`āœ“ Cleared ${stats.files} cached templates`));
190
+ console.log(chalk_1.default.gray(` Freed ${(stats.totalSize / 1024).toFixed(2)} KB`));
191
+ console.log();
192
+ }
193
+ /**
194
+ * Show template info
195
+ */
196
+ async function showTemplateInfo(category, platform) {
197
+ if (!category) {
198
+ console.log(chalk_1.default.red("Please specify a category and platform."));
199
+ console.log(chalk_1.default.gray("Example: expressots templates info cicd github"));
200
+ return;
201
+ }
202
+ console.log(chalk_1.default.cyan(`\nšŸ“„ Template Info: ${category}${platform ? `/${platform}` : ""}\n`));
203
+ const manager = (0, manager_1.getTemplateManager)();
204
+ const manifest = await manager.getManifest();
205
+ if (!manifest) {
206
+ console.log(chalk_1.default.yellow("No manifest available. Run 'expressots templates update' first."));
207
+ return;
208
+ }
209
+ const categoryTemplates = manifest.templates[category];
210
+ if (!categoryTemplates) {
211
+ console.log(chalk_1.default.red(`Category '${category}' not found.`));
212
+ return;
213
+ }
214
+ if (platform) {
215
+ const platformTemplates = categoryTemplates[platform];
216
+ if (!platformTemplates) {
217
+ console.log(chalk_1.default.red(`Platform '${platform}' not found in category '${category}'.`));
218
+ return;
219
+ }
220
+ console.log(chalk_1.default.bold(`${category}/${platform}:`));
221
+ for (const [variant, info] of Object.entries(platformTemplates)) {
222
+ console.log(` ${chalk_1.default.yellow(variant)}:`);
223
+ console.log(` Path: ${info.path}`);
224
+ console.log(` Version: ${info.version}`);
225
+ }
226
+ }
227
+ else {
228
+ console.log(chalk_1.default.bold(`${category}:`));
229
+ for (const [key, value] of Object.entries(categoryTemplates)) {
230
+ console.log(` ${chalk_1.default.yellow(key)}`);
231
+ }
232
+ }
233
+ console.log();
234
+ }
235
+ /**
236
+ * Manage template repository
237
+ */
238
+ async function manageRepository(args) {
239
+ const configManager = (0, config_1.getConfigManager)();
240
+ const subAction = args[0];
241
+ if (!subAction) {
242
+ const config = configManager.getTemplateConfig();
243
+ console.log(chalk_1.default.cyan("\nšŸ“¦ Template Repository Configuration\n"));
244
+ console.log(` Repository: ${chalk_1.default.yellow(config.repository)}`);
245
+ console.log(` Branch: ${chalk_1.default.cyan(config.branch)}`);
246
+ console.log(` Cache TTL: ${config.cacheTTL} seconds`);
247
+ console.log();
248
+ console.log(chalk_1.default.gray("Use 'expressots templates repo set <url>' to change."));
249
+ console.log(chalk_1.default.gray("Use 'expressots templates repo reset' to restore defaults."));
250
+ return;
251
+ }
252
+ switch (subAction) {
253
+ case "set": {
254
+ const repository = args[1];
255
+ const branch = args[2];
256
+ if (!repository) {
257
+ console.log(chalk_1.default.red("Please specify a repository URL."));
258
+ console.log(chalk_1.default.gray("Example: expressots templates repo set https://github.com/myorg/templates"));
259
+ return;
260
+ }
261
+ configManager.setTemplateRepository(repository, branch);
262
+ // Clear cache when repository changes
263
+ const manager = (0, manager_1.getTemplateManager)();
264
+ manager.clearCache();
265
+ manager.setRepository(repository, branch);
266
+ console.log(chalk_1.default.green(`\nāœ“ Template repository set to: ${repository}`));
267
+ if (branch) {
268
+ console.log(chalk_1.default.green(` Branch: ${branch}`));
269
+ }
270
+ console.log(chalk_1.default.gray("\nRun 'expressots templates update' to fetch templates from the new repository."));
271
+ break;
272
+ }
273
+ case "reset": {
274
+ configManager.resetTemplateRepository();
275
+ const manager = (0, manager_1.getTemplateManager)();
276
+ manager.clearCache();
277
+ manager.setRepository("expressots/templates", "main");
278
+ console.log(chalk_1.default.green("\nāœ“ Template repository reset to default (expressots/templates)"));
279
+ break;
280
+ }
281
+ default:
282
+ console.log(chalk_1.default.red(`Unknown repository action: ${subAction}`));
283
+ console.log(chalk_1.default.gray("Use 'set' or 'reset'."));
284
+ }
285
+ }
286
+ /**
287
+ * Show template system status
288
+ */
289
+ async function showStatus() {
290
+ const manager = (0, manager_1.getTemplateManager)();
291
+ await manager.printStatus();
292
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Template fetcher - fetches templates from GitHub repository
3
+ */
4
+ import type { TemplateManifest, FetchResult } from "./types";
5
+ export interface FetcherConfig {
6
+ repository: string;
7
+ branch: string;
8
+ timeout: number;
9
+ }
10
+ export declare class GitHubFetcher {
11
+ private config;
12
+ private retryCount;
13
+ private retryDelay;
14
+ constructor(config?: Partial<FetcherConfig>);
15
+ /**
16
+ * Build raw GitHub URL for a file
17
+ */
18
+ private buildUrl;
19
+ /**
20
+ * Fetch content from URL with retry logic
21
+ */
22
+ private fetchWithRetry;
23
+ /**
24
+ * Fetch template manifest
25
+ */
26
+ fetchManifest(): Promise<FetchResult<TemplateManifest>>;
27
+ /**
28
+ * Fetch template content by path
29
+ */
30
+ fetchTemplate(templatePath: string): Promise<FetchResult<string>>;
31
+ /**
32
+ * Fetch template by category, platform, and variant
33
+ */
34
+ fetchByType(category: string, platform: string, variant?: string): Promise<FetchResult<string>>;
35
+ /**
36
+ * Check if repository is accessible
37
+ */
38
+ checkConnection(): Promise<boolean>;
39
+ /**
40
+ * Update repository configuration
41
+ */
42
+ setRepository(repository: string, branch?: string): void;
43
+ /**
44
+ * Get current configuration
45
+ */
46
+ getConfig(): FetcherConfig;
47
+ }
48
+ export declare function getGitHubFetcher(config?: Partial<FetcherConfig>): GitHubFetcher;
49
+ export declare function resetFetcher(): void;