vibefast-cli 0.1.3 → 0.2.0
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/AUTO-DETECT-DEPS.md +607 -0
- package/CHANGELOG.md +86 -0
- package/FINAL-PACKAGE-STRATEGY.md +583 -0
- package/FINAL-SIMPLE-PLAN.md +487 -0
- package/FLOW-DIAGRAM.md +1629 -0
- package/GOTCHAS-AND-RISKS.md +801 -0
- package/IMPLEMENTATION-COMPLETE.md +477 -0
- package/IMPLEMENTATION-PLAN.md +1360 -0
- package/PRE-PUBLISH-CHECKLIST.md +558 -0
- package/PRODUCTION-READINESS.md +684 -0
- package/PRODUCTION-TEST-RESULTS.md +465 -0
- package/README.md +73 -7
- package/READY-TO-PUBLISH.md +419 -0
- package/SIMPLIFIED-PLAN.md +578 -0
- package/TEST-SUMMARY.md +261 -0
- package/USER-MODIFICATIONS.md +448 -0
- package/cloudflare-worker/worker.js +39 -11
- package/dist/commands/add.d.ts.map +1 -1
- package/dist/commands/add.js +192 -15
- package/dist/commands/add.js.map +1 -1
- package/dist/commands/checklist.d.ts +3 -0
- package/dist/commands/checklist.d.ts.map +1 -0
- package/dist/commands/checklist.js +64 -0
- package/dist/commands/checklist.js.map +1 -0
- package/dist/commands/remove.d.ts.map +1 -1
- package/dist/commands/remove.js +85 -2
- package/dist/commands/remove.js.map +1 -1
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.d.ts.map +1 -0
- package/dist/commands/status.js +40 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/core/__tests__/fsx.test.d.ts +2 -0
- package/dist/core/__tests__/fsx.test.d.ts.map +1 -0
- package/dist/core/__tests__/fsx.test.js +79 -0
- package/dist/core/__tests__/fsx.test.js.map +1 -0
- package/dist/core/__tests__/hash.test.d.ts +2 -0
- package/dist/core/__tests__/hash.test.d.ts.map +1 -0
- package/dist/core/__tests__/hash.test.js +84 -0
- package/dist/core/__tests__/hash.test.js.map +1 -0
- package/dist/core/__tests__/journal.test.js +65 -0
- package/dist/core/__tests__/journal.test.js.map +1 -1
- package/dist/core/__tests__/prompt.test.d.ts +2 -0
- package/dist/core/__tests__/prompt.test.d.ts.map +1 -0
- package/dist/core/__tests__/prompt.test.js +56 -0
- package/dist/core/__tests__/prompt.test.js.map +1 -0
- package/dist/core/fsx.d.ts +7 -1
- package/dist/core/fsx.d.ts.map +1 -1
- package/dist/core/fsx.js +18 -3
- package/dist/core/fsx.js.map +1 -1
- package/dist/core/hash.d.ts +13 -0
- package/dist/core/hash.d.ts.map +1 -0
- package/dist/core/hash.js +69 -0
- package/dist/core/hash.js.map +1 -0
- package/dist/core/journal.d.ts +10 -1
- package/dist/core/journal.d.ts.map +1 -1
- package/dist/core/journal.js +23 -1
- package/dist/core/journal.js.map +1 -1
- package/dist/core/prompt.d.ts +11 -0
- package/dist/core/prompt.d.ts.map +1 -0
- package/dist/core/prompt.js +34 -0
- package/dist/core/prompt.js.map +1 -0
- package/dist/index.js +5 -1
- package/dist/index.js.map +1 -1
- package/package.json +3 -1
- package/src/commands/add.ts +234 -16
- package/src/commands/checklist.ts +71 -0
- package/src/commands/remove.ts +105 -3
- package/src/commands/status.ts +47 -0
- package/src/core/__tests__/fsx.test.ts +101 -0
- package/src/core/__tests__/hash.test.ts +112 -0
- package/src/core/__tests__/journal.test.ts +76 -0
- package/src/core/__tests__/prompt.test.ts +72 -0
- package/src/core/fsx.ts +38 -5
- package/src/core/hash.ts +84 -0
- package/src/core/journal.ts +40 -2
- package/src/core/prompt.ts +40 -0
- package/src/index.ts +5 -1
- package/text.md +27 -0
package/src/core/hash.ts
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { readFile, stat } from 'fs/promises';
|
|
3
|
+
import { log } from './log.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Hash a single file using SHA-256
|
|
7
|
+
* Returns empty string if file doesn't exist or can't be read
|
|
8
|
+
*/
|
|
9
|
+
export async function hashFile(filePath: string): Promise<string> {
|
|
10
|
+
try {
|
|
11
|
+
const content = await readFile(filePath);
|
|
12
|
+
return createHash('sha256').update(content).digest('hex');
|
|
13
|
+
} catch (error) {
|
|
14
|
+
// File doesn't exist or can't be read
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Hash multiple files in batches
|
|
21
|
+
* Skips binary files and large files for performance
|
|
22
|
+
*/
|
|
23
|
+
export async function hashFiles(
|
|
24
|
+
filePaths: string[],
|
|
25
|
+
options?: { showProgress?: boolean }
|
|
26
|
+
): Promise<Map<string, string>> {
|
|
27
|
+
const hashes = new Map<string, string>();
|
|
28
|
+
|
|
29
|
+
// Filter out files we don't need to hash
|
|
30
|
+
const filesToHash: string[] = [];
|
|
31
|
+
|
|
32
|
+
for (const path of filePaths) {
|
|
33
|
+
// Skip binary files
|
|
34
|
+
if (/\.(png|jpg|jpeg|gif|ico|woff|woff2|ttf|eot|svg|mp4|mp3|pdf)$/i.test(path)) {
|
|
35
|
+
hashes.set(path, ''); // Store empty hash for binary files
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Skip large files (>1MB)
|
|
40
|
+
try {
|
|
41
|
+
const stats = await stat(path);
|
|
42
|
+
if (stats.size > 1024 * 1024) {
|
|
43
|
+
hashes.set(path, ''); // Store empty hash for large files
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
} catch {
|
|
47
|
+
// File doesn't exist, skip
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
filesToHash.push(path);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Show progress if many files
|
|
55
|
+
if (options?.showProgress && filesToHash.length > 20) {
|
|
56
|
+
log.info(`Computing file hashes for ${filesToHash.length} files...`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// Process in parallel batches
|
|
60
|
+
const batchSize = 10;
|
|
61
|
+
|
|
62
|
+
for (let i = 0; i < filesToHash.length; i += batchSize) {
|
|
63
|
+
const batch = filesToHash.slice(i, i + batchSize);
|
|
64
|
+
|
|
65
|
+
await Promise.all(
|
|
66
|
+
batch.map(async (path) => {
|
|
67
|
+
const hash = await hashFile(path);
|
|
68
|
+
hashes.set(path, hash);
|
|
69
|
+
})
|
|
70
|
+
);
|
|
71
|
+
|
|
72
|
+
// Show progress
|
|
73
|
+
if (options?.showProgress && filesToHash.length > 20) {
|
|
74
|
+
const progress = Math.min(i + batchSize, filesToHash.length);
|
|
75
|
+
process.stdout.write(`\r Progress: ${progress}/${filesToHash.length}`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
if (options?.showProgress && filesToHash.length > 20) {
|
|
80
|
+
process.stdout.write('\n');
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return hashes;
|
|
84
|
+
}
|
package/src/core/journal.ts
CHANGED
|
@@ -1,14 +1,25 @@
|
|
|
1
1
|
import { readFileContent, writeFileContent, exists, ensureDir } from './fsx.js';
|
|
2
2
|
import { dirname } from 'path';
|
|
3
|
+
import { hashFile } from './hash.js';
|
|
4
|
+
|
|
5
|
+
export interface FileEntry {
|
|
6
|
+
path: string;
|
|
7
|
+
hash: string;
|
|
8
|
+
}
|
|
3
9
|
|
|
4
10
|
export interface JournalEntry {
|
|
5
11
|
feature: string;
|
|
6
12
|
target: 'native' | 'web';
|
|
7
|
-
files: string[];
|
|
13
|
+
files: FileEntry[] | string[]; // Support both old and new format
|
|
8
14
|
insertedNav: boolean;
|
|
9
15
|
ts: number;
|
|
10
16
|
navHref?: string;
|
|
11
17
|
navLabel?: string;
|
|
18
|
+
manifest?: {
|
|
19
|
+
version?: string;
|
|
20
|
+
manualSteps?: any[];
|
|
21
|
+
env?: any[];
|
|
22
|
+
};
|
|
12
23
|
}
|
|
13
24
|
|
|
14
25
|
export interface Journal {
|
|
@@ -20,7 +31,34 @@ export async function readJournal(journalPath: string): Promise<Journal> {
|
|
|
20
31
|
return { entries: [] };
|
|
21
32
|
}
|
|
22
33
|
const content = await readFileContent(journalPath);
|
|
23
|
-
|
|
34
|
+
const journal = JSON.parse(content) as Journal;
|
|
35
|
+
|
|
36
|
+
// Migrate old format to new format
|
|
37
|
+
let needsMigration = false;
|
|
38
|
+
|
|
39
|
+
for (const entry of journal.entries) {
|
|
40
|
+
if (entry.files.length > 0 && typeof entry.files[0] === 'string') {
|
|
41
|
+
needsMigration = true;
|
|
42
|
+
// Old format: array of strings
|
|
43
|
+
const oldFiles = entry.files as string[];
|
|
44
|
+
|
|
45
|
+
// Convert to new format with hashes
|
|
46
|
+
const newFiles: FileEntry[] = [];
|
|
47
|
+
for (const filePath of oldFiles) {
|
|
48
|
+
const hash = await hashFile(filePath);
|
|
49
|
+
newFiles.push({ path: filePath, hash });
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
entry.files = newFiles;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// Save migrated journal
|
|
57
|
+
if (needsMigration) {
|
|
58
|
+
await writeJournal(journalPath, journal);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
return journal;
|
|
24
62
|
}
|
|
25
63
|
|
|
26
64
|
export async function writeJournal(journalPath: string, journal: Journal): Promise<void> {
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import readlineSync from 'readline-sync';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Prompt user for input
|
|
5
|
+
* Returns empty string in non-interactive environments (CI/CD)
|
|
6
|
+
*/
|
|
7
|
+
export function promptUser(question: string): string {
|
|
8
|
+
// Check if we're in a non-interactive environment
|
|
9
|
+
if (!process.stdin.isTTY) {
|
|
10
|
+
return '';
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Check for CI environment variables
|
|
14
|
+
const isCI = process.env.CI === 'true' ||
|
|
15
|
+
process.env.GITHUB_ACTIONS === 'true' ||
|
|
16
|
+
process.env.GITLAB_CI === 'true' ||
|
|
17
|
+
process.env.CIRCLECI === 'true';
|
|
18
|
+
|
|
19
|
+
if (isCI) {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return readlineSync.question(question);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Prompt user for yes/no confirmation
|
|
28
|
+
* Returns defaultValue in non-interactive environments
|
|
29
|
+
*/
|
|
30
|
+
export function promptYesNo(question: string, defaultYes = false): boolean {
|
|
31
|
+
const answer = promptUser(question);
|
|
32
|
+
|
|
33
|
+
// Empty answer (non-interactive or just pressed enter)
|
|
34
|
+
if (answer === '') {
|
|
35
|
+
return defaultYes;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const normalized = answer.toLowerCase().trim();
|
|
39
|
+
return normalized === 'y' || normalized === 'yes';
|
|
40
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
import { Command } from 'commander';
|
|
4
|
-
import pkg from '../package.json'
|
|
4
|
+
import pkg from '../package.json' with { type: 'json' };
|
|
5
5
|
import { addCommand } from './commands/add.js';
|
|
6
6
|
import { removeCommand } from './commands/remove.js';
|
|
7
7
|
import { listCommand } from './commands/list.js';
|
|
@@ -9,6 +9,8 @@ import { doctorCommand } from './commands/doctor.js';
|
|
|
9
9
|
import { loginCommand } from './commands/login.js';
|
|
10
10
|
import { devicesCommand } from './commands/devices.js';
|
|
11
11
|
import { logoutCommand } from './commands/logout.js';
|
|
12
|
+
import { statusCommand } from './commands/status.js';
|
|
13
|
+
import { checklistCommand } from './commands/checklist.js';
|
|
12
14
|
|
|
13
15
|
const program = new Command();
|
|
14
16
|
|
|
@@ -24,5 +26,7 @@ program.addCommand(doctorCommand);
|
|
|
24
26
|
program.addCommand(listCommand);
|
|
25
27
|
program.addCommand(addCommand);
|
|
26
28
|
program.addCommand(removeCommand);
|
|
29
|
+
program.addCommand(statusCommand);
|
|
30
|
+
program.addCommand(checklistCommand);
|
|
27
31
|
|
|
28
32
|
program.parse();
|
package/text.md
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/$$ /$$ /$$$$$$ /$$$$$$$ /$$$$$$$$ /$$$$$$$$ /$$$$$$ /$$$$$$ /$$$$$$$$
|
|
2
|
+
| $$ | $$|_ $$_/| $$__ $$| $$_____/| $$_____//$$__ $$ /$$__ $$|__ $$__/
|
|
3
|
+
| $$ | $$ | $$ | $$ \ $$| $$ | $$ | $$ \ $$| $$ \__/ | $$
|
|
4
|
+
| $$ / $$/ | $$ | $$$$$$$ | $$$$$ | $$$$$ | $$$$$$$$| $$$$$$ | $$
|
|
5
|
+
\ $$ $$/ | $$ | $$__ $$| $$__/ | $$__/ | $$__ $$ \____ $$ | $$
|
|
6
|
+
\ $$$/ | $$ | $$ \ $$| $$ | $$ | $$ | $$ /$$ \ $$ | $$
|
|
7
|
+
\ $/ /$$$$$$| $$$$$$$/| $$$$$$$$| $$ | $$ | $$| $$$$$$/ | $$
|
|
8
|
+
\_/ |______/|_______/ |________/|__/ |__/ |__/ \______/ |__/
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
▖▖▄▖▄ ▄▖▄▖▄▖▄▖▄▖
|
|
17
|
+
▌▌▐ ▙▘▙▖▙▖▌▌▚ ▐
|
|
18
|
+
▚▘▟▖▙▘▙▖▌ ▛▌▄▌▐
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
██╗ ██╗██╗██████╗ ███████╗███████╗ █████╗ ███████╗████████╗
|
|
22
|
+
██║ ██║██║██╔══██╗██╔════╝██╔════╝██╔══██╗██╔════╝╚══██╔══╝
|
|
23
|
+
██║ ██║██║██████╔╝█████╗ █████╗ ███████║███████╗ ██║
|
|
24
|
+
╚██╗ ██╔╝██║██╔══██╗██╔══╝ ██╔══╝ ██╔══██║╚════██║ ██║
|
|
25
|
+
╚████╔╝ ██║██████╔╝███████╗██║ ██║ ██║███████║ ██║
|
|
26
|
+
╚═══╝ ╚═╝╚═════╝ ╚══════╝╚═╝ ╚═╝ ╚═╝╚══════╝ ╚═╝
|
|
27
|
+
|