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,402 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API Contract: Cloud SCP Command
|
|
3
|
+
*
|
|
4
|
+
* This file defines the public API contract for the hsh cloud scp command.
|
|
5
|
+
* It serves as the interface specification for the command implementation.
|
|
6
|
+
*
|
|
7
|
+
* Feature: 001-cloud-scp-command
|
|
8
|
+
* Date: 2025-10-11
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { Environment, CloudConfig } from '../../../src/types/index.js';
|
|
12
|
+
|
|
13
|
+
// ============================================================================
|
|
14
|
+
// Command-Line Interface Contract
|
|
15
|
+
// ============================================================================
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Command Signature:
|
|
19
|
+
* hsh cloud scp [options] <local-path> <remote-path>
|
|
20
|
+
*
|
|
21
|
+
* Options:
|
|
22
|
+
* -r, --recursive Copy directories recursively
|
|
23
|
+
* --env <environment> Environment: dev, staging, or prod
|
|
24
|
+
* --service <service> Service name (e.g., todo-mini, wuhan-mall)
|
|
25
|
+
*
|
|
26
|
+
* Arguments:
|
|
27
|
+
* <local-path> Local file or directory path to copy
|
|
28
|
+
* <remote-path> Remote destination path on target server
|
|
29
|
+
*
|
|
30
|
+
* Examples:
|
|
31
|
+
* hsh cloud scp ./config.json /etc/app/config.json --env dev --service my-app
|
|
32
|
+
* hsh cloud scp -r ./dist /var/www/html --env staging --service my-app
|
|
33
|
+
* hsh cloud scp ./deploy.sh /root/scripts/
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
// ============================================================================
|
|
37
|
+
// Type Definitions
|
|
38
|
+
// ============================================================================
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* SCP command options parsed from CLI flags
|
|
42
|
+
*/
|
|
43
|
+
export interface ScpOptions {
|
|
44
|
+
/**
|
|
45
|
+
* Target environment (dev, staging, or prod)
|
|
46
|
+
* If undefined, user will be prompted to select
|
|
47
|
+
*/
|
|
48
|
+
env?: Environment;
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Target service name
|
|
52
|
+
* If undefined, user will be prompted to select from available services
|
|
53
|
+
*/
|
|
54
|
+
service?: string;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* Whether to copy directories recursively
|
|
58
|
+
* Required true for directory copies, ignored for files
|
|
59
|
+
*/
|
|
60
|
+
recursive?: boolean;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Result of local path validation
|
|
65
|
+
*/
|
|
66
|
+
export interface PathValidationResult {
|
|
67
|
+
/** Whether the path exists on the local filesystem */
|
|
68
|
+
exists: boolean;
|
|
69
|
+
|
|
70
|
+
/** Whether the path is a directory */
|
|
71
|
+
isDirectory: boolean;
|
|
72
|
+
|
|
73
|
+
/** Whether the path is a regular file */
|
|
74
|
+
isFile: boolean;
|
|
75
|
+
|
|
76
|
+
/** The validated path (may be resolved to absolute) */
|
|
77
|
+
path: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Complete execution context for SCP operation
|
|
82
|
+
*/
|
|
83
|
+
export interface ScpExecutionContext {
|
|
84
|
+
/** Selected service name */
|
|
85
|
+
service: string;
|
|
86
|
+
|
|
87
|
+
/** Selected environment */
|
|
88
|
+
environment: Environment;
|
|
89
|
+
|
|
90
|
+
/** Cloud configuration (IP and private key) */
|
|
91
|
+
cloudConfig: CloudConfig;
|
|
92
|
+
|
|
93
|
+
/** Validated local source path */
|
|
94
|
+
localPath: string;
|
|
95
|
+
|
|
96
|
+
/** Remote destination path */
|
|
97
|
+
remotePath: string;
|
|
98
|
+
|
|
99
|
+
/** Whether to use recursive flag */
|
|
100
|
+
isRecursive: boolean;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* SCP operation metadata for logging/tracking
|
|
105
|
+
*/
|
|
106
|
+
export interface ScpOperation {
|
|
107
|
+
/** Local source path */
|
|
108
|
+
localPath: string;
|
|
109
|
+
|
|
110
|
+
/** Remote destination path */
|
|
111
|
+
remotePath: string;
|
|
112
|
+
|
|
113
|
+
/** Target service */
|
|
114
|
+
service: string;
|
|
115
|
+
|
|
116
|
+
/** Target environment */
|
|
117
|
+
environment: Environment;
|
|
118
|
+
|
|
119
|
+
/** Whether operation was recursive */
|
|
120
|
+
isDirectory: boolean;
|
|
121
|
+
|
|
122
|
+
/** Operation timestamp */
|
|
123
|
+
timestamp: Date;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ============================================================================
|
|
127
|
+
// Main API Function
|
|
128
|
+
// ============================================================================
|
|
129
|
+
|
|
130
|
+
/**
|
|
131
|
+
* Execute SCP file transfer to cloud instance
|
|
132
|
+
*
|
|
133
|
+
* @param localPath - Local file or directory path to copy
|
|
134
|
+
* @param remotePath - Remote destination path on target server
|
|
135
|
+
* @param options - Command options (environment, service, recursive flag)
|
|
136
|
+
*
|
|
137
|
+
* @throws {Error} If local path doesn't exist
|
|
138
|
+
* @throws {Error} If directory copy attempted without -r flag
|
|
139
|
+
* @throws {Error} If service or environment not found in configuration
|
|
140
|
+
* @throws {Error} If private key validation fails
|
|
141
|
+
* @throws {Error} If SSH/SCP connection fails
|
|
142
|
+
*
|
|
143
|
+
* @returns Promise that resolves when file transfer completes successfully
|
|
144
|
+
*
|
|
145
|
+
* @example
|
|
146
|
+
* ```typescript
|
|
147
|
+
* // Copy file with explicit options
|
|
148
|
+
* await cloudScp('./config.json', '/etc/app/', {
|
|
149
|
+
* env: 'dev',
|
|
150
|
+
* service: 'my-app',
|
|
151
|
+
* recursive: false
|
|
152
|
+
* });
|
|
153
|
+
*
|
|
154
|
+
* // Copy directory with interactive prompts
|
|
155
|
+
* await cloudScp('./dist', '/var/www/html', {
|
|
156
|
+
* recursive: true
|
|
157
|
+
* // env and service will be prompted
|
|
158
|
+
* });
|
|
159
|
+
* ```
|
|
160
|
+
*/
|
|
161
|
+
export async function cloudScp(
|
|
162
|
+
localPath: string,
|
|
163
|
+
remotePath: string,
|
|
164
|
+
options: ScpOptions
|
|
165
|
+
): Promise<void>;
|
|
166
|
+
|
|
167
|
+
// ============================================================================
|
|
168
|
+
// Helper Functions (Exported for Testing/Reuse)
|
|
169
|
+
// ============================================================================
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Validate that local path exists and determine its type
|
|
173
|
+
*
|
|
174
|
+
* @param path - Local file or directory path to validate
|
|
175
|
+
* @returns Promise resolving to validation result
|
|
176
|
+
*
|
|
177
|
+
* @throws {Error} If permission denied or other filesystem error
|
|
178
|
+
*
|
|
179
|
+
* @example
|
|
180
|
+
* ```typescript
|
|
181
|
+
* const result = await validateLocalPath('./dist');
|
|
182
|
+
* if (!result.exists) {
|
|
183
|
+
* console.error('Path not found');
|
|
184
|
+
* } else if (result.isDirectory && !options.recursive) {
|
|
185
|
+
* console.error('Use -r flag for directories');
|
|
186
|
+
* }
|
|
187
|
+
* ```
|
|
188
|
+
*/
|
|
189
|
+
export async function validateLocalPath(path: string): Promise<PathValidationResult>;
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Build complete execution context from user input and configuration
|
|
193
|
+
*
|
|
194
|
+
* @param localPath - Validated local source path
|
|
195
|
+
* @param remotePath - Remote destination path
|
|
196
|
+
* @param options - Command options
|
|
197
|
+
* @param config - Application configuration
|
|
198
|
+
* @param pathInfo - Path validation result
|
|
199
|
+
*
|
|
200
|
+
* @returns Promise resolving to execution context
|
|
201
|
+
*
|
|
202
|
+
* @throws {Error} If service or environment not found in configuration
|
|
203
|
+
*/
|
|
204
|
+
export async function buildExecutionContext(
|
|
205
|
+
localPath: string,
|
|
206
|
+
remotePath: string,
|
|
207
|
+
options: ScpOptions,
|
|
208
|
+
config: Config,
|
|
209
|
+
pathInfo: PathValidationResult
|
|
210
|
+
): Promise<ScpExecutionContext>;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Construct and execute SCP command via SSH wrapper
|
|
214
|
+
*
|
|
215
|
+
* @param context - Complete execution context
|
|
216
|
+
*
|
|
217
|
+
* @returns Promise that resolves when SCP command completes
|
|
218
|
+
*
|
|
219
|
+
* @throws {Error} If SCP/SSH command fails
|
|
220
|
+
*
|
|
221
|
+
* @example
|
|
222
|
+
* ```typescript
|
|
223
|
+
* const context: ScpExecutionContext = {
|
|
224
|
+
* service: 'my-app',
|
|
225
|
+
* environment: 'dev',
|
|
226
|
+
* cloudConfig: { ip: '192.168.1.10', privateKeyFile: '/path/to/key.pem' },
|
|
227
|
+
* localPath: './dist',
|
|
228
|
+
* remotePath: '/var/www/html',
|
|
229
|
+
* isRecursive: true
|
|
230
|
+
* };
|
|
231
|
+
*
|
|
232
|
+
* await executeScpCommand(context);
|
|
233
|
+
* // Output: ✅ Successfully copied to my-app (dev): /var/www/html
|
|
234
|
+
* ```
|
|
235
|
+
*/
|
|
236
|
+
export async function executeScpCommand(context: ScpExecutionContext): Promise<void>;
|
|
237
|
+
|
|
238
|
+
// ============================================================================
|
|
239
|
+
// Validation Rules
|
|
240
|
+
// ============================================================================
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Validation rules applied during command execution:
|
|
244
|
+
*
|
|
245
|
+
* 1. Local Path Validation:
|
|
246
|
+
* - Path must exist on local filesystem
|
|
247
|
+
* - Path must be readable (file permission check)
|
|
248
|
+
* - If directory: -r flag must be provided
|
|
249
|
+
*
|
|
250
|
+
* 2. Configuration Validation:
|
|
251
|
+
* - Service must exist in config.yiren
|
|
252
|
+
* - Environment must exist for selected service
|
|
253
|
+
* - CloudConfig must have valid ip and privateKeyFile
|
|
254
|
+
*
|
|
255
|
+
* 3. Private Key Validation:
|
|
256
|
+
* - Private key file must exist
|
|
257
|
+
* - Private key file should have 600 permissions (warning if not)
|
|
258
|
+
*
|
|
259
|
+
* 4. Production Safety:
|
|
260
|
+
* - Production environment requires explicit confirmation
|
|
261
|
+
* - Confirmation must be affirmative (default: false)
|
|
262
|
+
*
|
|
263
|
+
* 5. Remote Path Validation:
|
|
264
|
+
* - Remote path must be non-empty string
|
|
265
|
+
* - Format validation delegated to SSH/SCP
|
|
266
|
+
*/
|
|
267
|
+
|
|
268
|
+
// ============================================================================
|
|
269
|
+
// Error Handling Contract
|
|
270
|
+
// ============================================================================
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Error Categories:
|
|
274
|
+
*
|
|
275
|
+
* 1. Path Errors:
|
|
276
|
+
* - "❌ Local path not found: {path}"
|
|
277
|
+
* - "❌ Permission denied: {path}"
|
|
278
|
+
* - "❌ Cannot copy directory without -r flag"
|
|
279
|
+
*
|
|
280
|
+
* 2. Configuration Errors:
|
|
281
|
+
* - "❌ No cloud services configured in yiren section"
|
|
282
|
+
* - "❌ Service '{service}' not found in configuration"
|
|
283
|
+
* - "❌ Environment '{env}' not configured for service '{service}'"
|
|
284
|
+
*
|
|
285
|
+
* 3. SSH/SCP Errors (handled by handleSSHError):
|
|
286
|
+
* - "❌ Connection timeout - check network connectivity and IP address"
|
|
287
|
+
* - "❌ Authentication failed - check private key file permissions and path"
|
|
288
|
+
* - "❌ Host unreachable - verify IP address and network access"
|
|
289
|
+
* - "❌ Connection refused - check if SSH service is running on target host"
|
|
290
|
+
*
|
|
291
|
+
* 4. User Cancellation:
|
|
292
|
+
* - "⏸️ Production operation cancelled."
|
|
293
|
+
*/
|
|
294
|
+
|
|
295
|
+
// ============================================================================
|
|
296
|
+
// Success Messages
|
|
297
|
+
// ============================================================================
|
|
298
|
+
|
|
299
|
+
/**
|
|
300
|
+
* Success message format:
|
|
301
|
+
* "✅ Successfully copied to {service} ({environment}): {remotePath}"
|
|
302
|
+
*
|
|
303
|
+
* Example:
|
|
304
|
+
* "✅ Successfully copied to my-app (dev): /var/www/html"
|
|
305
|
+
*/
|
|
306
|
+
|
|
307
|
+
// ============================================================================
|
|
308
|
+
// Configuration Contract
|
|
309
|
+
// ============================================================================
|
|
310
|
+
|
|
311
|
+
/**
|
|
312
|
+
* Configuration structure (reuses existing cloud login config):
|
|
313
|
+
*
|
|
314
|
+
* ~/.ai/config.json:
|
|
315
|
+
* {
|
|
316
|
+
* "yiren": {
|
|
317
|
+
* "[service-name]": {
|
|
318
|
+
* "dev": {
|
|
319
|
+
* "ip": "192.168.1.10",
|
|
320
|
+
* "privateKeyFile": "/path/to/dev-key.pem"
|
|
321
|
+
* },
|
|
322
|
+
* "staging": {
|
|
323
|
+
* "ip": "192.168.1.20",
|
|
324
|
+
* "privateKeyFile": "/path/to/staging-key.pem"
|
|
325
|
+
* },
|
|
326
|
+
* "prod": {
|
|
327
|
+
* "ip": "192.168.1.30",
|
|
328
|
+
* "privateKeyFile": "/path/to/prod-key.pem"
|
|
329
|
+
* }
|
|
330
|
+
* }
|
|
331
|
+
* }
|
|
332
|
+
* }
|
|
333
|
+
*
|
|
334
|
+
* No schema changes required - 100% compatible with cloud login configuration
|
|
335
|
+
*/
|
|
336
|
+
|
|
337
|
+
// ============================================================================
|
|
338
|
+
// Integration Points
|
|
339
|
+
// ============================================================================
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Functions reused from existing cloud.ts module:
|
|
343
|
+
*
|
|
344
|
+
* - validatePrivateKey(privateKeyFile: string): Promise<void>
|
|
345
|
+
* → Validates SSH private key existence and permissions
|
|
346
|
+
*
|
|
347
|
+
* - handleSSHError(error: any): void
|
|
348
|
+
* → Handles SSH/SCP connection errors with user-friendly messages
|
|
349
|
+
*
|
|
350
|
+
* - promptForService(availableServices: string[]): Promise<string>
|
|
351
|
+
* → Interactive service selection prompt
|
|
352
|
+
*
|
|
353
|
+
* - promptForEnvironment(availableEnvironments: Environment[]): Promise<Environment>
|
|
354
|
+
* → Interactive environment selection prompt
|
|
355
|
+
*
|
|
356
|
+
* - readConfig(): Config
|
|
357
|
+
* → Reads configuration from ~/.ai/config.json (from util.ts)
|
|
358
|
+
*/
|
|
359
|
+
|
|
360
|
+
// ============================================================================
|
|
361
|
+
// Testing Contract
|
|
362
|
+
// ============================================================================
|
|
363
|
+
|
|
364
|
+
/**
|
|
365
|
+
* Testable scenarios:
|
|
366
|
+
*
|
|
367
|
+
* 1. Happy Path - File Copy:
|
|
368
|
+
* Input: Valid file path, valid remote path, valid service/env
|
|
369
|
+
* Expected: SCP command executed successfully
|
|
370
|
+
*
|
|
371
|
+
* 2. Happy Path - Directory Copy:
|
|
372
|
+
* Input: Valid directory path with -r flag, valid remote path, valid service/env
|
|
373
|
+
* Expected: SCP command with -r flag executed successfully
|
|
374
|
+
*
|
|
375
|
+
* 3. Error - Missing File:
|
|
376
|
+
* Input: Non-existent file path
|
|
377
|
+
* Expected: Error message "❌ Local path not found: {path}"
|
|
378
|
+
*
|
|
379
|
+
* 4. Error - Directory without -r:
|
|
380
|
+
* Input: Directory path without -r flag
|
|
381
|
+
* Expected: Error message "❌ Cannot copy directory without -r flag"
|
|
382
|
+
*
|
|
383
|
+
* 5. Error - Service Not Found:
|
|
384
|
+
* Input: Invalid service name
|
|
385
|
+
* Expected: Error message "❌ Service '{service}' not found in configuration"
|
|
386
|
+
*
|
|
387
|
+
* 6. Interactive - Service Selection:
|
|
388
|
+
* Input: No --service flag provided
|
|
389
|
+
* Expected: Prompt displays available services, accepts selection
|
|
390
|
+
*
|
|
391
|
+
* 7. Interactive - Environment Selection:
|
|
392
|
+
* Input: No --env flag provided
|
|
393
|
+
* Expected: Prompt displays available environments, accepts selection
|
|
394
|
+
*
|
|
395
|
+
* 8. Safety - Production Confirmation:
|
|
396
|
+
* Input: --env prod
|
|
397
|
+
* Expected: Production warning prompt, requires confirmation
|
|
398
|
+
*
|
|
399
|
+
* 9. Safety - Production Cancelled:
|
|
400
|
+
* Input: --env prod, user declines confirmation
|
|
401
|
+
* Expected: Operation cancelled with message "⏸️ Production operation cancelled."
|
|
402
|
+
*/
|