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/CLAUDE.md +1491 -0
- package/dist/commands/companies.d.ts +26 -0
- package/dist/commands/companies.js +513 -0
- package/dist/commands/login.js +4 -3
- package/dist/commands/logs.d.ts +8 -0
- package/dist/commands/logs.js +153 -0
- package/dist/commands/push.d.ts +2 -2
- package/dist/commands/push.js +4 -3
- package/dist/index.d.ts +17 -7
- package/dist/index.js +64 -8
- package/dist/lib/api.d.ts +1 -0
- package/dist/lib/api.js +42 -5
- package/dist/lib/config.d.ts +4 -1
- package/dist/lib/config.js +13 -1
- package/package.json +15 -3
- package/src/commands/list.ts +0 -51
- package/src/commands/login.ts +0 -124
- package/src/commands/pull.ts +0 -113
- package/src/commands/push.ts +0 -85
- package/src/commands/watch.ts +0 -89
- package/src/index.ts +0 -73
- package/src/lib/api.ts +0 -127
- package/src/lib/config.ts +0 -93
- package/src/lib/sync.ts +0 -236
- package/tsconfig.json +0 -17
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
|
-
}
|