vipcode 0.0.0-stage → 0.2.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/LICENSE +21 -0
- package/README.en.md +60 -0
- package/README.md +401 -2
- package/dist/agent.js +502 -0
- package/dist/agents.js +174 -0
- package/dist/app.js +1025 -0
- package/dist/auth.js +108 -0
- package/dist/catalog.js +487 -0
- package/dist/commands.js +121 -0
- package/dist/config.js +230 -0
- package/dist/debug.js +32 -0
- package/dist/discovery.js +277 -0
- package/dist/frontmatter.js +45 -0
- package/dist/images.js +81 -0
- package/dist/index.js +623 -0
- package/dist/login.js +157 -0
- package/dist/lsp.js +480 -0
- package/dist/markdown.js +262 -0
- package/dist/match.js +8 -0
- package/dist/mcp.js +225 -0
- package/dist/meta.js +7 -0
- package/dist/paths.js +53 -0
- package/dist/permissions.js +144 -0
- package/dist/prompt.js +123 -0
- package/dist/ranking.js +230 -0
- package/dist/router.js +726 -0
- package/dist/sanitize.js +38 -0
- package/dist/session.js +219 -0
- package/dist/skills.js +374 -0
- package/dist/snapshot.js +199 -0
- package/dist/tools.js +1311 -0
- package/dist/trust.js +171 -0
- package/dist/tui/app.js +1019 -0
- package/dist/tui/dialogs.js +197 -0
- package/dist/tui/editor.js +120 -0
- package/dist/ui.js +184 -0
- package/dist/update.js +237 -0
- package/package.json +64 -4
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import fs from "node:fs";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import YAML from "yaml";
|
|
4
|
+
// Separa la cabecera YAML (entre ---) del cuerpo de un .md
|
|
5
|
+
export function parseFrontmatter(text) {
|
|
6
|
+
const match = /^---\r?\n([\s\S]*?)\r?\n---[ \t]*\r?\n?([\s\S]*)$/.exec(text);
|
|
7
|
+
if (!match) {
|
|
8
|
+
return { data: {}, body: text };
|
|
9
|
+
}
|
|
10
|
+
let data = {};
|
|
11
|
+
try {
|
|
12
|
+
const parsed = YAML.parse(match[1]);
|
|
13
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
14
|
+
data = parsed;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
data = {};
|
|
19
|
+
}
|
|
20
|
+
return { data, body: match[2] };
|
|
21
|
+
}
|
|
22
|
+
// Lee todos los .md de varias carpetas (las que no existen se ignoran); el nombre sale del fichero
|
|
23
|
+
export function readMarkdownDir(dirs) {
|
|
24
|
+
const result = [];
|
|
25
|
+
for (const dir of dirs) {
|
|
26
|
+
let entries = [];
|
|
27
|
+
try {
|
|
28
|
+
entries = fs.readdirSync(dir).filter((entry) => entry.endsWith(".md")).sort();
|
|
29
|
+
}
|
|
30
|
+
catch {
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
for (const entry of entries) {
|
|
34
|
+
const file = path.join(dir, entry);
|
|
35
|
+
try {
|
|
36
|
+
const { data, body } = parseFrontmatter(fs.readFileSync(file, "utf8"));
|
|
37
|
+
result.push({ name: entry.replace(/\.md$/, ""), file, data, body: body.trim() });
|
|
38
|
+
}
|
|
39
|
+
catch {
|
|
40
|
+
// fichero ilegible: lo saltamos
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return result;
|
|
45
|
+
}
|
package/dist/images.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
const MIME = {
|
|
6
|
+
".png": "image/png",
|
|
7
|
+
".jpg": "image/jpeg",
|
|
8
|
+
".jpeg": "image/jpeg",
|
|
9
|
+
".gif": "image/gif",
|
|
10
|
+
".webp": "image/webp",
|
|
11
|
+
};
|
|
12
|
+
// Las imágenes más grandes que esto no se mandan (los proveedores las rechazan)
|
|
13
|
+
const MAX_IMAGE_BYTES = 8 * 1024 * 1024;
|
|
14
|
+
export function isImagePath(file) {
|
|
15
|
+
return Boolean(MIME[path.extname(file).toLowerCase()]);
|
|
16
|
+
}
|
|
17
|
+
export function imageMime(file) {
|
|
18
|
+
return MIME[path.extname(file).toLowerCase()] || "image/png";
|
|
19
|
+
}
|
|
20
|
+
// Convierte un fichero de imagen en data URL (data:image/png;base64,...)
|
|
21
|
+
export function toDataUrl(file) {
|
|
22
|
+
const stat = fs.statSync(file);
|
|
23
|
+
if (stat.size > MAX_IMAGE_BYTES) {
|
|
24
|
+
throw new Error(`La imagen ${path.basename(file)} ocupa más de 8 MB`);
|
|
25
|
+
}
|
|
26
|
+
return `data:${imageMime(file)};base64,${fs.readFileSync(file).toString("base64")}`;
|
|
27
|
+
}
|
|
28
|
+
function run(command, args) {
|
|
29
|
+
return new Promise((resolve) => {
|
|
30
|
+
execFile(command, args, { encoding: "buffer", maxBuffer: 32 * 1024 * 1024, timeout: 10000 }, (err, stdout) => {
|
|
31
|
+
let code = 0;
|
|
32
|
+
if (err) {
|
|
33
|
+
code = typeof err.code === "number" ? err.code : 1;
|
|
34
|
+
}
|
|
35
|
+
resolve({ code, stdout: stdout || Buffer.alloc(0) });
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
// Lee una imagen del portapapeles (macOS con osascript, Linux con wl-paste o xclip)
|
|
40
|
+
export async function readClipboardImage() {
|
|
41
|
+
if (process.platform === "darwin") {
|
|
42
|
+
const tmp = path.join(os.tmpdir(), `vipcode-clip-${process.pid}-${Date.now()}.png`);
|
|
43
|
+
const script = [
|
|
44
|
+
`set f to open for access POSIX file "${tmp}" with write permission`,
|
|
45
|
+
"try",
|
|
46
|
+
"write (the clipboard as «class PNGf») to f",
|
|
47
|
+
"end try",
|
|
48
|
+
"close access f",
|
|
49
|
+
];
|
|
50
|
+
const args = [];
|
|
51
|
+
for (const line of script) {
|
|
52
|
+
args.push("-e", line);
|
|
53
|
+
}
|
|
54
|
+
await run("osascript", args);
|
|
55
|
+
try {
|
|
56
|
+
const size = fs.statSync(tmp).size;
|
|
57
|
+
if (size === 0) {
|
|
58
|
+
return null;
|
|
59
|
+
}
|
|
60
|
+
return `data:image/png;base64,${fs.readFileSync(tmp).toString("base64")}`;
|
|
61
|
+
}
|
|
62
|
+
catch {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
fs.rmSync(tmp, { force: true });
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
if (process.platform === "linux") {
|
|
70
|
+
for (const [command, args] of [
|
|
71
|
+
["wl-paste", ["--type", "image/png"]],
|
|
72
|
+
["xclip", ["-selection", "clipboard", "-t", "image/png", "-o"]],
|
|
73
|
+
]) {
|
|
74
|
+
const result = await run(command, args);
|
|
75
|
+
if (result.code === 0 && result.stdout.length > 100) {
|
|
76
|
+
return `data:image/png;base64,${result.stdout.toString("base64")}`;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return null;
|
|
81
|
+
}
|