ai-summon 0.0.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/.claude/commands/speckit.analyze.md +184 -0
- package/.claude/commands/speckit.checklist.md +294 -0
- package/.claude/commands/speckit.clarify.md +177 -0
- package/.claude/commands/speckit.constitution.md +78 -0
- package/.claude/commands/speckit.implement.md +121 -0
- package/.claude/commands/speckit.plan.md +81 -0
- package/.claude/commands/speckit.specify.md +204 -0
- package/.claude/commands/speckit.tasks.md +108 -0
- package/.claude/settings.local.json +23 -0
- package/.prettierignore +5 -0
- package/.prettierrc.json +10 -0
- package/.specify/memory/constitution.md +72 -0
- package/.specify/scripts/bash/check-prerequisites.sh +166 -0
- package/.specify/scripts/bash/common.sh +113 -0
- package/.specify/scripts/bash/create-new-feature.sh +97 -0
- package/.specify/scripts/bash/setup-plan.sh +60 -0
- package/.specify/scripts/bash/update-agent-context.sh +738 -0
- package/.specify/templates/agent-file-template.md +28 -0
- package/.specify/templates/checklist-template.md +40 -0
- package/.specify/templates/plan-template.md +111 -0
- package/.specify/templates/spec-template.md +115 -0
- package/.specify/templates/tasks-template.md +250 -0
- package/CLAUDE.md +199 -0
- package/PRD.md +268 -0
- package/README.md +171 -0
- package/dist/ai-summon.d.ts +2 -0
- package/dist/ai-summon.js +73 -0
- package/dist/commands/ide/index.d.ts +3 -0
- package/dist/commands/ide/index.js +253 -0
- package/dist/commands/init.d.ts +4 -0
- package/dist/commands/init.js +55 -0
- package/dist/commands/url.d.ts +4 -0
- package/dist/commands/url.js +223 -0
- package/dist/types/index.d.ts +40 -0
- package/dist/types/index.js +1 -0
- package/dist/util.d.ts +16 -0
- package/dist/util.js +109 -0
- package/eslint.config.js +47 -0
- package/package.json +47 -0
- package/specs/001-cloud-login-feature/contracts/cloud-command.ts +82 -0
- package/specs/001-cloud-login-feature/contracts/config-service.ts +170 -0
- package/specs/001-cloud-login-feature/data-model.md +269 -0
- package/specs/001-cloud-login-feature/plan.md +91 -0
- package/specs/001-cloud-login-feature/quickstart.md +366 -0
- package/specs/001-cloud-login-feature/research.md +290 -0
- package/specs/001-cloud-login-feature/spec.md +195 -0
- package/specs/001-cloud-login-feature/tasks.md +235 -0
- package/specs/001-cloud-scp-command/contracts/cloud-scp-api.ts +402 -0
- package/specs/001-cloud-scp-command/data-model.md +424 -0
- package/specs/001-cloud-scp-command/plan.md +124 -0
- package/specs/001-cloud-scp-command/quickstart.md +536 -0
- package/specs/001-cloud-scp-command/research.md +345 -0
- package/specs/001-cloud-scp-command/spec.md +248 -0
- package/specs/001-cloud-scp-command/tasks.md +434 -0
- package/src/ai-summon.ts +88 -0
- package/src/commands/ide/index.ts +322 -0
- package/src/commands/init.ts +64 -0
- package/src/commands/url.ts +262 -0
- package/src/types/index.ts +49 -0
- package/src/util.ts +146 -0
- package/tsconfig.json +21 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# Research: Cloud SCP Command
|
|
2
|
+
|
|
3
|
+
**Feature**: 001-cloud-scp-command
|
|
4
|
+
**Date**: 2025-10-11
|
|
5
|
+
**Status**: Complete
|
|
6
|
+
|
|
7
|
+
## Research Overview
|
|
8
|
+
|
|
9
|
+
This document consolidates research findings for implementing the `hsh cloud scp` command. Since this feature extends existing cloud infrastructure functionality, research focuses on SCP best practices, path validation approaches, and integration patterns with the existing codebase.
|
|
10
|
+
|
|
11
|
+
## Decision 1: SCP Command Pattern
|
|
12
|
+
|
|
13
|
+
### Decision
|
|
14
|
+
|
|
15
|
+
Use `scp -i {privateKey} scp [flags] {source} {user}@{host}:{dest}` pattern for SCP execution.
|
|
16
|
+
|
|
17
|
+
### Rationale
|
|
18
|
+
|
|
19
|
+
- **Consistency**: Matches the SSH approach used in `cloud login` command
|
|
20
|
+
- **Key Management**: Ensures proper private key authentication flow
|
|
21
|
+
- **Error Handling**: SSH error patterns can be handled by existing `handleSSHError` function
|
|
22
|
+
- **Platform Compatibility**: Works across all platforms supported by the SSH suite
|
|
23
|
+
|
|
24
|
+
### Alternatives Considered
|
|
25
|
+
|
|
26
|
+
1. **Direct SCP command**: `scp -i {privateKey} [flags] {source} {user}@{host}:{dest}`
|
|
27
|
+
- **Rejected**: While simpler, inconsistent with cloud login's SSH-first approach
|
|
28
|
+
- **Concern**: May have different error handling requirements
|
|
29
|
+
|
|
30
|
+
2. **rsync over SSH**: `rsync -avz -e "scp -i {privateKey}" {source} {user}@{host}:{dest}`
|
|
31
|
+
- **Rejected**: Adds external dependency (rsync)
|
|
32
|
+
- **Overkill**: Feature doesn't require rsync's advanced sync capabilities
|
|
33
|
+
- **Complexity**: More flags and options to manage
|
|
34
|
+
|
|
35
|
+
### Implementation Details
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
// For files
|
|
39
|
+
await $`scp -i ${privateKeyFile} scp ${localPath} root@${ip}:${remotePath}`;
|
|
40
|
+
|
|
41
|
+
// For directories (-r flag)
|
|
42
|
+
await $`scp -i ${privateKeyFile} scp -r ${localPath} root@${ip}:${remotePath}`;
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## Decision 2: Path Validation Strategy
|
|
46
|
+
|
|
47
|
+
### Decision
|
|
48
|
+
|
|
49
|
+
Use Node.js `fs/promises` API with `stat()` for comprehensive path validation before SCP execution.
|
|
50
|
+
|
|
51
|
+
### Rationale
|
|
52
|
+
|
|
53
|
+
- **Early Failure**: Detect invalid paths before expensive SSH/SCP operations
|
|
54
|
+
- **Type Detection**: `stat()` provides file vs directory information
|
|
55
|
+
- **Permission Checking**: Can detect read permission issues early
|
|
56
|
+
- **Synchronous Path Check**: Validates source exists, preventing ambiguous SCP errors
|
|
57
|
+
|
|
58
|
+
### Alternatives Considered
|
|
59
|
+
|
|
60
|
+
1. **No validation, rely on SCP errors**
|
|
61
|
+
- **Rejected**: Poor user experience with cryptic SCP error messages
|
|
62
|
+
- **Delayed feedback**: Only fails after SSH connection established
|
|
63
|
+
|
|
64
|
+
2. **Simple `access()` check only**
|
|
65
|
+
- **Rejected**: Doesn't provide file vs directory information
|
|
66
|
+
- **Missing context**: Can't auto-detect if `-r` flag is needed
|
|
67
|
+
|
|
68
|
+
### Implementation Details
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
import { stat } from 'fs/promises';
|
|
72
|
+
|
|
73
|
+
async function validateLocalPath(path: string): Promise<{ exists: boolean; isDirectory: boolean }> {
|
|
74
|
+
try {
|
|
75
|
+
const stats = await stat(path);
|
|
76
|
+
return { exists: true, isDirectory: stats.isDirectory() };
|
|
77
|
+
} catch (error) {
|
|
78
|
+
if (error.code === 'ENOENT') {
|
|
79
|
+
return { exists: false, isDirectory: false };
|
|
80
|
+
}
|
|
81
|
+
throw error; // Permission or other errors
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Decision 3: Recursive Flag Handling
|
|
87
|
+
|
|
88
|
+
### Decision
|
|
89
|
+
|
|
90
|
+
Require explicit `-r` flag for directory copies, error if missing.
|
|
91
|
+
|
|
92
|
+
### Rationale
|
|
93
|
+
|
|
94
|
+
- **SCP Standard**: Follows standard SCP behavior and conventions
|
|
95
|
+
- **Explicit Intent**: Forces user to be explicit about recursive operations
|
|
96
|
+
- **Error Prevention**: Prevents accidental large directory transfers
|
|
97
|
+
- **User Education**: Clear error message teaches correct flag usage
|
|
98
|
+
|
|
99
|
+
### Alternatives Considered
|
|
100
|
+
|
|
101
|
+
1. **Auto-detect and add `-r` flag**
|
|
102
|
+
- **Rejected**: Too implicit, hides important flag from user
|
|
103
|
+
- **Learning barrier**: Users won't learn correct SCP usage
|
|
104
|
+
|
|
105
|
+
2. **Prompt user when directory detected**
|
|
106
|
+
- **Rejected**: Adds friction to CLI workflow
|
|
107
|
+
- **Automation unfriendly**: Breaks non-interactive script usage
|
|
108
|
+
|
|
109
|
+
### Implementation Details
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
// Validation logic
|
|
113
|
+
if (pathInfo.isDirectory && !options.recursive) {
|
|
114
|
+
console.error(chalk.red('❌ Cannot copy directory without -r flag'));
|
|
115
|
+
console.log(chalk.yellow('Hint: Use -r flag for recursive directory copy'));
|
|
116
|
+
process.exit(1);
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Decision 4: Function Reuse Strategy
|
|
121
|
+
|
|
122
|
+
### Decision
|
|
123
|
+
|
|
124
|
+
Reuse existing cloud.ts helper functions for all shared functionality.
|
|
125
|
+
|
|
126
|
+
### Functions to Reuse
|
|
127
|
+
|
|
128
|
+
1. **validatePrivateKey()**: SSH key validation and permission checking
|
|
129
|
+
2. **promptForService()**: Interactive service selection
|
|
130
|
+
3. **promptForEnvironment()**: Interactive environment selection
|
|
131
|
+
4. **handleSSHError()**: SSH/SCP error handling with user-friendly messages
|
|
132
|
+
|
|
133
|
+
### Rationale
|
|
134
|
+
|
|
135
|
+
- **DRY Principle**: Eliminates code duplication
|
|
136
|
+
- **Consistency**: Same user experience across cloud commands
|
|
137
|
+
- **Maintainability**: Bug fixes benefit all cloud commands
|
|
138
|
+
- **Testing**: Shared functions already tested through cloud login
|
|
139
|
+
|
|
140
|
+
### New Functions Required
|
|
141
|
+
|
|
142
|
+
1. **validateLocalPath()**: Path existence and type checking (SCP-specific)
|
|
143
|
+
2. **cloudScp()**: Main SCP command execution (new subcommand)
|
|
144
|
+
|
|
145
|
+
### Implementation Pattern
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
export async function cloudScp(
|
|
149
|
+
localPath: string,
|
|
150
|
+
remotePath: string,
|
|
151
|
+
options: { env?: Environment; service?: string; recursive?: boolean }
|
|
152
|
+
): Promise<void> {
|
|
153
|
+
// Reuse existing patterns from cloudLogin
|
|
154
|
+
const config = readConfig();
|
|
155
|
+
|
|
156
|
+
// Reuse: Service selection
|
|
157
|
+
const service = options.service || (await promptForService(Object.keys(config.yiren)));
|
|
158
|
+
|
|
159
|
+
// Reuse: Environment selection
|
|
160
|
+
const env = options.env || (await promptForEnvironment(Object.keys(config.yiren[service])));
|
|
161
|
+
|
|
162
|
+
// Reuse: Key validation
|
|
163
|
+
await validatePrivateKey(cloudConfig.privateKeyFile);
|
|
164
|
+
|
|
165
|
+
// New: Path validation
|
|
166
|
+
const pathInfo = await validateLocalPath(localPath);
|
|
167
|
+
|
|
168
|
+
// Reuse: Production confirmation (from cloudLogin pattern)
|
|
169
|
+
if (env === 'prod') {
|
|
170
|
+
// ... confirmation prompt logic
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// New: SCP execution
|
|
174
|
+
await $`scp -i ${cloudConfig.privateKeyFile} scp ${flags} ${localPath} root@${cloudConfig.ip}:${remotePath}`;
|
|
175
|
+
}
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
## Decision 5: Production Safety Confirmation
|
|
179
|
+
|
|
180
|
+
### Decision
|
|
181
|
+
|
|
182
|
+
Implement same production confirmation prompt as `cloud login`.
|
|
183
|
+
|
|
184
|
+
### Rationale
|
|
185
|
+
|
|
186
|
+
- **Consistency**: Matches user expectations from cloud login
|
|
187
|
+
- **Safety**: Prevents accidental production file overwrites
|
|
188
|
+
- **Explicit Consent**: Requires active confirmation for prod operations
|
|
189
|
+
- **Audit Trail**: User explicitly acknowledges production access
|
|
190
|
+
|
|
191
|
+
### Implementation Details
|
|
192
|
+
|
|
193
|
+
```typescript
|
|
194
|
+
if (env === 'prod') {
|
|
195
|
+
const { confirmProduction } = await inquirer.prompt([
|
|
196
|
+
{
|
|
197
|
+
type: 'confirm',
|
|
198
|
+
name: 'confirmProduction',
|
|
199
|
+
message: chalk.red(`⚠️ You are about to copy files to PRODUCTION (${service}). Continue?`),
|
|
200
|
+
default: false,
|
|
201
|
+
},
|
|
202
|
+
]);
|
|
203
|
+
|
|
204
|
+
if (!confirmProduction) {
|
|
205
|
+
console.log(chalk.yellow('⏸️ Production operation cancelled.'));
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Decision 6: Error Handling Strategy
|
|
212
|
+
|
|
213
|
+
### Decision
|
|
214
|
+
|
|
215
|
+
Layer error handling with specific messages for each failure point.
|
|
216
|
+
|
|
217
|
+
### Error Categories
|
|
218
|
+
|
|
219
|
+
1. **Path Errors**: Local file/directory not found, permission denied
|
|
220
|
+
2. **Configuration Errors**: Service/environment not configured
|
|
221
|
+
3. **Validation Errors**: Missing -r flag for directories
|
|
222
|
+
4. **SSH/SCP Errors**: Connection failures, authentication failures
|
|
223
|
+
|
|
224
|
+
### Error Handling Flow
|
|
225
|
+
|
|
226
|
+
```typescript
|
|
227
|
+
try {
|
|
228
|
+
// Layer 1: Path validation
|
|
229
|
+
const pathInfo = await validateLocalPath(localPath);
|
|
230
|
+
if (!pathInfo.exists) {
|
|
231
|
+
console.error(chalk.red(`❌ Local path not found: ${localPath}`));
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Layer 2: Recursive flag validation
|
|
236
|
+
if (pathInfo.isDirectory && !options.recursive) {
|
|
237
|
+
console.error(chalk.red('❌ Cannot copy directory without -r flag'));
|
|
238
|
+
console.log(chalk.yellow('Hint: Use -r flag for recursive directory copy'));
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
// Layer 3: Configuration validation (reuse existing logic)
|
|
243
|
+
// ...
|
|
244
|
+
|
|
245
|
+
// Layer 4: SCP execution
|
|
246
|
+
await $`scp -i ${privateKey} scp ${flags} ${localPath} root@${ip}:${remotePath}`;
|
|
247
|
+
console.log(chalk.green(`✅ Successfully copied to ${service} (${env}): ${remotePath}`));
|
|
248
|
+
} catch (error) {
|
|
249
|
+
// Reuse handleSSHError for SSH/SCP connection errors
|
|
250
|
+
handleSSHError(error);
|
|
251
|
+
process.exit(1);
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Rationale
|
|
256
|
+
|
|
257
|
+
- **Clear Feedback**: Each error type has specific, actionable message
|
|
258
|
+
- **Early Failure**: Validation errors caught before SCP execution
|
|
259
|
+
- **Reuse Existing**: SSH errors handled by existing handleSSHError function
|
|
260
|
+
- **User Experience**: Helpful hints guide users to correct usage
|
|
261
|
+
|
|
262
|
+
## Technology Best Practices
|
|
263
|
+
|
|
264
|
+
### TypeScript Best Practices
|
|
265
|
+
|
|
266
|
+
- **Strict Mode**: All code follows strict TypeScript typing
|
|
267
|
+
- **Interface Reuse**: Use existing `CloudConfig`, `Environment` types
|
|
268
|
+
- **Async/Await**: All file system and shell operations use async/await
|
|
269
|
+
- **Error Types**: Properly type catch blocks and error handling
|
|
270
|
+
|
|
271
|
+
### zx Library Usage
|
|
272
|
+
|
|
273
|
+
- **Template Literals**: Use `$` template literals for all shell commands
|
|
274
|
+
- **Variable Escaping**: zx automatically handles path escaping
|
|
275
|
+
- **Error Propagation**: zx throws on non-zero exit codes by default
|
|
276
|
+
- **Process Handling**: Proper async/await with shell operations
|
|
277
|
+
|
|
278
|
+
### Commander.js Patterns
|
|
279
|
+
|
|
280
|
+
- **Option Definition**: Use `.option()` for flags with proper descriptions
|
|
281
|
+
- **Argument Definition**: Use `.argument()` for positional parameters
|
|
282
|
+
- **Action Handler**: Async action handlers for all commands
|
|
283
|
+
- **Delegation Pattern**: Main file defines interface, delegates to domain modules
|
|
284
|
+
|
|
285
|
+
## Integration Patterns
|
|
286
|
+
|
|
287
|
+
### Configuration Access
|
|
288
|
+
|
|
289
|
+
- Reuse `readConfig()` from util.ts
|
|
290
|
+
- Access `config.yiren` structure (established by cloud login)
|
|
291
|
+
- Validate service and environment existence before use
|
|
292
|
+
|
|
293
|
+
### Interactive Prompts
|
|
294
|
+
|
|
295
|
+
- Reuse `promptForService()` and `promptForEnvironment()`
|
|
296
|
+
- Maintain consistent prompt styling with inquirer
|
|
297
|
+
- Provide helpful validation messages
|
|
298
|
+
|
|
299
|
+
### Command Registration
|
|
300
|
+
|
|
301
|
+
```typescript
|
|
302
|
+
// In hsh.ts - following existing cloud command pattern
|
|
303
|
+
cloudCommand
|
|
304
|
+
.command('scp')
|
|
305
|
+
.description('Copy files to cloud instances')
|
|
306
|
+
.option('-r, --recursive', 'Copy directories recursively')
|
|
307
|
+
.option('--env <environment>', 'Environment: dev, staging, or prod')
|
|
308
|
+
.option('--service <service>', 'Service name')
|
|
309
|
+
.argument('<local-path>', 'Local file or directory path')
|
|
310
|
+
.argument('<remote-path>', 'Remote destination path')
|
|
311
|
+
.action(async (localPath, remotePath, options) => {
|
|
312
|
+
await cloudScp(localPath, remotePath, options);
|
|
313
|
+
});
|
|
314
|
+
```
|
|
315
|
+
|
|
316
|
+
## Open Questions & Resolutions
|
|
317
|
+
|
|
318
|
+
### Q1: Should we support SCP options like -P (port)?
|
|
319
|
+
|
|
320
|
+
**Resolution**: No, not in initial implementation. Current cloud config doesn't include custom SSH ports. Can add later if needed.
|
|
321
|
+
|
|
322
|
+
### Q2: Should we validate remote path format?
|
|
323
|
+
|
|
324
|
+
**Resolution**: No, let SCP/SSH handle remote path validation. Remote filesystem structure varies, hard to validate without SSH connection.
|
|
325
|
+
|
|
326
|
+
### Q3: Should we support bidirectional SCP (download from remote)?
|
|
327
|
+
|
|
328
|
+
**Resolution**: No, out of scope for this feature. Current requirement is upload only. Can be separate command later (e.g., `hsh cloud download`).
|
|
329
|
+
|
|
330
|
+
### Q4: Should we show progress for large file transfers?
|
|
331
|
+
|
|
332
|
+
**Resolution**: Not in initial version. SCP provides basic progress output by default. Enhanced progress indication can be added in future iteration if needed.
|
|
333
|
+
|
|
334
|
+
## Summary
|
|
335
|
+
|
|
336
|
+
This research establishes a clear implementation path for the `hsh cloud scp` command:
|
|
337
|
+
|
|
338
|
+
1. **SCP via SSH wrapper** for consistency with cloud login
|
|
339
|
+
2. **Node.js fs/promises** for path validation and type detection
|
|
340
|
+
3. **Explicit -r flag** requirement following SCP standards
|
|
341
|
+
4. **Maximum function reuse** from existing cloud.ts helpers
|
|
342
|
+
5. **Production safety** with confirmation prompts
|
|
343
|
+
6. **Layered error handling** with specific, actionable messages
|
|
344
|
+
|
|
345
|
+
All decisions align with the project's constitution (TypeScript-first, zx for shell, inquirer for prompts, modular architecture) and reuse existing patterns from the cloud login implementation.
|
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# Feature Specification: Cloud SCP Command
|
|
2
|
+
|
|
3
|
+
**Feature ID**: 001-cloud-scp-command
|
|
4
|
+
**Created**: 2025-10-11
|
|
5
|
+
**Type**: CLI Enhancement
|
|
6
|
+
**Depends On**: 001-cloud-login-feature (cloud configuration structure)
|
|
7
|
+
|
|
8
|
+
## Overview
|
|
9
|
+
|
|
10
|
+
Add a new `hsh cloud scp` command that enables users to securely copy files and directories to cloud instances using SCP. The command extends the existing cloud infrastructure management functionality by leveraging the same environment and service configuration used by `hsh cloud login`.
|
|
11
|
+
|
|
12
|
+
## Functional Requirements
|
|
13
|
+
|
|
14
|
+
### FR-1: Cloud SCP Command Structure
|
|
15
|
+
|
|
16
|
+
- **Main Command**: `hsh cloud` - Cloud infrastructure management (existing)
|
|
17
|
+
- **New Subcommand**: `hsh cloud scp [options] <local-path> <remote-path>`
|
|
18
|
+
- **Options**:
|
|
19
|
+
- `-r, --recursive`: Copy directories recursively (required for folders)
|
|
20
|
+
- `--env <environment>`: Environment selection (dev/staging/prod)
|
|
21
|
+
- `--service <service-name>`: Service name (todo-mini, wuhan-mall, etc.)
|
|
22
|
+
- **Parameters**:
|
|
23
|
+
- `<local-path>`: Local file or directory path to copy
|
|
24
|
+
- `<remote-path>`: Remote destination path on the target server
|
|
25
|
+
- **Behavior**: Execute SCP command to copy local files/directories to remote server
|
|
26
|
+
|
|
27
|
+
### FR-2: Interactive Prompts
|
|
28
|
+
|
|
29
|
+
When `--env` or `--service` options are not provided, the command should:
|
|
30
|
+
|
|
31
|
+
- **Service Selection**: Prompt user to select from available services in configuration
|
|
32
|
+
- **Environment Selection**: Prompt user to select from available environments for the chosen service
|
|
33
|
+
- **Reuse Existing Patterns**: Use the same prompt functions from cloud login (`promptForService`, `promptForEnvironment`)
|
|
34
|
+
|
|
35
|
+
### FR-3: Configuration Reuse
|
|
36
|
+
|
|
37
|
+
- **Configuration File**: `~/.ai/config.json` (same as cloud login)
|
|
38
|
+
- **Configuration Structure**: Uses existing `yiren` section from cloud login feature
|
|
39
|
+
```json
|
|
40
|
+
{
|
|
41
|
+
"yiren": {
|
|
42
|
+
"[service-name]": {
|
|
43
|
+
"dev": {
|
|
44
|
+
"ip": "IP",
|
|
45
|
+
"privateKeyFile": "path/to/private-key-file"
|
|
46
|
+
},
|
|
47
|
+
"staging": { ... },
|
|
48
|
+
"prod": { ... }
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### FR-4: SCP Command Execution
|
|
55
|
+
|
|
56
|
+
The command should construct and execute different SCP commands based on the input type:
|
|
57
|
+
|
|
58
|
+
**For Files**:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
scp -i /path/to/privateKey scp local-file-path root@IP:remote-folder-path
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**For Directories** (with `-r` flag):
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
scp -i /path/to/privateKey scp -r local-folder-path root@IP:remote-folder-path
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
**Command Resolution**:
|
|
71
|
+
|
|
72
|
+
- Private key: `config.yiren[service][env].privateKeyFile`
|
|
73
|
+
- IP address: `config.yiren[service][env].ip`
|
|
74
|
+
- User: Always `root` (consistent with cloud login)
|
|
75
|
+
|
|
76
|
+
### FR-5: Path Validation
|
|
77
|
+
|
|
78
|
+
- **Local Path**: Validate that local path exists before attempting copy
|
|
79
|
+
- **Directory Detection**: Automatically detect if local path is a directory
|
|
80
|
+
- **Recursive Flag**: Require `-r` flag for directory copies
|
|
81
|
+
- **Error Messages**: Clear feedback for missing paths or incorrect flag usage
|
|
82
|
+
|
|
83
|
+
## Technical Requirements
|
|
84
|
+
|
|
85
|
+
### TR-1: Command Integration
|
|
86
|
+
|
|
87
|
+
- Add `scp` subcommand to existing `cloud` command group in `hsh.ts`
|
|
88
|
+
- Implement `cloudScp` function in `src/commands/cloud.ts`
|
|
89
|
+
- Follow Commander.js patterns for option and argument parsing
|
|
90
|
+
- Reuse existing cloud helper functions for configuration and validation
|
|
91
|
+
|
|
92
|
+
### TR-2: File System Operations
|
|
93
|
+
|
|
94
|
+
- Use Node.js `fs/promises` API for path validation
|
|
95
|
+
- Detect file vs directory using `stat` or `lstat`
|
|
96
|
+
- Validate local path exists before SCP execution
|
|
97
|
+
- Provide clear error messages for invalid paths
|
|
98
|
+
|
|
99
|
+
### TR-3: SCP Execution
|
|
100
|
+
|
|
101
|
+
- Use zx library for shell command execution (following constitution)
|
|
102
|
+
- Construct SCP command with proper flag handling (`-r` for directories)
|
|
103
|
+
- Include SSH options for key authentication and connection settings
|
|
104
|
+
- Handle SCP-specific errors and exit codes
|
|
105
|
+
|
|
106
|
+
### TR-4: Error Handling
|
|
107
|
+
|
|
108
|
+
- **Path Errors**: Local path not found, permission issues
|
|
109
|
+
- **Configuration Errors**: Missing service/environment configuration
|
|
110
|
+
- **SCP Errors**: Connection failures, permission denied, file transfer issues
|
|
111
|
+
- **Flag Errors**: Missing `-r` flag for directory copy
|
|
112
|
+
- Reuse `handleSSHError` function for connection-related errors
|
|
113
|
+
|
|
114
|
+
### TR-5: Production Safety
|
|
115
|
+
|
|
116
|
+
- Implement same production confirmation prompt as cloud login
|
|
117
|
+
- Warn users before copying to production environments
|
|
118
|
+
- Require explicit confirmation for production operations
|
|
119
|
+
|
|
120
|
+
## User Stories
|
|
121
|
+
|
|
122
|
+
### US-1: Quick File Deploy
|
|
123
|
+
|
|
124
|
+
**As a** developer
|
|
125
|
+
**I want to** quickly copy a local file to a remote server
|
|
126
|
+
**So that** I can deploy configuration changes without manual SCP commands
|
|
127
|
+
|
|
128
|
+
**Acceptance Criteria**:
|
|
129
|
+
|
|
130
|
+
- Command accepts local file path and remote destination
|
|
131
|
+
- Automatically detects it's a file and uses appropriate SCP command
|
|
132
|
+
- Prompts for service and environment if not provided
|
|
133
|
+
- Successfully copies file to remote server
|
|
134
|
+
|
|
135
|
+
**Example**:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
hsh cloud scp ./config.json /etc/myapp/config.json
|
|
139
|
+
# Prompts for service and environment, then copies file
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
### US-2: Directory Upload
|
|
143
|
+
|
|
144
|
+
**As a** developer
|
|
145
|
+
**I want to** upload an entire directory to a remote server
|
|
146
|
+
**So that** I can deploy multiple files in one command
|
|
147
|
+
|
|
148
|
+
**Acceptance Criteria**:
|
|
149
|
+
|
|
150
|
+
- Command requires `-r` flag for directory copy
|
|
151
|
+
- Recursively copies entire directory structure
|
|
152
|
+
- Provides clear error if `-r` flag is missing for directories
|
|
153
|
+
|
|
154
|
+
**Example**:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
hsh cloud scp -r ./dist /var/www/html --env prod --service wuhan-mall
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
### US-3: Interactive Service Selection
|
|
161
|
+
|
|
162
|
+
**As a** developer managing multiple services
|
|
163
|
+
**I want to** be prompted for service and environment if not specified
|
|
164
|
+
**So that** I can quickly select without remembering exact names
|
|
165
|
+
|
|
166
|
+
**Acceptance Criteria**:
|
|
167
|
+
|
|
168
|
+
- Displays available services when `--service` is omitted
|
|
169
|
+
- Displays available environments when `--env` is omitted
|
|
170
|
+
- Uses same interactive prompts as cloud login command
|
|
171
|
+
|
|
172
|
+
**Example**:
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
hsh cloud scp ./app.js /opt/app/
|
|
176
|
+
# Interactive prompts guide service and environment selection
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Usage Examples
|
|
180
|
+
|
|
181
|
+
### Basic File Copy
|
|
182
|
+
|
|
183
|
+
```bash
|
|
184
|
+
hsh cloud scp ./config.json /etc/app/config.json --env dev --service todo-mini
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Directory Copy with Recursive Flag
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
hsh cloud scp -r ./build /var/www/html --env staging --service wuhan-mall
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Interactive Mode (No Flags)
|
|
194
|
+
|
|
195
|
+
```bash
|
|
196
|
+
hsh cloud scp ./deploy.sh /root/scripts/
|
|
197
|
+
# Prompts: Select service → Select environment → Executes SCP
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
### Production Copy with Confirmation
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
hsh cloud scp -r ./dist /var/www/html --env prod --service todo-mini
|
|
204
|
+
# Shows production warning → Requires confirmation → Executes SCP
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
## Dependencies
|
|
208
|
+
|
|
209
|
+
- **Existing**: commander, zx, chalk, inquirer, fs/promises (already in project)
|
|
210
|
+
- **New**: None required
|
|
211
|
+
- **External**: SCP command (system dependency, part of SSH suite)
|
|
212
|
+
- **Internal**: Reuses cloud.ts helper functions and configuration structure
|
|
213
|
+
|
|
214
|
+
## Success Criteria
|
|
215
|
+
|
|
216
|
+
1. Command successfully copies files to specified environment and service
|
|
217
|
+
2. Automatic detection of file vs directory with appropriate flag validation
|
|
218
|
+
3. Interactive prompts work consistently with cloud login command
|
|
219
|
+
4. Production confirmation prevents accidental deployments
|
|
220
|
+
5. Clear error messages for all failure scenarios
|
|
221
|
+
6. Follows project's TypeScript and CLI design principles
|
|
222
|
+
7. Code reuses existing cloud infrastructure patterns
|
|
223
|
+
|
|
224
|
+
## Non-Functional Requirements
|
|
225
|
+
|
|
226
|
+
- **Security**: SSH keys properly managed, not exposed in logs or error messages
|
|
227
|
+
- **Performance**: Command executes within 2 seconds (excluding actual file transfer time)
|
|
228
|
+
- **Usability**: Clear error messages, helpful validation, intuitive flag usage
|
|
229
|
+
- **Maintainability**: Code follows existing patterns, reuses helper functions, minimal duplication
|
|
230
|
+
- **Compatibility**: Works with existing cloud configuration without modifications
|
|
231
|
+
|
|
232
|
+
## Design Decisions
|
|
233
|
+
|
|
234
|
+
### Reuse Over Duplication
|
|
235
|
+
|
|
236
|
+
- Reuse `validatePrivateKey`, `promptForService`, `promptForEnvironment` from cloud login
|
|
237
|
+
- Reuse `handleSSHError` for consistent error handling
|
|
238
|
+
- Reuse configuration reading and validation patterns
|
|
239
|
+
|
|
240
|
+
### SCP via SSH Wrapper
|
|
241
|
+
|
|
242
|
+
The command pattern `scp -i {key} scp ...` is used instead of direct `scp -i {key} ...` for consistency with cloud login's SSH approach and to ensure proper key authentication flow.
|
|
243
|
+
|
|
244
|
+
### Flag Consistency
|
|
245
|
+
|
|
246
|
+
- `-r` flag follows standard SCP convention for recursive copy
|
|
247
|
+
- `--env` and `--service` flags match cloud login for consistency
|
|
248
|
+
- Position of local and remote paths follows standard SCP argument order
|