alegra-data-agent 0.2.2 → 0.2.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/dist/installer.js +112 -6
- package/dist/lib.js +26 -3
- package/dist/render.js +18 -1
- package/dist/targets.js +6 -6
- package/package.json +1 -1
package/dist/installer.js
CHANGED
|
@@ -3,7 +3,7 @@ import { copyFileSync, existsSync, readFileSync, renameSync, rmSync, writeFileSy
|
|
|
3
3
|
import { dirname, join, resolve, sep } from "node:path";
|
|
4
4
|
import { fetchManifest, fetchSkillFile } from "./api.js";
|
|
5
5
|
import { dim, gray, green, logError, red, yellow } from "./colors.js";
|
|
6
|
-
import { ensureDir, getLockFilePath, getPackageVersion, readLockFile, sha256File, writeLockFile, } from "./lib.js";
|
|
6
|
+
import { adaptStdioCommand, ensureDir, getLockFilePath, getAntigravityLegacyMcpConfigPath, getAntigravityLegacySkillsDir, getClaudeSettingsPath, getCursorLegacyRulesDir, getOpenCodeLegacyPromptsDir, getPackageVersion, readLockFile, sha256File, writeLockFile, } from "./lib.js";
|
|
7
7
|
import { inlineReferences, renderMcpForTarget } from "./render.js";
|
|
8
8
|
import { TARGETS, detectInstalledTargets } from "./targets.js";
|
|
9
9
|
const SKILL_NAME_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
@@ -34,7 +34,11 @@ function validateRelPath(rel) {
|
|
|
34
34
|
}
|
|
35
35
|
function mcpConfigHash(mcp) {
|
|
36
36
|
const salient = JSON.stringify({
|
|
37
|
-
|
|
37
|
+
transport: mcp.transport ?? "http",
|
|
38
|
+
url: mcp.url ?? null,
|
|
39
|
+
command: mcp.command ?? null,
|
|
40
|
+
args: mcp.args ?? null,
|
|
41
|
+
env: mcp.env ?? null,
|
|
38
42
|
type: mcp.auth.type,
|
|
39
43
|
tokenEnv: mcp.auth.tokenEnv ?? null,
|
|
40
44
|
});
|
|
@@ -99,7 +103,7 @@ function writeSkillToTarget(skillName, staged, spec) {
|
|
|
99
103
|
}
|
|
100
104
|
return;
|
|
101
105
|
}
|
|
102
|
-
const entry = staged.find((f) => f.rel === "SKILL.md"
|
|
106
|
+
const entry = staged.find((f) => f.rel === "SKILL.md") ?? staged.find((f) => f.rel === "README.md");
|
|
103
107
|
if (!entry) {
|
|
104
108
|
throw new Error(`Para target ${spec.id} se requiere SKILL.md o README.md en la skill`);
|
|
105
109
|
}
|
|
@@ -144,11 +148,31 @@ function parseFrontmatterMinimal(content) {
|
|
|
144
148
|
}
|
|
145
149
|
return out;
|
|
146
150
|
}
|
|
151
|
+
function sleepSync(ms) {
|
|
152
|
+
Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, ms);
|
|
153
|
+
}
|
|
147
154
|
function atomicWriteFile(path, content) {
|
|
148
155
|
ensureDir(dirname(path));
|
|
149
156
|
const tmp = `${path}.${process.pid}.tmp`;
|
|
150
157
|
writeFileSync(tmp, content);
|
|
151
|
-
|
|
158
|
+
for (let attempt = 0;; attempt++) {
|
|
159
|
+
try {
|
|
160
|
+
renameSync(tmp, path);
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
catch (err) {
|
|
164
|
+
const code = err.code;
|
|
165
|
+
if (attempt < 4 && (code === "EPERM" || code === "EBUSY" || code === "EACCES")) {
|
|
166
|
+
sleepSync(150);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
rmSync(tmp, { force: true });
|
|
171
|
+
}
|
|
172
|
+
catch { }
|
|
173
|
+
throw err;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
152
176
|
}
|
|
153
177
|
function backupIfExists(path) {
|
|
154
178
|
if (!existsSync(path))
|
|
@@ -199,7 +223,20 @@ function tomlBasicString(s) {
|
|
|
199
223
|
return `"${s.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
|
|
200
224
|
}
|
|
201
225
|
export function renderMcpToml(mcp) {
|
|
202
|
-
|
|
226
|
+
if (mcp.transport === "stdio") {
|
|
227
|
+
const { command, args } = adaptStdioCommand(mcp.command ?? "", mcp.args ?? []);
|
|
228
|
+
const lines = [`[mcp_servers.${mcp.name}]`, `command = ${tomlBasicString(command)}`];
|
|
229
|
+
if (args.length > 0) {
|
|
230
|
+
lines.push(`args = [${args.map((a) => tomlBasicString(a)).join(", ")}]`);
|
|
231
|
+
}
|
|
232
|
+
if (mcp.env && Object.keys(mcp.env).length > 0) {
|
|
233
|
+
lines.push(`[mcp_servers.${mcp.name}.env]`);
|
|
234
|
+
for (const [k, v] of Object.entries(mcp.env))
|
|
235
|
+
lines.push(`${k} = ${tomlBasicString(v)}`);
|
|
236
|
+
}
|
|
237
|
+
return lines.join("\n");
|
|
238
|
+
}
|
|
239
|
+
const lines = [`[mcp_servers.${mcp.name}]`, `url = ${tomlBasicString(mcp.url ?? "")}`];
|
|
203
240
|
if (mcp.auth.type === "gateway") {
|
|
204
241
|
if (!mcp.auth.tokenEnv) {
|
|
205
242
|
throw new Error(`MCP '${mcp.name}' es type=gateway pero no trae tokenEnv`);
|
|
@@ -271,7 +308,76 @@ function resolveTargets(opts) {
|
|
|
271
308
|
if (ids.length === 0) {
|
|
272
309
|
ids.push("claude-code");
|
|
273
310
|
}
|
|
274
|
-
|
|
311
|
+
const specs = ids.map((id) => TARGETS[id]);
|
|
312
|
+
for (const spec of specs)
|
|
313
|
+
cleanupLegacySkillArtifacts(spec);
|
|
314
|
+
return specs;
|
|
315
|
+
}
|
|
316
|
+
const LEGACY_RENAMED_SKILLS = ["alanube", "alegra-producto", "alegra-ce-universe"];
|
|
317
|
+
function stripMcpEntries(path, names) {
|
|
318
|
+
if (!existsSync(path) || names.length === 0)
|
|
319
|
+
return;
|
|
320
|
+
let cfg;
|
|
321
|
+
try {
|
|
322
|
+
cfg = JSON.parse(readFileSync(path, "utf-8"));
|
|
323
|
+
}
|
|
324
|
+
catch {
|
|
325
|
+
return;
|
|
326
|
+
}
|
|
327
|
+
let changed = false;
|
|
328
|
+
for (const key of ["mcpServers", "mcp"]) {
|
|
329
|
+
const section = cfg[key];
|
|
330
|
+
if (!section || typeof section !== "object")
|
|
331
|
+
continue;
|
|
332
|
+
for (const n of names) {
|
|
333
|
+
if (n in section) {
|
|
334
|
+
delete section[n];
|
|
335
|
+
changed = true;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
if (Object.keys(section).length === 0)
|
|
339
|
+
delete cfg[key];
|
|
340
|
+
}
|
|
341
|
+
if (!changed)
|
|
342
|
+
return;
|
|
343
|
+
backupIfExists(path);
|
|
344
|
+
atomicWriteFile(path, `${JSON.stringify(cfg, null, 2)}\n`);
|
|
345
|
+
}
|
|
346
|
+
function cleanupLegacySkillArtifacts(spec) {
|
|
347
|
+
try {
|
|
348
|
+
if (spec.skillFormat === "folder") {
|
|
349
|
+
for (const old of LEGACY_RENAMED_SKILLS) {
|
|
350
|
+
const dir = join(spec.skillsDir, old);
|
|
351
|
+
if (existsSync(dir))
|
|
352
|
+
rmSync(dir, { recursive: true, force: true });
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
const lock = readLockFile();
|
|
356
|
+
if (spec.id === "opencode" || spec.id === "cursor") {
|
|
357
|
+
const legacyDir = spec.id === "opencode" ? getOpenCodeLegacyPromptsDir() : getCursorLegacyRulesDir();
|
|
358
|
+
const ext = spec.id === "opencode" ? ".md" : ".mdc";
|
|
359
|
+
const managed = [...Object.keys(lock.skills), ...LEGACY_RENAMED_SKILLS];
|
|
360
|
+
for (const name of managed) {
|
|
361
|
+
const f = join(legacyDir, `${name}${ext}`);
|
|
362
|
+
if (existsSync(f))
|
|
363
|
+
rmSync(f, { force: true });
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
const ourMcps = Object.keys(lock.mcps ?? {});
|
|
367
|
+
if (spec.id === "claude-code") {
|
|
368
|
+
stripMcpEntries(getClaudeSettingsPath(), ourMcps);
|
|
369
|
+
}
|
|
370
|
+
if (spec.id === "antigravity") {
|
|
371
|
+
for (const name of [...Object.keys(lock.skills), ...LEGACY_RENAMED_SKILLS]) {
|
|
372
|
+
const d = join(getAntigravityLegacySkillsDir(), name);
|
|
373
|
+
if (existsSync(d))
|
|
374
|
+
rmSync(d, { recursive: true, force: true });
|
|
375
|
+
}
|
|
376
|
+
stripMcpEntries(getAntigravityLegacyMcpConfigPath(), ourMcps);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
catch {
|
|
380
|
+
}
|
|
275
381
|
}
|
|
276
382
|
export async function installSkill(name, manifest, opts = {}) {
|
|
277
383
|
const entry = manifest.skills[name];
|
package/dist/lib.js
CHANGED
|
@@ -31,13 +31,24 @@ export function getClaudeSkillsDir() {
|
|
|
31
31
|
export function getClaudeSettingsPath() {
|
|
32
32
|
return join(homedir(), ".claude", "settings.json");
|
|
33
33
|
}
|
|
34
|
+
export function getClaudeJsonPath() {
|
|
35
|
+
return join(homedir(), ".claude.json");
|
|
36
|
+
}
|
|
34
37
|
export function getCursorSkillsDir() {
|
|
38
|
+
return join(homedir(), ".cursor", "skills");
|
|
39
|
+
}
|
|
40
|
+
export function getCursorLegacyRulesDir() {
|
|
35
41
|
return join(homedir(), ".cursor", "rules");
|
|
36
42
|
}
|
|
37
43
|
export function getCursorMcpPath() {
|
|
38
44
|
return join(homedir(), ".cursor", "mcp.json");
|
|
39
45
|
}
|
|
40
46
|
export function getOpenCodeSkillsDir() {
|
|
47
|
+
const xdgHome = process.env.XDG_CONFIG_HOME;
|
|
48
|
+
const base = xdgHome && xdgHome.length > 0 ? xdgHome : join(homedir(), ".config");
|
|
49
|
+
return join(base, "opencode", "skills");
|
|
50
|
+
}
|
|
51
|
+
export function getOpenCodeLegacyPromptsDir() {
|
|
41
52
|
const xdgHome = process.env.XDG_CONFIG_HOME;
|
|
42
53
|
const base = xdgHome && xdgHome.length > 0 ? xdgHome : join(homedir(), ".config");
|
|
43
54
|
return join(base, "opencode", "prompts");
|
|
@@ -48,9 +59,15 @@ export function getOpenCodeConfigPath() {
|
|
|
48
59
|
return join(base, "opencode", "opencode.json");
|
|
49
60
|
}
|
|
50
61
|
export function getAntigravitySkillsDir() {
|
|
62
|
+
return join(homedir(), ".gemini", "antigravity", "skills");
|
|
63
|
+
}
|
|
64
|
+
export function getAntigravityMcpConfigPath() {
|
|
65
|
+
return join(homedir(), ".gemini", "antigravity", "mcp_config.json");
|
|
66
|
+
}
|
|
67
|
+
export function getAntigravityLegacySkillsDir() {
|
|
51
68
|
return join(homedir(), ".antigravity", "skills");
|
|
52
69
|
}
|
|
53
|
-
export function
|
|
70
|
+
export function getAntigravityLegacyMcpConfigPath() {
|
|
54
71
|
return join(homedir(), ".antigravity", "settings.json");
|
|
55
72
|
}
|
|
56
73
|
export function getCodexSkillsDir() {
|
|
@@ -78,13 +95,13 @@ export function getTargetSkillsDir(target) {
|
|
|
78
95
|
export function getTargetMcpConfigPath(target) {
|
|
79
96
|
switch (target) {
|
|
80
97
|
case "claude-code":
|
|
81
|
-
return
|
|
98
|
+
return getClaudeJsonPath();
|
|
82
99
|
case "cursor":
|
|
83
100
|
return getCursorMcpPath();
|
|
84
101
|
case "opencode":
|
|
85
102
|
return getOpenCodeConfigPath();
|
|
86
103
|
case "antigravity":
|
|
87
|
-
return
|
|
104
|
+
return getAntigravityMcpConfigPath();
|
|
88
105
|
case "codex":
|
|
89
106
|
return getCodexConfigPath();
|
|
90
107
|
}
|
|
@@ -236,3 +253,9 @@ export function ensureDir(path) {
|
|
|
236
253
|
if (!existsSync(path))
|
|
237
254
|
mkdirSync(path, { recursive: true });
|
|
238
255
|
}
|
|
256
|
+
export function adaptStdioCommand(command, args, platform = process.platform) {
|
|
257
|
+
if (platform === "win32" && (command === "npx" || command === "npm" || command === "pnpm")) {
|
|
258
|
+
return { command: "cmd", args: ["/c", command, ...args] };
|
|
259
|
+
}
|
|
260
|
+
return { command, args };
|
|
261
|
+
}
|
package/dist/render.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { extname, join } from "node:path";
|
|
3
|
-
import { parseFrontmatter } from "./lib.js";
|
|
3
|
+
import { adaptStdioCommand, parseFrontmatter } from "./lib.js";
|
|
4
4
|
function readSkillEntryPoint(skillDir) {
|
|
5
5
|
const candidates = ["SKILL.md", "README.md"];
|
|
6
6
|
for (const c of candidates) {
|
|
@@ -71,6 +71,9 @@ export function inlineReferences(refs) {
|
|
|
71
71
|
return `\n\n---\n\n# Referencias (incluidas inline)\n\n> Este cliente instala la skill como un solo archivo; el contenido de \`references/\` se incluye acá para que las menciones del cuerpo sigan disponibles.\n\n${sections.join("\n\n")}\n`;
|
|
72
72
|
}
|
|
73
73
|
export function renderMcpForTarget(mcp, spec) {
|
|
74
|
+
if (mcp.transport === "stdio") {
|
|
75
|
+
return renderStdioMcpForTarget(mcp, spec);
|
|
76
|
+
}
|
|
74
77
|
const obj = {
|
|
75
78
|
[spec.mcpUrlKey]: mcp.url,
|
|
76
79
|
};
|
|
@@ -88,6 +91,20 @@ export function renderMcpForTarget(mcp, spec) {
|
|
|
88
91
|
}
|
|
89
92
|
return obj;
|
|
90
93
|
}
|
|
94
|
+
function renderStdioMcpForTarget(mcp, spec) {
|
|
95
|
+
const { command, args } = adaptStdioCommand(mcp.command ?? "", mcp.args ?? []);
|
|
96
|
+
const hasEnv = mcp.env && Object.keys(mcp.env).length > 0;
|
|
97
|
+
if (spec.id === "opencode") {
|
|
98
|
+
const obj = { type: "local", command: [command, ...args], enabled: true };
|
|
99
|
+
if (hasEnv)
|
|
100
|
+
obj.environment = mcp.env;
|
|
101
|
+
return obj;
|
|
102
|
+
}
|
|
103
|
+
const obj = { command, args };
|
|
104
|
+
if (hasEnv)
|
|
105
|
+
obj.env = mcp.env;
|
|
106
|
+
return obj;
|
|
107
|
+
}
|
|
91
108
|
function bearerInterpolation(env, target) {
|
|
92
109
|
switch (target) {
|
|
93
110
|
case "claude-code":
|
package/dist/targets.js
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import {
|
|
4
|
+
import { getAntigravityMcpConfigPath, getAntigravitySkillsDir, getClaudeJsonPath, getClaudeSkillsDir, getCodexConfigPath, getCodexSkillsDir, getCursorMcpPath, getCursorSkillsDir, getOpenCodeConfigPath, getOpenCodeSkillsDir, } from "./lib.js";
|
|
5
5
|
export const TARGETS = {
|
|
6
6
|
"claude-code": {
|
|
7
7
|
id: "claude-code",
|
|
8
8
|
label: "Claude Code",
|
|
9
9
|
skillsDir: getClaudeSkillsDir(),
|
|
10
10
|
skillFormat: "folder",
|
|
11
|
-
mcpConfigPath:
|
|
11
|
+
mcpConfigPath: getClaudeJsonPath(),
|
|
12
12
|
mcpRootKey: "mcpServers",
|
|
13
13
|
mcpUrlKey: "url",
|
|
14
14
|
},
|
|
@@ -16,7 +16,7 @@ export const TARGETS = {
|
|
|
16
16
|
id: "cursor",
|
|
17
17
|
label: "Cursor",
|
|
18
18
|
skillsDir: getCursorSkillsDir(),
|
|
19
|
-
skillFormat: "
|
|
19
|
+
skillFormat: "folder",
|
|
20
20
|
mcpConfigPath: getCursorMcpPath(),
|
|
21
21
|
mcpRootKey: "mcpServers",
|
|
22
22
|
mcpUrlKey: "url",
|
|
@@ -25,7 +25,7 @@ export const TARGETS = {
|
|
|
25
25
|
id: "opencode",
|
|
26
26
|
label: "OpenCode",
|
|
27
27
|
skillsDir: getOpenCodeSkillsDir(),
|
|
28
|
-
skillFormat: "
|
|
28
|
+
skillFormat: "folder",
|
|
29
29
|
mcpConfigPath: getOpenCodeConfigPath(),
|
|
30
30
|
mcpRootKey: "mcp",
|
|
31
31
|
mcpUrlKey: "url",
|
|
@@ -36,7 +36,7 @@ export const TARGETS = {
|
|
|
36
36
|
label: "Antigravity",
|
|
37
37
|
skillsDir: getAntigravitySkillsDir(),
|
|
38
38
|
skillFormat: "folder",
|
|
39
|
-
mcpConfigPath:
|
|
39
|
+
mcpConfigPath: getAntigravityMcpConfigPath(),
|
|
40
40
|
mcpRootKey: "mcpServers",
|
|
41
41
|
mcpUrlKey: "serverUrl",
|
|
42
42
|
},
|
|
@@ -63,7 +63,7 @@ export function detectInstalledTargets() {
|
|
|
63
63
|
"claude-code": join(home, ".claude"),
|
|
64
64
|
cursor: join(home, ".cursor"),
|
|
65
65
|
opencode: join(xdgConfig, "opencode"),
|
|
66
|
-
antigravity: join(home, ".antigravity"),
|
|
66
|
+
antigravity: join(home, ".gemini", "antigravity"),
|
|
67
67
|
codex: codexHome,
|
|
68
68
|
};
|
|
69
69
|
const out = [];
|