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
package/dist/trust.js
ADDED
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
2
|
+
import fs from "node:fs";
|
|
3
|
+
import path from "node:path";
|
|
4
|
+
import { parseFrontmatter } from "./frontmatter.js";
|
|
5
|
+
import { TRUST_PATH, ensureHomeDir } from "./paths.js";
|
|
6
|
+
// Lo que un proyecto puede traer y que cambia qué ejecuta vipcode o a dónde manda tus claves: servidores MCP y
|
|
7
|
+
// de lenguaje, proveedores, permisos, agentes con permisos propios y comandos que lanzan órdenes. No se usa hasta
|
|
8
|
+
// que confías en la carpeta, y si cambia (por ejemplo tras un git pull) se vuelve a preguntar.
|
|
9
|
+
const CONFIG_FILES = ["vipcode.json", path.join(".vipcode", "config.json")];
|
|
10
|
+
const AGENT_DIRS = [path.join(".vipcode", "agents"), path.join(".opencode", "agent"), path.join(".opencode", "agents")];
|
|
11
|
+
const COMMAND_DIRS = [path.join(".vipcode", "commands"), path.join(".opencode", "command"), path.join(".opencode", "commands")];
|
|
12
|
+
function isObject(value) {
|
|
13
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
+
}
|
|
15
|
+
function short(value) {
|
|
16
|
+
const text = typeof value === "string" ? value : JSON.stringify(value);
|
|
17
|
+
return text.length > 100 ? `${text.slice(0, 99)}…` : text;
|
|
18
|
+
}
|
|
19
|
+
function readText(file) {
|
|
20
|
+
try {
|
|
21
|
+
return fs.statSync(file).isFile() ? fs.readFileSync(file, "utf8") : null;
|
|
22
|
+
}
|
|
23
|
+
catch {
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function markdownFiles(root, dirs) {
|
|
28
|
+
const files = [];
|
|
29
|
+
for (const dir of dirs) {
|
|
30
|
+
try {
|
|
31
|
+
for (const name of fs.readdirSync(path.join(root, dir)).sort()) {
|
|
32
|
+
if (name.endsWith(".md")) {
|
|
33
|
+
files.push(path.join(dir, name));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
// la carpeta no existe
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return files;
|
|
42
|
+
}
|
|
43
|
+
function describeConfig(data) {
|
|
44
|
+
const changes = [];
|
|
45
|
+
const keys = Object.keys(data).filter((key) => !key.startsWith("$"));
|
|
46
|
+
const rest = [];
|
|
47
|
+
for (const key of keys) {
|
|
48
|
+
const value = data[key];
|
|
49
|
+
if (key === "providers" && Array.isArray(value)) {
|
|
50
|
+
const names = value.map((item) => (isObject(item) ? String(item.name || "?") : "?"));
|
|
51
|
+
changes.push(`proveedores: ${names.join(", ")} (pueden cambiar a dónde se mandan tus claves)`);
|
|
52
|
+
}
|
|
53
|
+
else if (key === "mcp" && isObject(value)) {
|
|
54
|
+
const servers = Object.entries(value).map(([name, server]) => {
|
|
55
|
+
const detail = isObject(server) ? server.command || server.url : server;
|
|
56
|
+
return `${name} (${short(detail)})`;
|
|
57
|
+
});
|
|
58
|
+
changes.push(`servidores MCP que se arrancan solos: ${servers.join(", ")}`);
|
|
59
|
+
}
|
|
60
|
+
else if (key === "lsp" && isObject(value)) {
|
|
61
|
+
changes.push(`servidores de lenguaje: ${short(value)}`);
|
|
62
|
+
}
|
|
63
|
+
else if (key === "permission") {
|
|
64
|
+
changes.push(`permisos: ${short(value)}`);
|
|
65
|
+
}
|
|
66
|
+
else if (key === "agents" && isObject(value)) {
|
|
67
|
+
changes.push(`agentes: ${Object.keys(value).join(", ")}`);
|
|
68
|
+
}
|
|
69
|
+
else if (key === "commands" && isObject(value)) {
|
|
70
|
+
changes.push(`comandos: ${Object.keys(value).join(", ")}`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
rest.push(key);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (rest.length > 0) {
|
|
77
|
+
changes.push(`otros ajustes: ${rest.join(", ")}`);
|
|
78
|
+
}
|
|
79
|
+
return changes;
|
|
80
|
+
}
|
|
81
|
+
function readStore() {
|
|
82
|
+
try {
|
|
83
|
+
const data = JSON.parse(fs.readFileSync(TRUST_PATH, "utf8"));
|
|
84
|
+
return isObject(data) ? data : {};
|
|
85
|
+
}
|
|
86
|
+
catch {
|
|
87
|
+
return {};
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function key(root) {
|
|
91
|
+
try {
|
|
92
|
+
return fs.realpathSync(root);
|
|
93
|
+
}
|
|
94
|
+
catch {
|
|
95
|
+
return path.resolve(root);
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
export function projectTrust(root) {
|
|
99
|
+
const files = [];
|
|
100
|
+
const changes = [];
|
|
101
|
+
const parts = [];
|
|
102
|
+
const add = (relative, text, change) => {
|
|
103
|
+
files.push(relative);
|
|
104
|
+
parts.push(`${relative}\u0000${text}`);
|
|
105
|
+
changes.push(...change.map((item) => `${relative}: ${item}`));
|
|
106
|
+
};
|
|
107
|
+
for (const relative of CONFIG_FILES) {
|
|
108
|
+
const text = readText(path.join(root, relative));
|
|
109
|
+
if (text === null) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
let data = {};
|
|
113
|
+
try {
|
|
114
|
+
data = JSON.parse(text);
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
data = {};
|
|
118
|
+
}
|
|
119
|
+
const described = isObject(data) ? describeConfig(data) : [];
|
|
120
|
+
add(relative, text, described.length > 0 ? described : ["configuración de vipcode"]);
|
|
121
|
+
}
|
|
122
|
+
for (const relative of markdownFiles(root, AGENT_DIRS)) {
|
|
123
|
+
const text = readText(path.join(root, relative)) || "";
|
|
124
|
+
const { data } = parseFrontmatter(text);
|
|
125
|
+
// Un agente que solo trae instrucciones es como un AGENTS.md: no hace falta confiar
|
|
126
|
+
if (data.permission !== undefined || data.readOnly !== undefined) {
|
|
127
|
+
add(relative, text, [`agente con permisos propios: ${short({ permission: data.permission, readOnly: data.readOnly })}`]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
for (const relative of markdownFiles(root, COMMAND_DIRS)) {
|
|
131
|
+
const text = readText(path.join(root, relative)) || "";
|
|
132
|
+
if (/!`[^`]+`/.test(text)) {
|
|
133
|
+
add(relative, text, ["comando que ejecuta órdenes en la terminal al usarlo"]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (files.length === 0) {
|
|
137
|
+
return { files, changes, fingerprint: null, trusted: true };
|
|
138
|
+
}
|
|
139
|
+
const fingerprint = crypto.createHash("sha256").update(parts.join("\u0000\u0000")).digest("hex");
|
|
140
|
+
return { files, changes, fingerprint, trusted: readStore()[key(root)]?.fingerprint === fingerprint };
|
|
141
|
+
}
|
|
142
|
+
// Confías en la configuración que trae la carpeta tal como está ahora
|
|
143
|
+
export function trustProject(root) {
|
|
144
|
+
const trust = projectTrust(root);
|
|
145
|
+
if (!trust.fingerprint) {
|
|
146
|
+
return trust;
|
|
147
|
+
}
|
|
148
|
+
const store = readStore();
|
|
149
|
+
store[key(root)] = { fingerprint: trust.fingerprint, date: new Date().toISOString() };
|
|
150
|
+
ensureHomeDir();
|
|
151
|
+
fs.writeFileSync(TRUST_PATH, JSON.stringify(store, null, 2), { mode: 0o600 });
|
|
152
|
+
return { ...trust, trusted: true };
|
|
153
|
+
}
|
|
154
|
+
export function untrustProject(root) {
|
|
155
|
+
const store = readStore();
|
|
156
|
+
if (!store[key(root)]) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
delete store[key(root)];
|
|
160
|
+
ensureHomeDir();
|
|
161
|
+
fs.writeFileSync(TRUST_PATH, JSON.stringify(store, null, 2), { mode: 0o600 });
|
|
162
|
+
return true;
|
|
163
|
+
}
|
|
164
|
+
// Ficheros de un agente o comando que están dentro del proyecto (los tuyos de ~/.vipcode no cuentan)
|
|
165
|
+
export function isProjectFile(root, file) {
|
|
166
|
+
if (!file) {
|
|
167
|
+
return false;
|
|
168
|
+
}
|
|
169
|
+
const relative = path.relative(root, file);
|
|
170
|
+
return relative !== "" && !relative.startsWith("..") && !path.isAbsolute(relative);
|
|
171
|
+
}
|