@khoaha/spek-cli 1.0.3 → 1.0.5
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/dist/commands/svg-to-vd/handler.d.ts +14 -0
- package/dist/commands/svg-to-vd/handler.d.ts.map +1 -0
- package/dist/commands/svg-to-vd/handler.js +119 -0
- package/dist/commands/svg-to-vd/handler.js.map +1 -0
- package/dist/config/manager.d.ts +18 -0
- package/dist/config/manager.d.ts.map +1 -0
- package/dist/config/manager.js +53 -0
- package/dist/config/manager.js.map +1 -0
- package/dist/directus/client.d.ts +14 -0
- package/dist/directus/client.d.ts.map +1 -0
- package/dist/directus/client.js +81 -0
- package/dist/directus/client.js.map +1 -0
- package/dist/download/handler.d.ts +6 -0
- package/dist/download/handler.d.ts.map +1 -0
- package/dist/download/handler.js +100 -0
- package/dist/download/handler.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +209 -0
- package/dist/index.js.map +1 -0
- package/dist/prompts/index.d.ts +14 -0
- package/dist/prompts/index.d.ts.map +1 -0
- package/dist/prompts/index.js +69 -0
- package/dist/prompts/index.js.map +1 -0
- package/dist/types/index.d.ts +67 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/file-utils.d.ts +28 -0
- package/dist/utils/file-utils.d.ts.map +1 -0
- package/dist/utils/file-utils.js +61 -0
- package/dist/utils/file-utils.js.map +1 -0
- package/dist/utils/svg-converter.d.ts +44 -0
- package/dist/utils/svg-converter.d.ts.map +1 -0
- package/dist/utils/svg-converter.js +149 -0
- package/dist/utils/svg-converter.js.map +1 -0
- package/package.json +7 -1
- package/docs/ARCHITECTURE.md +0 -286
- package/docs/PUBLISH_QUICK_REFERENCE.md +0 -135
- package/docs/SVG_TO_VECTOR_DRAWABLE.md +0 -186
- package/docs/TESTING.md +0 -429
- package/docs/USAGE_EXAMPLES.md +0 -520
- package/docs/WINDOWS_DEVELOPMENT.md +0 -487
- package/docs/WORKFLOW.md +0 -479
- package/scripts/publish.ps1 +0 -193
- package/scripts/publish.sh +0 -170
- package/src/commands/svg-to-vd/handler.ts +0 -131
- package/src/config/manager.ts +0 -58
- package/src/directus/client.ts +0 -101
- package/src/download/handler.ts +0 -116
- package/src/index.ts +0 -231
- package/src/prompts/index.ts +0 -76
- package/src/types/index.ts +0 -72
- package/src/utils/file-utils.ts +0 -69
- package/src/utils/svg-converter.ts +0 -196
- package/tsconfig.json +0 -20
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SVG to Vector Drawable Conversion Utility
|
|
3
|
+
*
|
|
4
|
+
* Converts SVG content to Android Vector Drawable XML format using vd-tool
|
|
5
|
+
*/
|
|
6
|
+
import { writeFile, unlink, mkdtemp, readFile } from 'fs/promises';
|
|
7
|
+
import { join } from 'path';
|
|
8
|
+
import { tmpdir } from 'os';
|
|
9
|
+
import { vdConvert } from 'vd-tool';
|
|
10
|
+
/**
|
|
11
|
+
* Validates SVG content format
|
|
12
|
+
*
|
|
13
|
+
* @param svgContent - The SVG content to validate
|
|
14
|
+
* @returns Validation result with isValid boolean and errors array
|
|
15
|
+
*/
|
|
16
|
+
export function validateSvgContent(svgContent) {
|
|
17
|
+
const errors = [];
|
|
18
|
+
if (!svgContent || typeof svgContent !== 'string') {
|
|
19
|
+
errors.push('SVG content is required and must be a string');
|
|
20
|
+
}
|
|
21
|
+
else {
|
|
22
|
+
if (svgContent.trim().length === 0) {
|
|
23
|
+
errors.push('SVG content cannot be empty');
|
|
24
|
+
}
|
|
25
|
+
if (!svgContent.includes('<svg')) {
|
|
26
|
+
errors.push('SVG content must contain an opening <svg> tag');
|
|
27
|
+
}
|
|
28
|
+
if (!svgContent.includes('</svg>')) {
|
|
29
|
+
errors.push('SVG content must contain a closing </svg> tag');
|
|
30
|
+
}
|
|
31
|
+
// Check for basic XML structure
|
|
32
|
+
const openTags = (svgContent.match(/<svg[^>]*>/g) || []).length;
|
|
33
|
+
const closeTags = (svgContent.match(/<\/svg>/g) || []).length;
|
|
34
|
+
if (openTags !== closeTags) {
|
|
35
|
+
errors.push('SVG content has mismatched <svg> tags');
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return {
|
|
39
|
+
isValid: errors.length === 0,
|
|
40
|
+
errors
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Applies customizations to the Vector Drawable XML
|
|
45
|
+
*
|
|
46
|
+
* @param vectorDrawableXml - The Vector Drawable XML content
|
|
47
|
+
* @param options - Customization options
|
|
48
|
+
* @returns Customized Vector Drawable XML
|
|
49
|
+
*/
|
|
50
|
+
function applyCustomizations(vectorDrawableXml, options) {
|
|
51
|
+
let customizedXml = vectorDrawableXml;
|
|
52
|
+
// Apply tint if specified
|
|
53
|
+
if (options.tint) {
|
|
54
|
+
customizedXml = customizedXml.replace(/<vector([^>]*)>/, `<vector$1 android:tint="${options.tint}">`);
|
|
55
|
+
}
|
|
56
|
+
return customizedXml;
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Cleans up temporary files and directories
|
|
60
|
+
*
|
|
61
|
+
* @param svgFile - Path to temporary SVG file
|
|
62
|
+
* @param vdFile - Path to temporary Vector Drawable file
|
|
63
|
+
* @param tempDir - Path to temporary directory
|
|
64
|
+
*/
|
|
65
|
+
async function cleanup(svgFile, vdFile, tempDir) {
|
|
66
|
+
try {
|
|
67
|
+
if (svgFile)
|
|
68
|
+
await unlink(svgFile).catch(() => { });
|
|
69
|
+
if (vdFile)
|
|
70
|
+
await unlink(vdFile).catch(() => { });
|
|
71
|
+
if (tempDir) {
|
|
72
|
+
const { rm } = await import('fs/promises');
|
|
73
|
+
await rm(tempDir, { recursive: true, force: true }).catch(() => { });
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// Ignore cleanup errors
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Converts SVG content to Android Vector Drawable XML format
|
|
82
|
+
*
|
|
83
|
+
* @param svgContent - The SVG content to convert
|
|
84
|
+
* @param options - Conversion options
|
|
85
|
+
* @returns Conversion result with vectorDrawable XML and optional warnings
|
|
86
|
+
* @throws Error if conversion fails
|
|
87
|
+
*/
|
|
88
|
+
export async function convertSvgToVectorDrawable(svgContent, options = {}) {
|
|
89
|
+
// Input validation
|
|
90
|
+
if (!svgContent || typeof svgContent !== 'string') {
|
|
91
|
+
throw new Error('SVG content is required and must be a string');
|
|
92
|
+
}
|
|
93
|
+
if (svgContent.trim().length === 0) {
|
|
94
|
+
throw new Error('SVG content cannot be empty');
|
|
95
|
+
}
|
|
96
|
+
// Basic SVG format validation
|
|
97
|
+
if (!svgContent.includes('<svg') || !svgContent.includes('</svg>')) {
|
|
98
|
+
throw new Error('Invalid SVG format: must contain <svg> tags');
|
|
99
|
+
}
|
|
100
|
+
let tempDir = null;
|
|
101
|
+
let tempSvgFile = null;
|
|
102
|
+
let tempVdFile = null;
|
|
103
|
+
try {
|
|
104
|
+
// Create temporary directory
|
|
105
|
+
tempDir = await mkdtemp(join(tmpdir(), 'svg-to-vd-'));
|
|
106
|
+
tempSvgFile = join(tempDir, 'input.svg');
|
|
107
|
+
tempVdFile = join(tempDir, 'input.xml');
|
|
108
|
+
// Write SVG content to temporary file
|
|
109
|
+
await writeFile(tempSvgFile, svgContent, 'utf8');
|
|
110
|
+
// Use vd-tool library for conversion
|
|
111
|
+
try {
|
|
112
|
+
await vdConvert(tempSvgFile, {
|
|
113
|
+
outDir: tempDir
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
catch (conversionError) {
|
|
117
|
+
const errorMessage = conversionError.message || 'Unknown conversion error';
|
|
118
|
+
throw new Error(`SVG to Vector Drawable conversion failed: ${errorMessage}`);
|
|
119
|
+
}
|
|
120
|
+
// Read the generated Vector Drawable XML
|
|
121
|
+
let vectorDrawableContent;
|
|
122
|
+
try {
|
|
123
|
+
vectorDrawableContent = await readFile(tempVdFile, 'utf8');
|
|
124
|
+
}
|
|
125
|
+
catch (readError) {
|
|
126
|
+
throw new Error('Failed to read converted Vector Drawable file');
|
|
127
|
+
}
|
|
128
|
+
// Apply customizations if provided
|
|
129
|
+
if (options.tint) {
|
|
130
|
+
vectorDrawableContent = applyCustomizations(vectorDrawableContent, options);
|
|
131
|
+
}
|
|
132
|
+
// Clean up temporary files
|
|
133
|
+
await cleanup(tempSvgFile, tempVdFile, tempDir);
|
|
134
|
+
return {
|
|
135
|
+
vectorDrawable: vectorDrawableContent,
|
|
136
|
+
warnings: []
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
catch (error) {
|
|
140
|
+
// Clean up temporary files in case of error
|
|
141
|
+
if (tempSvgFile || tempVdFile || tempDir) {
|
|
142
|
+
await cleanup(tempSvgFile, tempVdFile, tempDir).catch(() => {
|
|
143
|
+
// Ignore cleanup errors
|
|
144
|
+
});
|
|
145
|
+
}
|
|
146
|
+
throw error;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=svg-converter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"svg-converter.js","sourceRoot":"","sources":["../../src/utils/svg-converter.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@khoaha/spek-cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.5",
|
|
4
4
|
"description": "CLI tool to download and extract Figma design specs from Directus",
|
|
5
5
|
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist",
|
|
8
|
+
"bin",
|
|
9
|
+
"README.md",
|
|
10
|
+
"QUICKSTART.md"
|
|
11
|
+
],
|
|
6
12
|
"bin": {
|
|
7
13
|
"spek-cli": "./bin/cli.js"
|
|
8
14
|
},
|
package/docs/ARCHITECTURE.md
DELETED
|
@@ -1,286 +0,0 @@
|
|
|
1
|
-
# CLI Tool Architecture
|
|
2
|
-
|
|
3
|
-
## Overview
|
|
4
|
-
|
|
5
|
-
`spek-cli` is a standalone CLI tool for downloading and extracting Figma design specs from Directus vault storage. It's built with TypeScript and uses the official Directus SDK for authentication and file downloads.
|
|
6
|
-
|
|
7
|
-
## Architecture Diagram
|
|
8
|
-
|
|
9
|
-
```
|
|
10
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
-
│ User │
|
|
12
|
-
└────────────────────┬────────────────────────────────────────┘
|
|
13
|
-
│
|
|
14
|
-
▼
|
|
15
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
16
|
-
│ CLI Entry Point │
|
|
17
|
-
│ (src/index.ts) │
|
|
18
|
-
│ • Parse arguments (-d, --download, --help, --version) │
|
|
19
|
-
│ • Orchestrate workflow │
|
|
20
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
21
|
-
│
|
|
22
|
-
▼
|
|
23
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
24
|
-
│ Configuration Manager │
|
|
25
|
-
│ (src/config/manager.ts) │
|
|
26
|
-
│ • Check if config exists │
|
|
27
|
-
│ • Load from ~/.spek-cli/config.json │
|
|
28
|
-
│ • Save new configuration │
|
|
29
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
30
|
-
│
|
|
31
|
-
▼
|
|
32
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
33
|
-
│ Prompts Module │
|
|
34
|
-
│ (src/prompts/index.ts) │
|
|
35
|
-
│ • Prompt for Directus URL (first run) │
|
|
36
|
-
│ • Prompt for access token (first run) │
|
|
37
|
-
│ • Prompt for file ID (interactive mode) │
|
|
38
|
-
│ • Prompt for overwrite confirmation │
|
|
39
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
40
|
-
│
|
|
41
|
-
▼
|
|
42
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
43
|
-
│ Directus Client │
|
|
44
|
-
│ (src/directus/client.ts) │
|
|
45
|
-
│ • Create authenticated Directus SDK client │
|
|
46
|
-
│ • Download file using readAssetRaw() │
|
|
47
|
-
│ • Handle authentication and errors │
|
|
48
|
-
└────────────┬────────────────────────────────────────────────┘
|
|
49
|
-
│
|
|
50
|
-
▼
|
|
51
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
52
|
-
│ Download Handler │
|
|
53
|
-
│ (src/download/handler.ts) │
|
|
54
|
-
│ • Download file to temp location │
|
|
55
|
-
│ • Validate ZIP file │
|
|
56
|
-
│ • Check for existing files │
|
|
57
|
-
│ • Extract to current working directory │
|
|
58
|
-
│ • Cleanup temp files │
|
|
59
|
-
└─────────────────────────────────────────────────────────────┘
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
## Module Breakdown
|
|
63
|
-
|
|
64
|
-
### 1. Entry Point (`src/index.ts`)
|
|
65
|
-
|
|
66
|
-
**Responsibilities:**
|
|
67
|
-
- Parse command-line arguments
|
|
68
|
-
- Check/initialize configuration
|
|
69
|
-
- Orchestrate the download workflow
|
|
70
|
-
- Handle errors and display results
|
|
71
|
-
|
|
72
|
-
**Key Functions:**
|
|
73
|
-
- `parseArgs()` - Parse CLI arguments
|
|
74
|
-
- `showHelp()` - Display help message
|
|
75
|
-
- `showVersion()` - Display version
|
|
76
|
-
- `main()` - Main entry point
|
|
77
|
-
|
|
78
|
-
**Flow:**
|
|
79
|
-
```
|
|
80
|
-
1. Parse arguments
|
|
81
|
-
2. Load or initialize config
|
|
82
|
-
3. Get file ID (from args or prompt)
|
|
83
|
-
4. Call download handler
|
|
84
|
-
5. Display result
|
|
85
|
-
```
|
|
86
|
-
|
|
87
|
-
### 2. Configuration Manager (`src/config/manager.ts`)
|
|
88
|
-
|
|
89
|
-
**Responsibilities:**
|
|
90
|
-
- Manage configuration file at `~/.spek-cli/config.json`
|
|
91
|
-
- Load, save, and validate configuration
|
|
92
|
-
- Ensure config directory exists
|
|
93
|
-
|
|
94
|
-
**Key Functions:**
|
|
95
|
-
- `configExists()` - Check if config file exists
|
|
96
|
-
- `loadConfig()` - Load configuration from disk
|
|
97
|
-
- `saveConfig()` - Save configuration to disk
|
|
98
|
-
- `getConfigPath()` - Get config file path
|
|
99
|
-
|
|
100
|
-
**Configuration Structure:**
|
|
101
|
-
```typescript
|
|
102
|
-
interface VaultConfig {
|
|
103
|
-
directusUrl: string; // e.g., https://my.directus.app
|
|
104
|
-
accessToken: string; // Directus access token
|
|
105
|
-
createdAt: string; // ISO timestamp
|
|
106
|
-
}
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### 3. Prompts Module (`src/prompts/index.ts`)
|
|
110
|
-
|
|
111
|
-
**Responsibilities:**
|
|
112
|
-
- Interactive user input collection
|
|
113
|
-
- Validation of user inputs
|
|
114
|
-
- Confirmation dialogs
|
|
115
|
-
|
|
116
|
-
**Key Functions:**
|
|
117
|
-
- `promptForConfig()` - First-run configuration setup
|
|
118
|
-
- `promptForFileId()` - Get file ID in interactive mode
|
|
119
|
-
- `promptOverwrite()` - Confirm overwrite of existing files
|
|
120
|
-
|
|
121
|
-
**Uses:** `prompts` package (v2.4.2) for user-friendly CLI prompts
|
|
122
|
-
|
|
123
|
-
### 4. Directus Client (`src/directus/client.ts`)
|
|
124
|
-
|
|
125
|
-
**Responsibilities:**
|
|
126
|
-
- Create authenticated Directus SDK client
|
|
127
|
-
- Download files from Directus assets
|
|
128
|
-
- Handle authentication and API errors
|
|
129
|
-
|
|
130
|
-
**Key Functions:**
|
|
131
|
-
- `createAuthenticatedClient()` - Initialize Directus client
|
|
132
|
-
- `downloadFile()` - Download file by ID
|
|
133
|
-
|
|
134
|
-
**Error Handling:**
|
|
135
|
-
- 401: Authentication failed
|
|
136
|
-
- 404: File not found
|
|
137
|
-
- Network errors: Connection issues
|
|
138
|
-
|
|
139
|
-
**Implementation Details:**
|
|
140
|
-
- Uses `@directus/sdk` with `authentication()` and `rest()` modules
|
|
141
|
-
- Converts `ReadableStream` to `Buffer` for file processing
|
|
142
|
-
- Sets access token before making requests
|
|
143
|
-
|
|
144
|
-
### 5. Download Handler (`src/download/handler.ts`)
|
|
145
|
-
|
|
146
|
-
**Responsibilities:**
|
|
147
|
-
- Orchestrate download and extraction process
|
|
148
|
-
- Validate ZIP files
|
|
149
|
-
- Check for file conflicts
|
|
150
|
-
- Extract to current working directory
|
|
151
|
-
- Cleanup temporary files
|
|
152
|
-
|
|
153
|
-
**Key Functions:**
|
|
154
|
-
- `checkExistingFiles()` - Check if extraction would overwrite files
|
|
155
|
-
- `handleDownload()` - Main download and extract workflow
|
|
156
|
-
|
|
157
|
-
**Flow:**
|
|
158
|
-
```
|
|
159
|
-
1. Download file from Directus
|
|
160
|
-
2. Save to temp file
|
|
161
|
-
3. Validate ZIP structure
|
|
162
|
-
4. Check for existing files
|
|
163
|
-
5. Prompt for overwrite if needed
|
|
164
|
-
6. Extract to CWD
|
|
165
|
-
7. Cleanup temp files
|
|
166
|
-
8. Return result
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
**Uses:** `adm-zip` for ZIP file operations
|
|
170
|
-
|
|
171
|
-
## Data Flow
|
|
172
|
-
|
|
173
|
-
```
|
|
174
|
-
User Input
|
|
175
|
-
↓
|
|
176
|
-
CLI Arguments / Prompts
|
|
177
|
-
↓
|
|
178
|
-
Configuration (from file or new setup)
|
|
179
|
-
↓
|
|
180
|
-
Directus SDK Client
|
|
181
|
-
↓
|
|
182
|
-
Download File (via Directus API)
|
|
183
|
-
↓
|
|
184
|
-
Temp File Storage
|
|
185
|
-
↓
|
|
186
|
-
ZIP Validation
|
|
187
|
-
↓
|
|
188
|
-
Overwrite Check
|
|
189
|
-
↓
|
|
190
|
-
Extract to CWD
|
|
191
|
-
↓
|
|
192
|
-
Cleanup & Result
|
|
193
|
-
```
|
|
194
|
-
|
|
195
|
-
## Error Handling Strategy
|
|
196
|
-
|
|
197
|
-
### Configuration Errors
|
|
198
|
-
- Missing config → Auto-trigger setup wizard
|
|
199
|
-
- Invalid config → Show error, suggest re-setup
|
|
200
|
-
|
|
201
|
-
### Authentication Errors
|
|
202
|
-
- 401 Unauthorized → Check access token message
|
|
203
|
-
- Invalid URL → Validation during setup
|
|
204
|
-
|
|
205
|
-
### Download Errors
|
|
206
|
-
- 404 Not Found → File ID doesn't exist
|
|
207
|
-
- Network errors → Connection issues
|
|
208
|
-
- Timeout → Retry suggestion
|
|
209
|
-
|
|
210
|
-
### Extraction Errors
|
|
211
|
-
- Invalid ZIP → Corrupted file message
|
|
212
|
-
- Permission errors → Write access issues
|
|
213
|
-
- Disk space → Insufficient space
|
|
214
|
-
|
|
215
|
-
### User Cancellation
|
|
216
|
-
- Ctrl+C during prompts → Graceful exit
|
|
217
|
-
- Overwrite declined → Cancel operation
|
|
218
|
-
|
|
219
|
-
## Dependencies
|
|
220
|
-
|
|
221
|
-
### Production Dependencies
|
|
222
|
-
- `@directus/sdk` (^17.0.0) - Official Directus SDK
|
|
223
|
-
- `prompts` (^2.4.2) - Interactive CLI prompts
|
|
224
|
-
- `adm-zip` (^0.5.10) - ZIP file operations
|
|
225
|
-
- `chalk` (^5.3.0) - Terminal colors
|
|
226
|
-
|
|
227
|
-
### Development Dependencies
|
|
228
|
-
- `typescript` (^5.3.3) - TypeScript compiler
|
|
229
|
-
- `@types/node` (^20.11.0) - Node.js type definitions
|
|
230
|
-
- `@types/adm-zip` (^0.5.5) - adm-zip type definitions
|
|
231
|
-
- `@types/prompts` (^2.4.9) - prompts type definitions
|
|
232
|
-
|
|
233
|
-
## Build System
|
|
234
|
-
|
|
235
|
-
**Compiler:** TypeScript 5.3.3
|
|
236
|
-
|
|
237
|
-
**Target:** ES2022 with Node.js modules
|
|
238
|
-
|
|
239
|
-
**Output:** `dist/` directory with compiled JavaScript + source maps
|
|
240
|
-
|
|
241
|
-
**Entry Point:** `dist/index.js` (with shebang for CLI execution)
|
|
242
|
-
|
|
243
|
-
## Configuration File Location
|
|
244
|
-
|
|
245
|
-
**Path:** `~/.spek-cli/config.json`
|
|
246
|
-
|
|
247
|
-
**Platform-specific:**
|
|
248
|
-
- Windows: `C:\Users\<username>\.spek-cli\config.json`
|
|
249
|
-
- macOS: `/Users/<username>/.spek-cli/config.json`
|
|
250
|
-
- Linux: `/home/<username>/.spek-cli/config.json`
|
|
251
|
-
|
|
252
|
-
## Security Considerations
|
|
253
|
-
|
|
254
|
-
1. **Access Token Storage**
|
|
255
|
-
- Stored in user's home directory
|
|
256
|
-
- File permissions should be restricted (user-only)
|
|
257
|
-
- Never logged or displayed in output
|
|
258
|
-
|
|
259
|
-
2. **HTTPS Enforcement**
|
|
260
|
-
- Directus URL validated to be valid URL
|
|
261
|
-
- SDK handles HTTPS connections
|
|
262
|
-
|
|
263
|
-
3. **Input Validation**
|
|
264
|
-
- URL validation during setup
|
|
265
|
-
- File ID passed through without modification
|
|
266
|
-
- No shell command injection risks
|
|
267
|
-
|
|
268
|
-
## Performance Characteristics
|
|
269
|
-
|
|
270
|
-
- **Download Speed:** Limited by network and Directus server
|
|
271
|
-
- **Memory Usage:** Streams file to temp, then loads ZIP into memory
|
|
272
|
-
- **Disk Usage:** Temporary file during download (auto-cleaned)
|
|
273
|
-
- **Startup Time:** ~100ms for config load + argument parsing
|
|
274
|
-
|
|
275
|
-
## Future Enhancements
|
|
276
|
-
|
|
277
|
-
Potential features for future versions:
|
|
278
|
-
|
|
279
|
-
1. **Progress Bar:** Show download progress for large files
|
|
280
|
-
2. **Resume Downloads:** Support partial download resume
|
|
281
|
-
3. **Batch Downloads:** Download multiple files at once
|
|
282
|
-
4. **Config Management:** Commands to view/edit/reset config
|
|
283
|
-
5. **Dry Run:** Preview what would be extracted without extracting
|
|
284
|
-
6. **Custom Output:** Specify extraction directory
|
|
285
|
-
7. **Compression:** Support other archive formats
|
|
286
|
-
8. **Logging:** Verbose mode with detailed logs
|
|
@@ -1,135 +0,0 @@
|
|
|
1
|
-
# 🚀 Quick Publish Reference
|
|
2
|
-
|
|
3
|
-
## Pre-Publish Checklist
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
# 1. Verify token is configured
|
|
7
|
-
cat .env | grep NPM_ACCESS_TOKEN
|
|
8
|
-
|
|
9
|
-
# 2. Clean build
|
|
10
|
-
npm run build
|
|
11
|
-
|
|
12
|
-
# 3. Test locally
|
|
13
|
-
node dist/index.js --help
|
|
14
|
-
node dist/index.js --version
|
|
15
|
-
|
|
16
|
-
# 4. Dry run
|
|
17
|
-
npm publish --dry-run
|
|
18
|
-
```
|
|
19
|
-
|
|
20
|
-
## Publish Commands
|
|
21
|
-
|
|
22
|
-
### Linux/macOS
|
|
23
|
-
```bash
|
|
24
|
-
# Make executable (first time only)
|
|
25
|
-
chmod +x scripts/publish.sh
|
|
26
|
-
|
|
27
|
-
# Publish (choose one)
|
|
28
|
-
./scripts/publish.sh # Patch: 1.0.0 → 1.0.1
|
|
29
|
-
./scripts/publish.sh minor # Minor: 1.0.0 → 1.1.0
|
|
30
|
-
./scripts/publish.sh major # Major: 1.0.0 → 2.0.0
|
|
31
|
-
./scripts/publish.sh 2.5.3 # Specific version
|
|
32
|
-
```
|
|
33
|
-
|
|
34
|
-
### Windows (PowerShell)
|
|
35
|
-
```powershell
|
|
36
|
-
# Publish (choose one)
|
|
37
|
-
.\scripts\publish.ps1 # Patch: 1.0.0 → 1.0.1
|
|
38
|
-
.\scripts\publish.ps1 minor # Minor: 1.0.0 → 1.1.0
|
|
39
|
-
.\scripts\publish.ps1 major # Major: 1.0.0 → 2.0.0
|
|
40
|
-
.\scripts\publish.ps1 2.5.3 # Specific version
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
### Or Use npm Scripts
|
|
44
|
-
```bash
|
|
45
|
-
npm run publish:patch # 1.0.0 → 1.0.1
|
|
46
|
-
npm run publish:minor # 1.0.0 → 1.1.0
|
|
47
|
-
npm run publish:major # 1.0.0 → 2.0.0
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Post-Publish
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
# 1. Verify on npm
|
|
54
|
-
https://www.npmjs.com/package/spek-cli
|
|
55
|
-
|
|
56
|
-
# 2. Test installation
|
|
57
|
-
npx spek-cli@latest --version
|
|
58
|
-
|
|
59
|
-
# 3. Push git tag
|
|
60
|
-
git push origin v1.0.0
|
|
61
|
-
|
|
62
|
-
# 4. Test full workflow
|
|
63
|
-
npx spek-cli -d <test-file-id>
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
## Quick Test
|
|
67
|
-
|
|
68
|
-
```bash
|
|
69
|
-
# Test without publishing
|
|
70
|
-
npm link
|
|
71
|
-
spek-cli --help
|
|
72
|
-
spek-cli --version
|
|
73
|
-
npm unlink -g spek-cli
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
## Environment
|
|
77
|
-
|
|
78
|
-
Required in `.env`:
|
|
79
|
-
```bash
|
|
80
|
-
NPM_ACCESS_TOKEN=npm_xxxxxxxxxxxxxxxxxxxxxx
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
## What the Script Does
|
|
84
|
-
|
|
85
|
-
1. ✓ Checks git status
|
|
86
|
-
2. ✓ Clean installs dependencies
|
|
87
|
-
3. ✓ Builds TypeScript
|
|
88
|
-
4. ✓ Verifies build output
|
|
89
|
-
5. ✓ Bumps version
|
|
90
|
-
6. ✓ Creates .npmrc with token
|
|
91
|
-
7. ✓ Runs dry-run
|
|
92
|
-
8. ✓ Asks for confirmation
|
|
93
|
-
9. ✓ Publishes to npm
|
|
94
|
-
10. ✓ Cleans up .npmrc
|
|
95
|
-
11. ✓ Creates git tag
|
|
96
|
-
12. ✓ Shows success message
|
|
97
|
-
|
|
98
|
-
## Troubleshooting
|
|
99
|
-
|
|
100
|
-
### "NPM_ACCESS_TOKEN not found"
|
|
101
|
-
```bash
|
|
102
|
-
# Check .env file exists
|
|
103
|
-
ls -la .env
|
|
104
|
-
|
|
105
|
-
# Create if missing
|
|
106
|
-
echo "NPM_ACCESS_TOKEN=your-token-here" > .env
|
|
107
|
-
```
|
|
108
|
-
|
|
109
|
-
### "401 Unauthorized"
|
|
110
|
-
- Generate new token at https://www.npmjs.com/settings/~/tokens
|
|
111
|
-
- Update `.env` with new token
|
|
112
|
-
|
|
113
|
-
### "403 Forbidden"
|
|
114
|
-
- Package name already exists
|
|
115
|
-
- Or insufficient token permissions
|
|
116
|
-
|
|
117
|
-
### Build fails
|
|
118
|
-
```bash
|
|
119
|
-
rm -rf dist node_modules
|
|
120
|
-
npm install
|
|
121
|
-
npm run build
|
|
122
|
-
```
|
|
123
|
-
|
|
124
|
-
## Quick Links
|
|
125
|
-
|
|
126
|
-
- **Publishing Guide**: `docs/PUBLISHING.md`
|
|
127
|
-
- **npm Registry**: https://www.npmjs.com/package/spek-cli
|
|
128
|
-
- **Token Settings**: https://www.npmjs.com/settings/~/tokens
|
|
129
|
-
- **Rename Summary**: `RENAME_COMPLETE.md`
|
|
130
|
-
|
|
131
|
-
---
|
|
132
|
-
|
|
133
|
-
**Current Version**: 1.0.0 (unpublished)
|
|
134
|
-
**Ready**: ✅ Yes - All files updated and tested
|
|
135
|
-
**Next**: Run publish script
|