gufi-cli 0.1.1 → 0.1.3

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/src/lib/sync.ts DELETED
@@ -1,236 +0,0 @@
1
- /**
2
- * Gufi Dev CLI - Sync Library
3
- * Handles bidirectional file synchronization
4
- */
5
-
6
- import fs from "fs";
7
- import path from "path";
8
- import os from "os";
9
- import { getViewFiles, saveViewFile, type ViewFile } from "./api.js";
10
- import { setCurrentView, getCurrentView } from "./config.js";
11
-
12
- const GUFI_DEV_DIR = path.join(os.homedir(), "gufi-dev");
13
- const META_FILE = ".gufi-view.json";
14
-
15
- export interface ViewMeta {
16
- viewId: number;
17
- viewName: string;
18
- packageId: number;
19
- lastSync: string;
20
- files: Record<string, { hash: string; mtime: number }>;
21
- }
22
-
23
- function ensureDir(dir: string): void {
24
- if (!fs.existsSync(dir)) {
25
- fs.mkdirSync(dir, { recursive: true });
26
- }
27
- }
28
-
29
- function hashContent(content: string): string {
30
- // Simple hash for change detection
31
- let hash = 0;
32
- for (let i = 0; i < content.length; i++) {
33
- const char = content.charCodeAt(i);
34
- hash = ((hash << 5) - hash) + char;
35
- hash = hash & hash;
36
- }
37
- return hash.toString(16);
38
- }
39
-
40
- function getLanguage(filePath: string): string {
41
- const ext = path.extname(filePath).toLowerCase();
42
- const langMap: Record<string, string> = {
43
- ".ts": "typescript",
44
- ".tsx": "typescript",
45
- ".js": "javascript",
46
- ".jsx": "javascript",
47
- ".css": "css",
48
- ".json": "json",
49
- ".md": "markdown",
50
- };
51
- return langMap[ext] || "text";
52
- }
53
-
54
- export function getViewDir(viewName: string): string {
55
- return path.join(GUFI_DEV_DIR, viewName.toLowerCase().replace(/\s+/g, "-"));
56
- }
57
-
58
- export function loadViewMeta(viewDir: string): ViewMeta | null {
59
- const metaPath = path.join(viewDir, META_FILE);
60
- if (!fs.existsSync(metaPath)) return null;
61
- try {
62
- return JSON.parse(fs.readFileSync(metaPath, "utf-8"));
63
- } catch {
64
- return null;
65
- }
66
- }
67
-
68
- function saveViewMeta(viewDir: string, meta: ViewMeta): void {
69
- const metaPath = path.join(viewDir, META_FILE);
70
- fs.writeFileSync(metaPath, JSON.stringify(meta, null, 2));
71
- }
72
-
73
- /**
74
- * Pull view files from Gufi to local directory
75
- */
76
- export async function pullView(
77
- viewId: number,
78
- viewName: string,
79
- packageId: number
80
- ): Promise<{ dir: string; fileCount: number }> {
81
- const viewDir = getViewDir(viewName);
82
- ensureDir(viewDir);
83
-
84
- const files = await getViewFiles(viewId);
85
- const fileMeta: ViewMeta["files"] = {};
86
-
87
- for (const file of files) {
88
- const filePath = path.join(viewDir, file.file_path.replace(/^\//, ""));
89
- ensureDir(path.dirname(filePath));
90
- fs.writeFileSync(filePath, file.content);
91
-
92
- fileMeta[file.file_path] = {
93
- hash: hashContent(file.content),
94
- mtime: Date.now(),
95
- };
96
- }
97
-
98
- const meta: ViewMeta = {
99
- viewId,
100
- viewName,
101
- packageId,
102
- lastSync: new Date().toISOString(),
103
- files: fileMeta,
104
- };
105
- saveViewMeta(viewDir, meta);
106
-
107
- // Update current view in config
108
- setCurrentView({ id: viewId, name: viewName, packageId, localPath: viewDir });
109
-
110
- return { dir: viewDir, fileCount: files.length };
111
- }
112
-
113
- /**
114
- * Push local files to Gufi
115
- */
116
- export async function pushView(viewDir?: string): Promise<{ pushed: number }> {
117
- const dir = viewDir || getCurrentView()?.localPath;
118
- if (!dir) {
119
- throw new Error("No hay vista activa. Usa: gufi pull <vista>");
120
- }
121
-
122
- const meta = loadViewMeta(dir);
123
- if (!meta) {
124
- throw new Error("No se encontró metadata de vista. ¿Hiciste pull primero?");
125
- }
126
-
127
- const localFiles = getLocalFiles(dir);
128
- let pushed = 0;
129
-
130
- for (const file of localFiles) {
131
- const content = fs.readFileSync(path.join(dir, file), "utf-8");
132
- const hash = hashContent(content);
133
- const filePath = "/" + file;
134
-
135
- // Check if file changed
136
- const oldMeta = meta.files[filePath];
137
- if (oldMeta && oldMeta.hash === hash) {
138
- continue; // No changes
139
- }
140
-
141
- // Push to Gufi
142
- await saveViewFile(meta.viewId, {
143
- file_path: filePath,
144
- content,
145
- language: getLanguage(file),
146
- is_entry_point: file === "index.tsx",
147
- });
148
-
149
- // Update meta
150
- meta.files[filePath] = { hash, mtime: Date.now() };
151
- pushed++;
152
- }
153
-
154
- meta.lastSync = new Date().toISOString();
155
- saveViewMeta(dir, meta);
156
-
157
- return { pushed };
158
- }
159
-
160
- /**
161
- * Get list of local files (excluding meta and hidden)
162
- */
163
- function getLocalFiles(dir: string, prefix = ""): string[] {
164
- const files: string[] = [];
165
- const entries = fs.readdirSync(dir, { withFileTypes: true });
166
-
167
- for (const entry of entries) {
168
- if (entry.name.startsWith(".")) continue; // Skip hidden files
169
-
170
- const fullPath = path.join(prefix, entry.name);
171
-
172
- if (entry.isDirectory()) {
173
- files.push(...getLocalFiles(path.join(dir, entry.name), fullPath));
174
- } else {
175
- files.push(fullPath);
176
- }
177
- }
178
-
179
- return files;
180
- }
181
-
182
- /**
183
- * Check for local changes that need pushing
184
- */
185
- export function getChangedFiles(viewDir: string): string[] {
186
- const meta = loadViewMeta(viewDir);
187
- if (!meta) return [];
188
-
189
- const changed: string[] = [];
190
- const localFiles = getLocalFiles(viewDir);
191
-
192
- for (const file of localFiles) {
193
- const content = fs.readFileSync(path.join(viewDir, file), "utf-8");
194
- const hash = hashContent(content);
195
- const filePath = "/" + file;
196
-
197
- const oldMeta = meta.files[filePath];
198
- if (!oldMeta || oldMeta.hash !== hash) {
199
- changed.push(file);
200
- }
201
- }
202
-
203
- return changed;
204
- }
205
-
206
- /**
207
- * Push a single file
208
- */
209
- export async function pushSingleFile(
210
- viewDir: string,
211
- relativePath: string
212
- ): Promise<void> {
213
- const meta = loadViewMeta(viewDir);
214
- if (!meta) {
215
- throw new Error("No se encontró metadata de vista");
216
- }
217
-
218
- const fullPath = path.join(viewDir, relativePath);
219
- const content = fs.readFileSync(fullPath, "utf-8");
220
- const filePath = "/" + relativePath.replace(/\\/g, "/");
221
-
222
- await saveViewFile(meta.viewId, {
223
- file_path: filePath,
224
- content,
225
- language: getLanguage(relativePath),
226
- is_entry_point: relativePath === "index.tsx",
227
- });
228
-
229
- // Update meta
230
- meta.files[filePath] = {
231
- hash: hashContent(content),
232
- mtime: Date.now(),
233
- };
234
- meta.lastSync = new Date().toISOString();
235
- saveViewMeta(viewDir, meta);
236
- }
package/tsconfig.json DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2022",
4
- "module": "NodeNext",
5
- "moduleResolution": "NodeNext",
6
- "outDir": "./dist",
7
- "rootDir": "./src",
8
- "strict": true,
9
- "esModuleInterop": true,
10
- "skipLibCheck": true,
11
- "forceConsistentCasingInFileNames": true,
12
- "declaration": true,
13
- "resolveJsonModule": true
14
- },
15
- "include": ["src/**/*"],
16
- "exclude": ["node_modules", "dist"]
17
- }