@stacksjs/ts-cloud-core 0.1.1

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 (251) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +321 -0
  3. package/package.json +31 -0
  4. package/src/advanced-features.test.ts +465 -0
  5. package/src/aws/cloudformation.ts +421 -0
  6. package/src/aws/cloudfront.ts +158 -0
  7. package/src/aws/credentials.test.ts +132 -0
  8. package/src/aws/credentials.ts +545 -0
  9. package/src/aws/index.ts +87 -0
  10. package/src/aws/s3.test.ts +188 -0
  11. package/src/aws/s3.ts +1088 -0
  12. package/src/aws/signature.test.ts +670 -0
  13. package/src/aws/signature.ts +1155 -0
  14. package/src/backup/disaster-recovery.test.ts +726 -0
  15. package/src/backup/disaster-recovery.ts +500 -0
  16. package/src/backup/index.ts +34 -0
  17. package/src/backup/manager.test.ts +498 -0
  18. package/src/backup/manager.ts +432 -0
  19. package/src/cicd/circleci.ts +430 -0
  20. package/src/cicd/github-actions.ts +424 -0
  21. package/src/cicd/gitlab-ci.ts +255 -0
  22. package/src/cicd/index.ts +8 -0
  23. package/src/cli/history.ts +396 -0
  24. package/src/cli/index.ts +10 -0
  25. package/src/cli/progress.ts +458 -0
  26. package/src/cli/repl.ts +454 -0
  27. package/src/cli/suggestions.ts +327 -0
  28. package/src/cli/table.test.ts +319 -0
  29. package/src/cli/table.ts +332 -0
  30. package/src/cloudformation/builder.test.ts +327 -0
  31. package/src/cloudformation/builder.ts +378 -0
  32. package/src/cloudformation/builders/api-gateway.ts +449 -0
  33. package/src/cloudformation/builders/cache.ts +334 -0
  34. package/src/cloudformation/builders/cdn.ts +278 -0
  35. package/src/cloudformation/builders/compute.ts +485 -0
  36. package/src/cloudformation/builders/database.ts +392 -0
  37. package/src/cloudformation/builders/functions.ts +343 -0
  38. package/src/cloudformation/builders/messaging.ts +140 -0
  39. package/src/cloudformation/builders/monitoring.ts +300 -0
  40. package/src/cloudformation/builders/network.ts +264 -0
  41. package/src/cloudformation/builders/queue.ts +147 -0
  42. package/src/cloudformation/builders/security.ts +399 -0
  43. package/src/cloudformation/builders/storage.ts +285 -0
  44. package/src/cloudformation/index.ts +30 -0
  45. package/src/cloudformation/types.ts +173 -0
  46. package/src/compliance/aws-config.ts +543 -0
  47. package/src/compliance/cloudtrail.ts +376 -0
  48. package/src/compliance/compliance.test.ts +423 -0
  49. package/src/compliance/guardduty.ts +446 -0
  50. package/src/compliance/index.ts +66 -0
  51. package/src/compliance/security-hub.ts +456 -0
  52. package/src/containers/build-optimization.ts +416 -0
  53. package/src/containers/containers.test.ts +508 -0
  54. package/src/containers/image-scanning.ts +360 -0
  55. package/src/containers/index.ts +9 -0
  56. package/src/containers/registry.ts +293 -0
  57. package/src/containers/service-mesh.ts +520 -0
  58. package/src/database/database.test.ts +762 -0
  59. package/src/database/index.ts +9 -0
  60. package/src/database/migrations.ts +444 -0
  61. package/src/database/performance.ts +528 -0
  62. package/src/database/replicas.ts +534 -0
  63. package/src/database/users.ts +494 -0
  64. package/src/dependency-graph.ts +143 -0
  65. package/src/deployment/ab-testing.ts +582 -0
  66. package/src/deployment/blue-green.ts +452 -0
  67. package/src/deployment/canary.ts +500 -0
  68. package/src/deployment/deployment.test.ts +526 -0
  69. package/src/deployment/index.ts +61 -0
  70. package/src/deployment/progressive.ts +62 -0
  71. package/src/dns/dns.test.ts +641 -0
  72. package/src/dns/dnssec.ts +315 -0
  73. package/src/dns/index.ts +8 -0
  74. package/src/dns/resolver.ts +496 -0
  75. package/src/dns/routing.ts +593 -0
  76. package/src/email/advanced/analytics.ts +445 -0
  77. package/src/email/advanced/index.ts +11 -0
  78. package/src/email/advanced/rules.ts +465 -0
  79. package/src/email/advanced/scheduling.ts +352 -0
  80. package/src/email/advanced/search.ts +412 -0
  81. package/src/email/advanced/shared-mailboxes.ts +404 -0
  82. package/src/email/advanced/templates.ts +455 -0
  83. package/src/email/advanced/threading.ts +281 -0
  84. package/src/email/analytics.ts +467 -0
  85. package/src/email/bounce-handling.ts +425 -0
  86. package/src/email/email.test.ts +431 -0
  87. package/src/email/handlers/__tests__/inbound.test.ts +38 -0
  88. package/src/email/handlers/__tests__/outbound.test.ts +37 -0
  89. package/src/email/handlers/converter.ts +227 -0
  90. package/src/email/handlers/feedback.ts +228 -0
  91. package/src/email/handlers/inbound.ts +169 -0
  92. package/src/email/handlers/outbound.ts +178 -0
  93. package/src/email/index.ts +15 -0
  94. package/src/email/reputation.ts +303 -0
  95. package/src/email/templates.ts +352 -0
  96. package/src/errors/index.test.ts +434 -0
  97. package/src/errors/index.ts +416 -0
  98. package/src/health-checks/index.ts +40 -0
  99. package/src/index.ts +360 -0
  100. package/src/intrinsic-functions.ts +118 -0
  101. package/src/lambda/concurrency.ts +330 -0
  102. package/src/lambda/destinations.ts +345 -0
  103. package/src/lambda/dlq.ts +425 -0
  104. package/src/lambda/index.ts +11 -0
  105. package/src/lambda/lambda.test.ts +840 -0
  106. package/src/lambda/layers.ts +263 -0
  107. package/src/lambda/versions.ts +376 -0
  108. package/src/lambda/vpc.ts +399 -0
  109. package/src/local/config.ts +114 -0
  110. package/src/local/index.ts +6 -0
  111. package/src/local/mock-aws.ts +351 -0
  112. package/src/modules/ai.ts +340 -0
  113. package/src/modules/api.ts +478 -0
  114. package/src/modules/auth.ts +805 -0
  115. package/src/modules/cache.ts +417 -0
  116. package/src/modules/cdn.ts +1062 -0
  117. package/src/modules/communication.ts +1094 -0
  118. package/src/modules/compute.ts +3348 -0
  119. package/src/modules/database.ts +554 -0
  120. package/src/modules/deployment.ts +1079 -0
  121. package/src/modules/dns.ts +337 -0
  122. package/src/modules/email.ts +1538 -0
  123. package/src/modules/filesystem.ts +515 -0
  124. package/src/modules/index.ts +32 -0
  125. package/src/modules/messaging.ts +486 -0
  126. package/src/modules/monitoring.ts +2086 -0
  127. package/src/modules/network.ts +664 -0
  128. package/src/modules/parameter-store.ts +325 -0
  129. package/src/modules/permissions.ts +1081 -0
  130. package/src/modules/phone.ts +494 -0
  131. package/src/modules/queue.ts +1260 -0
  132. package/src/modules/redirects.ts +464 -0
  133. package/src/modules/registry.ts +699 -0
  134. package/src/modules/search.ts +401 -0
  135. package/src/modules/secrets.ts +416 -0
  136. package/src/modules/security.ts +731 -0
  137. package/src/modules/sms.ts +389 -0
  138. package/src/modules/storage.ts +1120 -0
  139. package/src/modules/workflow.ts +680 -0
  140. package/src/multi-account/config.ts +521 -0
  141. package/src/multi-account/index.ts +7 -0
  142. package/src/multi-account/manager.ts +427 -0
  143. package/src/multi-region/cross-region.ts +410 -0
  144. package/src/multi-region/index.ts +8 -0
  145. package/src/multi-region/manager.ts +483 -0
  146. package/src/multi-region/regions.ts +435 -0
  147. package/src/network-security/index.ts +48 -0
  148. package/src/observability/index.ts +9 -0
  149. package/src/observability/logs.ts +522 -0
  150. package/src/observability/metrics.ts +460 -0
  151. package/src/observability/observability.test.ts +782 -0
  152. package/src/observability/synthetics.ts +568 -0
  153. package/src/observability/xray.ts +358 -0
  154. package/src/phone/advanced/analytics.ts +349 -0
  155. package/src/phone/advanced/callbacks.ts +428 -0
  156. package/src/phone/advanced/index.ts +8 -0
  157. package/src/phone/advanced/ivr-builder.ts +504 -0
  158. package/src/phone/advanced/recording.ts +310 -0
  159. package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
  160. package/src/phone/handlers/incoming-call.ts +117 -0
  161. package/src/phone/handlers/missed-call.ts +116 -0
  162. package/src/phone/handlers/voicemail.ts +179 -0
  163. package/src/phone/index.ts +9 -0
  164. package/src/presets/api-backend.ts +134 -0
  165. package/src/presets/data-pipeline.ts +204 -0
  166. package/src/presets/extend.test.ts +295 -0
  167. package/src/presets/extend.ts +297 -0
  168. package/src/presets/fullstack-app.ts +144 -0
  169. package/src/presets/index.ts +27 -0
  170. package/src/presets/jamstack.ts +135 -0
  171. package/src/presets/microservices.ts +167 -0
  172. package/src/presets/ml-api.ts +208 -0
  173. package/src/presets/nodejs-server.ts +104 -0
  174. package/src/presets/nodejs-serverless.ts +114 -0
  175. package/src/presets/realtime-app.ts +184 -0
  176. package/src/presets/static-site.ts +64 -0
  177. package/src/presets/traditional-web-app.ts +339 -0
  178. package/src/presets/wordpress.ts +138 -0
  179. package/src/preview/github.test.ts +249 -0
  180. package/src/preview/github.ts +297 -0
  181. package/src/preview/index.ts +37 -0
  182. package/src/preview/manager.test.ts +440 -0
  183. package/src/preview/manager.ts +326 -0
  184. package/src/preview/notifications.test.ts +582 -0
  185. package/src/preview/notifications.ts +341 -0
  186. package/src/queue/batch-processing.ts +402 -0
  187. package/src/queue/dlq-monitoring.ts +402 -0
  188. package/src/queue/fifo.ts +342 -0
  189. package/src/queue/index.ts +9 -0
  190. package/src/queue/management.ts +428 -0
  191. package/src/queue/queue.test.ts +429 -0
  192. package/src/resource-mgmt/index.ts +39 -0
  193. package/src/resource-naming.ts +62 -0
  194. package/src/s3/index.ts +523 -0
  195. package/src/schema/cloud-config.schema.json +554 -0
  196. package/src/schema/index.ts +68 -0
  197. package/src/security/certificate-manager.ts +492 -0
  198. package/src/security/index.ts +9 -0
  199. package/src/security/scanning.ts +545 -0
  200. package/src/security/secrets-manager.ts +476 -0
  201. package/src/security/secrets-rotation.ts +456 -0
  202. package/src/security/security.test.ts +738 -0
  203. package/src/sms/advanced/ab-testing.ts +389 -0
  204. package/src/sms/advanced/analytics.ts +336 -0
  205. package/src/sms/advanced/campaigns.ts +523 -0
  206. package/src/sms/advanced/chatbot.ts +224 -0
  207. package/src/sms/advanced/index.ts +10 -0
  208. package/src/sms/advanced/link-tracking.ts +248 -0
  209. package/src/sms/advanced/mms.ts +308 -0
  210. package/src/sms/handlers/__tests__/send.test.ts +40 -0
  211. package/src/sms/handlers/delivery-status.ts +133 -0
  212. package/src/sms/handlers/receive.ts +162 -0
  213. package/src/sms/handlers/send.ts +174 -0
  214. package/src/sms/index.ts +9 -0
  215. package/src/stack-diff.ts +389 -0
  216. package/src/static-site/index.ts +85 -0
  217. package/src/template-builder.ts +110 -0
  218. package/src/template-validator.ts +574 -0
  219. package/src/utils/cache.ts +291 -0
  220. package/src/utils/diff.ts +269 -0
  221. package/src/utils/hash.ts +227 -0
  222. package/src/utils/index.ts +8 -0
  223. package/src/utils/parallel.ts +294 -0
  224. package/src/validators/credentials.test.ts +274 -0
  225. package/src/validators/credentials.ts +233 -0
  226. package/src/validators/quotas.test.ts +434 -0
  227. package/src/validators/quotas.ts +217 -0
  228. package/test/ai.test.ts +327 -0
  229. package/test/api.test.ts +511 -0
  230. package/test/auth.test.ts +632 -0
  231. package/test/cache.test.ts +406 -0
  232. package/test/cdn.test.ts +247 -0
  233. package/test/compute.test.ts +861 -0
  234. package/test/database.test.ts +523 -0
  235. package/test/deployment.test.ts +499 -0
  236. package/test/dns.test.ts +270 -0
  237. package/test/email.test.ts +439 -0
  238. package/test/filesystem.test.ts +382 -0
  239. package/test/integration.test.ts +350 -0
  240. package/test/messaging.test.ts +514 -0
  241. package/test/monitoring.test.ts +634 -0
  242. package/test/network.test.ts +425 -0
  243. package/test/permissions.test.ts +488 -0
  244. package/test/queue.test.ts +484 -0
  245. package/test/registry.test.ts +306 -0
  246. package/test/security.test.ts +462 -0
  247. package/test/storage.test.ts +463 -0
  248. package/test/template-validator.test.ts +559 -0
  249. package/test/workflow.test.ts +592 -0
  250. package/tsconfig.json +16 -0
  251. package/tsconfig.tsbuildinfo +1 -0
@@ -0,0 +1,396 @@
1
+ /**
2
+ * Command history with search and persistence
3
+ * Tracks executed commands and provides search/replay functionality
4
+ */
5
+
6
+ export interface HistoryEntry {
7
+ command: string
8
+ timestamp: Date
9
+ success: boolean
10
+ duration?: number
11
+ output?: string
12
+ }
13
+
14
+ export interface HistoryOptions {
15
+ maxSize?: number
16
+ persistFile?: string
17
+ trackOutput?: boolean
18
+ }
19
+
20
+ /**
21
+ * Command history manager
22
+ */
23
+ export class CommandHistory {
24
+ private entries: HistoryEntry[] = []
25
+ private maxSize: number
26
+ private persistFile?: string
27
+ private trackOutput: boolean
28
+
29
+ constructor(options: HistoryOptions = {}) {
30
+ this.maxSize = options.maxSize || 1000
31
+ this.persistFile = options.persistFile
32
+ this.trackOutput = options.trackOutput || false
33
+ }
34
+
35
+ /**
36
+ * Add command to history
37
+ */
38
+ add(entry: Omit<HistoryEntry, 'timestamp'>): void {
39
+ this.entries.push({
40
+ ...entry,
41
+ timestamp: new Date(),
42
+ })
43
+
44
+ // Trim if exceeds max size
45
+ if (this.entries.length > this.maxSize) {
46
+ this.entries = this.entries.slice(-this.maxSize)
47
+ }
48
+ }
49
+
50
+ /**
51
+ * Get all history entries
52
+ */
53
+ getAll(): HistoryEntry[] {
54
+ return [...this.entries]
55
+ }
56
+
57
+ /**
58
+ * Get recent entries
59
+ */
60
+ getRecent(count: number = 10): HistoryEntry[] {
61
+ return this.entries.slice(-count)
62
+ }
63
+
64
+ /**
65
+ * Search history by command text
66
+ */
67
+ search(query: string): HistoryEntry[] {
68
+ const lowerQuery = query.toLowerCase()
69
+
70
+ return this.entries.filter(entry =>
71
+ entry.command.toLowerCase().includes(lowerQuery),
72
+ )
73
+ }
74
+
75
+ /**
76
+ * Search history by date range
77
+ */
78
+ searchByDate(startDate: Date, endDate: Date): HistoryEntry[] {
79
+ return this.entries.filter(
80
+ entry => entry.timestamp >= startDate && entry.timestamp <= endDate,
81
+ )
82
+ }
83
+
84
+ /**
85
+ * Get successful commands
86
+ */
87
+ getSuccessful(): HistoryEntry[] {
88
+ return this.entries.filter(entry => entry.success)
89
+ }
90
+
91
+ /**
92
+ * Get failed commands
93
+ */
94
+ getFailed(): HistoryEntry[] {
95
+ return this.entries.filter(entry => !entry.success)
96
+ }
97
+
98
+ /**
99
+ * Get most used commands
100
+ */
101
+ getMostUsed(count: number = 10): Array<{ command: string; count: number }> {
102
+ const commandCounts: Map<string, number> = new Map()
103
+
104
+ for (const entry of this.entries) {
105
+ const baseCommand = entry.command.split(' ')[0]
106
+ commandCounts.set(baseCommand, (commandCounts.get(baseCommand) || 0) + 1)
107
+ }
108
+
109
+ return Array.from(commandCounts.entries())
110
+ .map(([command, count]) => ({ command, count }))
111
+ .sort((a, b) => b.count - a.count)
112
+ .slice(0, count)
113
+ }
114
+
115
+ /**
116
+ * Get statistics
117
+ */
118
+ getStats(): {
119
+ total: number
120
+ successful: number
121
+ failed: number
122
+ averageDuration: number
123
+ mostUsed: string
124
+ } {
125
+ const total = this.entries.length
126
+ const successful = this.entries.filter(e => e.success).length
127
+ const failed = this.entries.filter(e => !e.success).length
128
+
129
+ const durationsWithValue = this.entries.filter(e => e.duration !== undefined)
130
+ const averageDuration = durationsWithValue.length > 0
131
+ ? durationsWithValue.reduce((sum, e) => sum + (e.duration || 0), 0) / durationsWithValue.length
132
+ : 0
133
+
134
+ const mostUsedList = this.getMostUsed(1)
135
+ const mostUsed = mostUsedList.length > 0 ? mostUsedList[0].command : 'N/A'
136
+
137
+ return {
138
+ total,
139
+ successful,
140
+ failed,
141
+ averageDuration,
142
+ mostUsed,
143
+ }
144
+ }
145
+
146
+ /**
147
+ * Clear history
148
+ */
149
+ clear(): void {
150
+ this.entries = []
151
+ }
152
+
153
+ /**
154
+ * Get entry by index
155
+ */
156
+ getByIndex(index: number): HistoryEntry | undefined {
157
+ if (index < 0 || index >= this.entries.length) {
158
+ return undefined
159
+ }
160
+ return this.entries[index]
161
+ }
162
+
163
+ /**
164
+ * Remove entry by index
165
+ */
166
+ removeByIndex(index: number): void {
167
+ if (index >= 0 && index < this.entries.length) {
168
+ this.entries.splice(index, 1)
169
+ }
170
+ }
171
+
172
+ /**
173
+ * Save history to file
174
+ */
175
+ async save(): Promise<void> {
176
+ if (!this.persistFile) return
177
+
178
+ try {
179
+ const fs = await import('node:fs/promises')
180
+ const data = JSON.stringify(this.entries, null, 2)
181
+ await fs.writeFile(this.persistFile, data, 'utf-8')
182
+ }
183
+ catch (error) {
184
+ throw new Error(`Failed to save history: ${error}`)
185
+ }
186
+ }
187
+
188
+ /**
189
+ * Load history from file
190
+ */
191
+ async load(): Promise<void> {
192
+ if (!this.persistFile) return
193
+
194
+ try {
195
+ const fs = await import('node:fs/promises')
196
+ const data = await fs.readFile(this.persistFile, 'utf-8')
197
+ const parsed = JSON.parse(data)
198
+
199
+ this.entries = parsed.map((entry: any) => ({
200
+ ...entry,
201
+ timestamp: new Date(entry.timestamp),
202
+ }))
203
+ }
204
+ catch {
205
+ // File doesn't exist or can't be read - that's ok
206
+ this.entries = []
207
+ }
208
+ }
209
+
210
+ /**
211
+ * Export history as JSON
212
+ */
213
+ exportJSON(): string {
214
+ return JSON.stringify(this.entries, null, 2)
215
+ }
216
+
217
+ /**
218
+ * Export history as CSV
219
+ */
220
+ exportCSV(): string {
221
+ const header = 'Timestamp,Command,Success,Duration'
222
+ const rows = this.entries.map(entry =>
223
+ [
224
+ entry.timestamp.toISOString(),
225
+ `"${entry.command.replace(/"/g, '""')}"`, // Escape quotes
226
+ entry.success,
227
+ entry.duration || '',
228
+ ].join(','),
229
+ )
230
+
231
+ return [header, ...rows].join('\n')
232
+ }
233
+
234
+ /**
235
+ * Import history from JSON
236
+ */
237
+ importJSON(json: string): void {
238
+ const parsed = JSON.parse(json)
239
+
240
+ const imported = parsed.map((entry: any) => ({
241
+ ...entry,
242
+ timestamp: new Date(entry.timestamp),
243
+ }))
244
+
245
+ this.entries.push(...imported)
246
+
247
+ // Trim if exceeds max size
248
+ if (this.entries.length > this.maxSize) {
249
+ this.entries = this.entries.slice(-this.maxSize)
250
+ }
251
+ }
252
+
253
+ /**
254
+ * Get history grouped by date
255
+ */
256
+ groupByDate(): Map<string, HistoryEntry[]> {
257
+ const grouped: Map<string, HistoryEntry[]> = new Map()
258
+
259
+ for (const entry of this.entries) {
260
+ const dateKey = entry.timestamp.toISOString().split('T')[0]
261
+
262
+ if (!grouped.has(dateKey)) {
263
+ grouped.set(dateKey, [])
264
+ }
265
+
266
+ grouped.get(dateKey)!.push(entry)
267
+ }
268
+
269
+ return grouped
270
+ }
271
+
272
+ /**
273
+ * Get history grouped by command
274
+ */
275
+ groupByCommand(): Map<string, HistoryEntry[]> {
276
+ const grouped: Map<string, HistoryEntry[]> = new Map()
277
+
278
+ for (const entry of this.entries) {
279
+ const baseCommand = entry.command.split(' ')[0]
280
+
281
+ if (!grouped.has(baseCommand)) {
282
+ grouped.set(baseCommand, [])
283
+ }
284
+
285
+ grouped.get(baseCommand)!.push(entry)
286
+ }
287
+
288
+ return grouped
289
+ }
290
+
291
+ /**
292
+ * Replay a command from history
293
+ */
294
+ replay(index: number): string | undefined {
295
+ const entry = this.getByIndex(index)
296
+ return entry?.command
297
+ }
298
+
299
+ /**
300
+ * Get suggestions based on partial input
301
+ */
302
+ getSuggestions(partial: string, limit: number = 5): string[] {
303
+ const lowerPartial = partial.toLowerCase()
304
+
305
+ // Find commands that start with the partial
306
+ const matches = this.entries
307
+ .filter(entry => entry.command.toLowerCase().startsWith(lowerPartial))
308
+ .map(entry => entry.command)
309
+
310
+ // Remove duplicates and limit
311
+ return [...new Set(matches)].slice(0, limit)
312
+ }
313
+
314
+ /**
315
+ * Analyze command patterns
316
+ */
317
+ analyzePatterns(): {
318
+ timeOfDay: Map<number, number> // hour -> count
319
+ dayOfWeek: Map<number, number> // day -> count
320
+ successRate: number
321
+ } {
322
+ const timeOfDay: Map<number, number> = new Map()
323
+ const dayOfWeek: Map<number, number> = new Map()
324
+
325
+ for (const entry of this.entries) {
326
+ const hour = entry.timestamp.getHours()
327
+ const day = entry.timestamp.getDay()
328
+
329
+ timeOfDay.set(hour, (timeOfDay.get(hour) || 0) + 1)
330
+ dayOfWeek.set(day, (dayOfWeek.get(day) || 0) + 1)
331
+ }
332
+
333
+ const successRate = this.entries.length > 0
334
+ ? this.getSuccessful().length / this.entries.length
335
+ : 0
336
+
337
+ return {
338
+ timeOfDay,
339
+ dayOfWeek,
340
+ successRate,
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Format history for display
347
+ */
348
+ export function formatHistory(entries: HistoryEntry[], options: { maxWidth?: number } = {}): string {
349
+ const { maxWidth = 100 } = options
350
+
351
+ if (entries.length === 0) {
352
+ return 'No command history'
353
+ }
354
+
355
+ const lines: string[] = []
356
+
357
+ for (let i = 0; i < entries.length; i++) {
358
+ const entry = entries[i]
359
+ const index = (i + 1).toString().padStart(4)
360
+ const timestamp = entry.timestamp.toLocaleString()
361
+ const status = entry.success ? '✓' : '✗'
362
+
363
+ let command = entry.command
364
+ if (command.length > maxWidth - 30) {
365
+ command = command.substring(0, maxWidth - 33) + '...'
366
+ }
367
+
368
+ let line = `${index} ${timestamp} ${status} ${command}`
369
+
370
+ if (entry.duration) {
371
+ line += ` (${entry.duration}ms)`
372
+ }
373
+
374
+ lines.push(line)
375
+ }
376
+
377
+ return lines.join('\n')
378
+ }
379
+
380
+ /**
381
+ * Format history statistics
382
+ */
383
+ export function formatHistoryStats(stats: ReturnType<CommandHistory['getStats']>): string {
384
+ const lines: string[] = []
385
+
386
+ lines.push('Command History Statistics')
387
+ lines.push('─'.repeat(30))
388
+ lines.push(`Total commands: ${stats.total}`)
389
+ lines.push(`Successful: ${stats.successful}`)
390
+ lines.push(`Failed: ${stats.failed}`)
391
+ lines.push(`Success rate: ${((stats.successful / stats.total) * 100).toFixed(1)}%`)
392
+ lines.push(`Average duration: ${stats.averageDuration.toFixed(0)}ms`)
393
+ lines.push(`Most used: ${stats.mostUsed}`)
394
+
395
+ return lines.join('\n')
396
+ }
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Advanced CLI utilities
3
+ * Interactive features, progress tracking, and better UX
4
+ */
5
+
6
+ export * from './table'
7
+ export * from './progress'
8
+ export * from './suggestions'
9
+ export * from './repl'
10
+ export * from './history'