@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.
- package/LICENSE.md +21 -0
- package/README.md +321 -0
- package/package.json +31 -0
- package/src/advanced-features.test.ts +465 -0
- package/src/aws/cloudformation.ts +421 -0
- package/src/aws/cloudfront.ts +158 -0
- package/src/aws/credentials.test.ts +132 -0
- package/src/aws/credentials.ts +545 -0
- package/src/aws/index.ts +87 -0
- package/src/aws/s3.test.ts +188 -0
- package/src/aws/s3.ts +1088 -0
- package/src/aws/signature.test.ts +670 -0
- package/src/aws/signature.ts +1155 -0
- package/src/backup/disaster-recovery.test.ts +726 -0
- package/src/backup/disaster-recovery.ts +500 -0
- package/src/backup/index.ts +34 -0
- package/src/backup/manager.test.ts +498 -0
- package/src/backup/manager.ts +432 -0
- package/src/cicd/circleci.ts +430 -0
- package/src/cicd/github-actions.ts +424 -0
- package/src/cicd/gitlab-ci.ts +255 -0
- package/src/cicd/index.ts +8 -0
- package/src/cli/history.ts +396 -0
- package/src/cli/index.ts +10 -0
- package/src/cli/progress.ts +458 -0
- package/src/cli/repl.ts +454 -0
- package/src/cli/suggestions.ts +327 -0
- package/src/cli/table.test.ts +319 -0
- package/src/cli/table.ts +332 -0
- package/src/cloudformation/builder.test.ts +327 -0
- package/src/cloudformation/builder.ts +378 -0
- package/src/cloudformation/builders/api-gateway.ts +449 -0
- package/src/cloudformation/builders/cache.ts +334 -0
- package/src/cloudformation/builders/cdn.ts +278 -0
- package/src/cloudformation/builders/compute.ts +485 -0
- package/src/cloudformation/builders/database.ts +392 -0
- package/src/cloudformation/builders/functions.ts +343 -0
- package/src/cloudformation/builders/messaging.ts +140 -0
- package/src/cloudformation/builders/monitoring.ts +300 -0
- package/src/cloudformation/builders/network.ts +264 -0
- package/src/cloudformation/builders/queue.ts +147 -0
- package/src/cloudformation/builders/security.ts +399 -0
- package/src/cloudformation/builders/storage.ts +285 -0
- package/src/cloudformation/index.ts +30 -0
- package/src/cloudformation/types.ts +173 -0
- package/src/compliance/aws-config.ts +543 -0
- package/src/compliance/cloudtrail.ts +376 -0
- package/src/compliance/compliance.test.ts +423 -0
- package/src/compliance/guardduty.ts +446 -0
- package/src/compliance/index.ts +66 -0
- package/src/compliance/security-hub.ts +456 -0
- package/src/containers/build-optimization.ts +416 -0
- package/src/containers/containers.test.ts +508 -0
- package/src/containers/image-scanning.ts +360 -0
- package/src/containers/index.ts +9 -0
- package/src/containers/registry.ts +293 -0
- package/src/containers/service-mesh.ts +520 -0
- package/src/database/database.test.ts +762 -0
- package/src/database/index.ts +9 -0
- package/src/database/migrations.ts +444 -0
- package/src/database/performance.ts +528 -0
- package/src/database/replicas.ts +534 -0
- package/src/database/users.ts +494 -0
- package/src/dependency-graph.ts +143 -0
- package/src/deployment/ab-testing.ts +582 -0
- package/src/deployment/blue-green.ts +452 -0
- package/src/deployment/canary.ts +500 -0
- package/src/deployment/deployment.test.ts +526 -0
- package/src/deployment/index.ts +61 -0
- package/src/deployment/progressive.ts +62 -0
- package/src/dns/dns.test.ts +641 -0
- package/src/dns/dnssec.ts +315 -0
- package/src/dns/index.ts +8 -0
- package/src/dns/resolver.ts +496 -0
- package/src/dns/routing.ts +593 -0
- package/src/email/advanced/analytics.ts +445 -0
- package/src/email/advanced/index.ts +11 -0
- package/src/email/advanced/rules.ts +465 -0
- package/src/email/advanced/scheduling.ts +352 -0
- package/src/email/advanced/search.ts +412 -0
- package/src/email/advanced/shared-mailboxes.ts +404 -0
- package/src/email/advanced/templates.ts +455 -0
- package/src/email/advanced/threading.ts +281 -0
- package/src/email/analytics.ts +467 -0
- package/src/email/bounce-handling.ts +425 -0
- package/src/email/email.test.ts +431 -0
- package/src/email/handlers/__tests__/inbound.test.ts +38 -0
- package/src/email/handlers/__tests__/outbound.test.ts +37 -0
- package/src/email/handlers/converter.ts +227 -0
- package/src/email/handlers/feedback.ts +228 -0
- package/src/email/handlers/inbound.ts +169 -0
- package/src/email/handlers/outbound.ts +178 -0
- package/src/email/index.ts +15 -0
- package/src/email/reputation.ts +303 -0
- package/src/email/templates.ts +352 -0
- package/src/errors/index.test.ts +434 -0
- package/src/errors/index.ts +416 -0
- package/src/health-checks/index.ts +40 -0
- package/src/index.ts +360 -0
- package/src/intrinsic-functions.ts +118 -0
- package/src/lambda/concurrency.ts +330 -0
- package/src/lambda/destinations.ts +345 -0
- package/src/lambda/dlq.ts +425 -0
- package/src/lambda/index.ts +11 -0
- package/src/lambda/lambda.test.ts +840 -0
- package/src/lambda/layers.ts +263 -0
- package/src/lambda/versions.ts +376 -0
- package/src/lambda/vpc.ts +399 -0
- package/src/local/config.ts +114 -0
- package/src/local/index.ts +6 -0
- package/src/local/mock-aws.ts +351 -0
- package/src/modules/ai.ts +340 -0
- package/src/modules/api.ts +478 -0
- package/src/modules/auth.ts +805 -0
- package/src/modules/cache.ts +417 -0
- package/src/modules/cdn.ts +1062 -0
- package/src/modules/communication.ts +1094 -0
- package/src/modules/compute.ts +3348 -0
- package/src/modules/database.ts +554 -0
- package/src/modules/deployment.ts +1079 -0
- package/src/modules/dns.ts +337 -0
- package/src/modules/email.ts +1538 -0
- package/src/modules/filesystem.ts +515 -0
- package/src/modules/index.ts +32 -0
- package/src/modules/messaging.ts +486 -0
- package/src/modules/monitoring.ts +2086 -0
- package/src/modules/network.ts +664 -0
- package/src/modules/parameter-store.ts +325 -0
- package/src/modules/permissions.ts +1081 -0
- package/src/modules/phone.ts +494 -0
- package/src/modules/queue.ts +1260 -0
- package/src/modules/redirects.ts +464 -0
- package/src/modules/registry.ts +699 -0
- package/src/modules/search.ts +401 -0
- package/src/modules/secrets.ts +416 -0
- package/src/modules/security.ts +731 -0
- package/src/modules/sms.ts +389 -0
- package/src/modules/storage.ts +1120 -0
- package/src/modules/workflow.ts +680 -0
- package/src/multi-account/config.ts +521 -0
- package/src/multi-account/index.ts +7 -0
- package/src/multi-account/manager.ts +427 -0
- package/src/multi-region/cross-region.ts +410 -0
- package/src/multi-region/index.ts +8 -0
- package/src/multi-region/manager.ts +483 -0
- package/src/multi-region/regions.ts +435 -0
- package/src/network-security/index.ts +48 -0
- package/src/observability/index.ts +9 -0
- package/src/observability/logs.ts +522 -0
- package/src/observability/metrics.ts +460 -0
- package/src/observability/observability.test.ts +782 -0
- package/src/observability/synthetics.ts +568 -0
- package/src/observability/xray.ts +358 -0
- package/src/phone/advanced/analytics.ts +349 -0
- package/src/phone/advanced/callbacks.ts +428 -0
- package/src/phone/advanced/index.ts +8 -0
- package/src/phone/advanced/ivr-builder.ts +504 -0
- package/src/phone/advanced/recording.ts +310 -0
- package/src/phone/handlers/__tests__/incoming-call.test.ts +40 -0
- package/src/phone/handlers/incoming-call.ts +117 -0
- package/src/phone/handlers/missed-call.ts +116 -0
- package/src/phone/handlers/voicemail.ts +179 -0
- package/src/phone/index.ts +9 -0
- package/src/presets/api-backend.ts +134 -0
- package/src/presets/data-pipeline.ts +204 -0
- package/src/presets/extend.test.ts +295 -0
- package/src/presets/extend.ts +297 -0
- package/src/presets/fullstack-app.ts +144 -0
- package/src/presets/index.ts +27 -0
- package/src/presets/jamstack.ts +135 -0
- package/src/presets/microservices.ts +167 -0
- package/src/presets/ml-api.ts +208 -0
- package/src/presets/nodejs-server.ts +104 -0
- package/src/presets/nodejs-serverless.ts +114 -0
- package/src/presets/realtime-app.ts +184 -0
- package/src/presets/static-site.ts +64 -0
- package/src/presets/traditional-web-app.ts +339 -0
- package/src/presets/wordpress.ts +138 -0
- package/src/preview/github.test.ts +249 -0
- package/src/preview/github.ts +297 -0
- package/src/preview/index.ts +37 -0
- package/src/preview/manager.test.ts +440 -0
- package/src/preview/manager.ts +326 -0
- package/src/preview/notifications.test.ts +582 -0
- package/src/preview/notifications.ts +341 -0
- package/src/queue/batch-processing.ts +402 -0
- package/src/queue/dlq-monitoring.ts +402 -0
- package/src/queue/fifo.ts +342 -0
- package/src/queue/index.ts +9 -0
- package/src/queue/management.ts +428 -0
- package/src/queue/queue.test.ts +429 -0
- package/src/resource-mgmt/index.ts +39 -0
- package/src/resource-naming.ts +62 -0
- package/src/s3/index.ts +523 -0
- package/src/schema/cloud-config.schema.json +554 -0
- package/src/schema/index.ts +68 -0
- package/src/security/certificate-manager.ts +492 -0
- package/src/security/index.ts +9 -0
- package/src/security/scanning.ts +545 -0
- package/src/security/secrets-manager.ts +476 -0
- package/src/security/secrets-rotation.ts +456 -0
- package/src/security/security.test.ts +738 -0
- package/src/sms/advanced/ab-testing.ts +389 -0
- package/src/sms/advanced/analytics.ts +336 -0
- package/src/sms/advanced/campaigns.ts +523 -0
- package/src/sms/advanced/chatbot.ts +224 -0
- package/src/sms/advanced/index.ts +10 -0
- package/src/sms/advanced/link-tracking.ts +248 -0
- package/src/sms/advanced/mms.ts +308 -0
- package/src/sms/handlers/__tests__/send.test.ts +40 -0
- package/src/sms/handlers/delivery-status.ts +133 -0
- package/src/sms/handlers/receive.ts +162 -0
- package/src/sms/handlers/send.ts +174 -0
- package/src/sms/index.ts +9 -0
- package/src/stack-diff.ts +389 -0
- package/src/static-site/index.ts +85 -0
- package/src/template-builder.ts +110 -0
- package/src/template-validator.ts +574 -0
- package/src/utils/cache.ts +291 -0
- package/src/utils/diff.ts +269 -0
- package/src/utils/hash.ts +227 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/parallel.ts +294 -0
- package/src/validators/credentials.test.ts +274 -0
- package/src/validators/credentials.ts +233 -0
- package/src/validators/quotas.test.ts +434 -0
- package/src/validators/quotas.ts +217 -0
- package/test/ai.test.ts +327 -0
- package/test/api.test.ts +511 -0
- package/test/auth.test.ts +632 -0
- package/test/cache.test.ts +406 -0
- package/test/cdn.test.ts +247 -0
- package/test/compute.test.ts +861 -0
- package/test/database.test.ts +523 -0
- package/test/deployment.test.ts +499 -0
- package/test/dns.test.ts +270 -0
- package/test/email.test.ts +439 -0
- package/test/filesystem.test.ts +382 -0
- package/test/integration.test.ts +350 -0
- package/test/messaging.test.ts +514 -0
- package/test/monitoring.test.ts +634 -0
- package/test/network.test.ts +425 -0
- package/test/permissions.test.ts +488 -0
- package/test/queue.test.ts +484 -0
- package/test/registry.test.ts +306 -0
- package/test/security.test.ts +462 -0
- package/test/storage.test.ts +463 -0
- package/test/template-validator.test.ts +559 -0
- package/test/workflow.test.ts +592 -0
- package/tsconfig.json +16 -0
- package/tsconfig.tsbuildinfo +1 -0
package/src/cli/repl.ts
ADDED
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interactive REPL mode for ts-cloud CLI
|
|
3
|
+
* Provides a shell-like experience for running commands
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
export interface REPLOptions {
|
|
7
|
+
prompt?: string
|
|
8
|
+
welcome?: string
|
|
9
|
+
commands: Map<string, REPLCommand>
|
|
10
|
+
historyFile?: string
|
|
11
|
+
autocomplete?: boolean
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface REPLCommand {
|
|
15
|
+
name: string
|
|
16
|
+
description: string
|
|
17
|
+
aliases?: string[]
|
|
18
|
+
handler: (args: string[]) => Promise<void> | void
|
|
19
|
+
autocomplete?: (partial: string) => string[]
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface REPLHistory {
|
|
23
|
+
commands: string[]
|
|
24
|
+
maxSize: number
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* REPL session manager
|
|
29
|
+
*/
|
|
30
|
+
export class REPL {
|
|
31
|
+
private options: REPLOptions
|
|
32
|
+
private running: boolean = false
|
|
33
|
+
private history: REPLHistory = {
|
|
34
|
+
commands: [],
|
|
35
|
+
maxSize: 1000,
|
|
36
|
+
}
|
|
37
|
+
private historyIndex: number = -1
|
|
38
|
+
|
|
39
|
+
constructor(options: REPLOptions) {
|
|
40
|
+
this.options = {
|
|
41
|
+
prompt: options.prompt || '> ',
|
|
42
|
+
welcome: options.welcome || 'Welcome to ts-cloud interactive mode. Type "help" for available commands.',
|
|
43
|
+
...options,
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Start REPL session
|
|
49
|
+
*/
|
|
50
|
+
async start(): Promise<void> {
|
|
51
|
+
this.running = true
|
|
52
|
+
|
|
53
|
+
// Print welcome message
|
|
54
|
+
if (this.options.welcome) {
|
|
55
|
+
console.log(this.options.welcome)
|
|
56
|
+
console.log('')
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Load history from file if specified
|
|
60
|
+
if (this.options.historyFile) {
|
|
61
|
+
await this.loadHistory()
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// Main REPL loop
|
|
65
|
+
while (this.running) {
|
|
66
|
+
try {
|
|
67
|
+
const input = await this.readInput()
|
|
68
|
+
|
|
69
|
+
if (!input.trim()) continue
|
|
70
|
+
|
|
71
|
+
// Add to history
|
|
72
|
+
this.addToHistory(input)
|
|
73
|
+
|
|
74
|
+
// Parse and execute command
|
|
75
|
+
await this.executeCommand(input)
|
|
76
|
+
}
|
|
77
|
+
catch (error) {
|
|
78
|
+
if (error instanceof Error) {
|
|
79
|
+
console.error(`Error: ${error.message}`)
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Save history before exiting
|
|
85
|
+
if (this.options.historyFile) {
|
|
86
|
+
await this.saveHistory()
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Stop REPL session
|
|
92
|
+
*/
|
|
93
|
+
stop(): void {
|
|
94
|
+
this.running = false
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Read input from user
|
|
99
|
+
*/
|
|
100
|
+
private async readInput(): Promise<string> {
|
|
101
|
+
// In a real implementation, this would use readline or similar
|
|
102
|
+
// For now, we'll return a mock implementation
|
|
103
|
+
return new Promise((resolve) => {
|
|
104
|
+
// Mock implementation - in real code, use readline
|
|
105
|
+
process.stdout.write(this.options.prompt || '> ')
|
|
106
|
+
|
|
107
|
+
// This is a simplified version - real implementation would handle:
|
|
108
|
+
// - Line editing
|
|
109
|
+
// - History navigation (up/down arrows)
|
|
110
|
+
// - Autocomplete (tab)
|
|
111
|
+
// - Ctrl+C handling
|
|
112
|
+
resolve('')
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/**
|
|
117
|
+
* Execute command
|
|
118
|
+
*/
|
|
119
|
+
private async executeCommand(input: string): Promise<void> {
|
|
120
|
+
const [commandName, ...args] = this.parseCommand(input)
|
|
121
|
+
|
|
122
|
+
// Check for built-in commands
|
|
123
|
+
if (commandName === 'exit' || commandName === 'quit') {
|
|
124
|
+
this.stop()
|
|
125
|
+
return
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (commandName === 'help') {
|
|
129
|
+
this.showHelp()
|
|
130
|
+
return
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
if (commandName === 'history') {
|
|
134
|
+
this.showHistory()
|
|
135
|
+
return
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (commandName === 'clear') {
|
|
139
|
+
console.clear()
|
|
140
|
+
return
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
// Find command (including aliases)
|
|
144
|
+
const command = this.findCommand(commandName)
|
|
145
|
+
|
|
146
|
+
if (!command) {
|
|
147
|
+
console.error(`Unknown command: ${commandName}`)
|
|
148
|
+
console.log('Type "help" to see available commands.')
|
|
149
|
+
return
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// Execute command handler
|
|
153
|
+
try {
|
|
154
|
+
await command.handler(args)
|
|
155
|
+
}
|
|
156
|
+
catch (error) {
|
|
157
|
+
if (error instanceof Error) {
|
|
158
|
+
console.error(`Command failed: ${error.message}`)
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Parse command input
|
|
165
|
+
*/
|
|
166
|
+
private parseCommand(input: string): string[] {
|
|
167
|
+
// Simple parser - could be enhanced to handle:
|
|
168
|
+
// - Quoted strings
|
|
169
|
+
// - Escaped characters
|
|
170
|
+
// - Variable substitution
|
|
171
|
+
return input.trim().split(/\s+/)
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Find command by name or alias
|
|
176
|
+
*/
|
|
177
|
+
private findCommand(name: string): REPLCommand | undefined {
|
|
178
|
+
for (const [_key, command] of this.options.commands) {
|
|
179
|
+
if (command.name === name || command.aliases?.includes(name)) {
|
|
180
|
+
return command
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return undefined
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
/**
|
|
187
|
+
* Show help message
|
|
188
|
+
*/
|
|
189
|
+
private showHelp(): void {
|
|
190
|
+
console.log('Available commands:')
|
|
191
|
+
console.log('')
|
|
192
|
+
|
|
193
|
+
const commands = Array.from(this.options.commands.values())
|
|
194
|
+
|
|
195
|
+
// Built-in commands
|
|
196
|
+
console.log(' help Show this help message')
|
|
197
|
+
console.log(' history Show command history')
|
|
198
|
+
console.log(' clear Clear screen')
|
|
199
|
+
console.log(' exit, quit Exit interactive mode')
|
|
200
|
+
console.log('')
|
|
201
|
+
|
|
202
|
+
// User commands
|
|
203
|
+
for (const command of commands) {
|
|
204
|
+
let line = ` ${command.name.padEnd(20)} ${command.description}`
|
|
205
|
+
|
|
206
|
+
if (command.aliases && command.aliases.length > 0) {
|
|
207
|
+
line += ` (aliases: ${command.aliases.join(', ')})`
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
console.log(line)
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Show command history
|
|
216
|
+
*/
|
|
217
|
+
private showHistory(): void {
|
|
218
|
+
if (this.history.commands.length === 0) {
|
|
219
|
+
console.log('No command history')
|
|
220
|
+
return
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
console.log('Command history:')
|
|
224
|
+
this.history.commands.forEach((cmd, index) => {
|
|
225
|
+
console.log(` ${(index + 1).toString().padStart(4)} ${cmd}`)
|
|
226
|
+
})
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Add command to history
|
|
231
|
+
*/
|
|
232
|
+
private addToHistory(command: string): void {
|
|
233
|
+
// Don't add duplicates of the last command
|
|
234
|
+
if (this.history.commands[this.history.commands.length - 1] === command) {
|
|
235
|
+
return
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
this.history.commands.push(command)
|
|
239
|
+
|
|
240
|
+
// Trim history if it exceeds max size
|
|
241
|
+
if (this.history.commands.length > this.history.maxSize) {
|
|
242
|
+
this.history.commands = this.history.commands.slice(-this.history.maxSize)
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.historyIndex = this.history.commands.length
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
/**
|
|
249
|
+
* Navigate history (up arrow)
|
|
250
|
+
*/
|
|
251
|
+
private historyBack(): string | undefined {
|
|
252
|
+
if (this.historyIndex > 0) {
|
|
253
|
+
this.historyIndex--
|
|
254
|
+
return this.history.commands[this.historyIndex]
|
|
255
|
+
}
|
|
256
|
+
return undefined
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Navigate history (down arrow)
|
|
261
|
+
*/
|
|
262
|
+
private historyForward(): string | undefined {
|
|
263
|
+
if (this.historyIndex < this.history.commands.length - 1) {
|
|
264
|
+
this.historyIndex++
|
|
265
|
+
return this.history.commands[this.historyIndex]
|
|
266
|
+
}
|
|
267
|
+
this.historyIndex = this.history.commands.length
|
|
268
|
+
return ''
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
/**
|
|
272
|
+
* Autocomplete command
|
|
273
|
+
*/
|
|
274
|
+
private autocomplete(partial: string): string[] {
|
|
275
|
+
const suggestions: string[] = []
|
|
276
|
+
|
|
277
|
+
// Check built-in commands
|
|
278
|
+
const builtins = ['help', 'history', 'clear', 'exit', 'quit']
|
|
279
|
+
for (const builtin of builtins) {
|
|
280
|
+
if (builtin.startsWith(partial)) {
|
|
281
|
+
suggestions.push(builtin)
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
// Check user commands
|
|
286
|
+
for (const [_key, command] of this.options.commands) {
|
|
287
|
+
if (command.name.startsWith(partial)) {
|
|
288
|
+
suggestions.push(command.name)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
if (command.aliases) {
|
|
292
|
+
for (const alias of command.aliases) {
|
|
293
|
+
if (alias.startsWith(partial)) {
|
|
294
|
+
suggestions.push(alias)
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
return suggestions
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Load history from file
|
|
305
|
+
*/
|
|
306
|
+
private async loadHistory(): Promise<void> {
|
|
307
|
+
if (!this.options.historyFile) return
|
|
308
|
+
|
|
309
|
+
try {
|
|
310
|
+
const fs = await import('node:fs/promises')
|
|
311
|
+
const data = await fs.readFile(this.options.historyFile, 'utf-8')
|
|
312
|
+
this.history.commands = data.split('\n').filter(line => line.trim())
|
|
313
|
+
this.historyIndex = this.history.commands.length
|
|
314
|
+
}
|
|
315
|
+
catch {
|
|
316
|
+
// File doesn't exist or can't be read - that's ok
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Save history to file
|
|
322
|
+
*/
|
|
323
|
+
private async saveHistory(): Promise<void> {
|
|
324
|
+
if (!this.options.historyFile) return
|
|
325
|
+
|
|
326
|
+
try {
|
|
327
|
+
const fs = await import('node:fs/promises')
|
|
328
|
+
await fs.writeFile(this.options.historyFile, this.history.commands.join('\n'))
|
|
329
|
+
}
|
|
330
|
+
catch (error) {
|
|
331
|
+
console.error(`Failed to save history: ${error}`)
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Search history
|
|
337
|
+
*/
|
|
338
|
+
searchHistory(query: string): string[] {
|
|
339
|
+
return this.history.commands.filter(cmd => cmd.includes(query))
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Clear history
|
|
344
|
+
*/
|
|
345
|
+
clearHistory(): void {
|
|
346
|
+
this.history.commands = []
|
|
347
|
+
this.historyIndex = 0
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
/**
|
|
352
|
+
* Context manager for REPL sessions
|
|
353
|
+
* Maintains state across commands
|
|
354
|
+
*/
|
|
355
|
+
export class REPLContext {
|
|
356
|
+
private variables: Map<string, any> = new Map()
|
|
357
|
+
private workingDirectory: string = process.cwd()
|
|
358
|
+
|
|
359
|
+
/**
|
|
360
|
+
* Set variable
|
|
361
|
+
*/
|
|
362
|
+
set(key: string, value: any): void {
|
|
363
|
+
this.variables.set(key, value)
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* Get variable
|
|
368
|
+
*/
|
|
369
|
+
get(key: string): any {
|
|
370
|
+
return this.variables.get(key)
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Check if variable exists
|
|
375
|
+
*/
|
|
376
|
+
has(key: string): boolean {
|
|
377
|
+
return this.variables.has(key)
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
/**
|
|
381
|
+
* Delete variable
|
|
382
|
+
*/
|
|
383
|
+
delete(key: string): void {
|
|
384
|
+
this.variables.delete(key)
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Get all variables
|
|
389
|
+
*/
|
|
390
|
+
getAll(): Record<string, any> {
|
|
391
|
+
return Object.fromEntries(this.variables)
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Clear all variables
|
|
396
|
+
*/
|
|
397
|
+
clear(): void {
|
|
398
|
+
this.variables.clear()
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* Set working directory
|
|
403
|
+
*/
|
|
404
|
+
setWorkingDirectory(path: string): void {
|
|
405
|
+
this.workingDirectory = path
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/**
|
|
409
|
+
* Get working directory
|
|
410
|
+
*/
|
|
411
|
+
getWorkingDirectory(): string {
|
|
412
|
+
return this.workingDirectory
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
/**
|
|
417
|
+
* Command builder for creating REPL commands
|
|
418
|
+
*/
|
|
419
|
+
export class REPLCommandBuilder {
|
|
420
|
+
private command: Partial<REPLCommand> = {}
|
|
421
|
+
|
|
422
|
+
name(name: string): this {
|
|
423
|
+
this.command.name = name
|
|
424
|
+
return this
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
description(description: string): this {
|
|
428
|
+
this.command.description = description
|
|
429
|
+
return this
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
aliases(...aliases: string[]): this {
|
|
433
|
+
this.command.aliases = aliases
|
|
434
|
+
return this
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
handler(handler: (args: string[]) => Promise<void> | void): this {
|
|
438
|
+
this.command.handler = handler
|
|
439
|
+
return this
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
autocomplete(fn: (partial: string) => string[]): this {
|
|
443
|
+
this.command.autocomplete = fn
|
|
444
|
+
return this
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
build(): REPLCommand {
|
|
448
|
+
if (!this.command.name || !this.command.description || !this.command.handler) {
|
|
449
|
+
throw new Error('Command must have name, description, and handler')
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
return this.command as REPLCommand
|
|
453
|
+
}
|
|
454
|
+
}
|