@factor_ec/ai-tools 0.1.0

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/cli.js ADDED
@@ -0,0 +1,275 @@
1
+ #!/usr/bin/env node
2
+ import fs from "node:fs";
3
+ import { parseArgs } from "node:util";
4
+ import path from "node:path";
5
+ import { fileURLToPath } from "node:url";
6
+ import process from "node:process";
7
+ import { checkbox, confirm, select } from "@inquirer/prompts";
8
+ import { AGENTS, AGENT_IDS, installBundle, isAgentId, listBundledSkillIds, describeTarget, resolveTarget, skillsDirForAgent, } from "./lib/index.js";
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ function resolvePackageRoot(entryFile) {
11
+ const entryDir = path.dirname(entryFile);
12
+ if (fs.existsSync(path.join(entryDir, "templates"))) {
13
+ return entryDir;
14
+ }
15
+ const parent = path.resolve(entryDir, "..");
16
+ if (fs.existsSync(path.join(parent, "templates"))) {
17
+ return parent;
18
+ }
19
+ return parent;
20
+ }
21
+ const packageRoot = resolvePackageRoot(__filename);
22
+ function printHelp() {
23
+ process.stderr.write(`
24
+ Uso:
25
+ ai-tools init [opciones]
26
+ ai-tools update [opciones]
27
+
28
+ Comandos:
29
+ init Asistente de instalación (o flags no interactivos)
30
+ update Sincroniza los skills incluidos en este paquete con la versión actual
31
+
32
+ Opciones:
33
+ --agent <cursor|claude-code|codex> Agente destino
34
+ --skills <id1,id2> Subconjunto de skills (por defecto: todos)
35
+ --yes, -y Sin confirmación interactiva
36
+ --dry-run Solo muestra qué haría
37
+ --force init: sobrescribe skills existentes del bundle
38
+ --user-only Fuerza instalación en el home aunque haya repo git
39
+ --project-root <ruta> Fuerza la raíz del proyecto
40
+ -h, --help Ayuda
41
+
42
+ Destino: si el cwd está en un repo Git, los skills van al proyecto; si no, al usuario (~/.cursor, ~/.claude o ~/.agents).
43
+
44
+ `);
45
+ }
46
+ function parseSkillList(raw) {
47
+ if (raw === undefined) {
48
+ return undefined;
49
+ }
50
+ const ids = raw
51
+ .split(",")
52
+ .map((s) => s.trim())
53
+ .filter(Boolean);
54
+ return ids.length ? ids : undefined;
55
+ }
56
+ function isInteractive() {
57
+ return Boolean(process.stdin.isTTY && process.stdout.isTTY);
58
+ }
59
+ async function promptAgent() {
60
+ const value = await select({
61
+ message: "¿Para qué agente instalas los skills?",
62
+ choices: AGENT_IDS.map((id) => ({
63
+ value: id,
64
+ name: `${AGENTS[id].label} (${id})`,
65
+ })),
66
+ });
67
+ return value;
68
+ }
69
+ async function promptSkills(skillIds) {
70
+ return checkbox({
71
+ message: "Selecciona los skills a instalar (espacio para marcar)",
72
+ choices: skillIds.map((id) => ({
73
+ value: id,
74
+ name: id,
75
+ checked: true,
76
+ })),
77
+ required: true,
78
+ });
79
+ }
80
+ async function promptConfirm(label, targetLabel) {
81
+ return confirm({
82
+ message: `¿Continuar? Agente: ${label}. Destino: ${targetLabel}`,
83
+ default: true,
84
+ });
85
+ }
86
+ async function runInit(opts) {
87
+ if (opts.agent !== undefined && !isAgentId(opts.agent)) {
88
+ process.stderr.write(`Agente inválido: ${opts.agent}. Valores: ${AGENT_IDS.join(", ")}.\n`);
89
+ return 1;
90
+ }
91
+ let agentId = opts.agent && isAgentId(opts.agent) ? opts.agent : undefined;
92
+ const bundled = listBundledSkillIds(packageRoot);
93
+ if (!bundled.length) {
94
+ process.stderr.write("No hay skills empaquetados en templates/.\n");
95
+ return 1;
96
+ }
97
+ if (!agentId) {
98
+ if (!isInteractive()) {
99
+ process.stderr.write("Falta --agent en modo no interactivo.\n");
100
+ return 1;
101
+ }
102
+ agentId = await promptAgent();
103
+ }
104
+ const target = resolveTarget({
105
+ cwd: opts.cwd,
106
+ userOnly: opts.userOnly,
107
+ projectRoot: opts.projectRoot,
108
+ });
109
+ let skillIds = parseSkillList(opts.skills);
110
+ if (!skillIds) {
111
+ if (isInteractive()) {
112
+ skillIds = await promptSkills(bundled);
113
+ }
114
+ else {
115
+ skillIds = bundled;
116
+ }
117
+ }
118
+ if (!opts.yes && isInteractive()) {
119
+ const ok = await promptConfirm(AGENTS[agentId].label, describeTarget(target));
120
+ if (!ok) {
121
+ process.stderr.write("Cancelado.\n");
122
+ return 0;
123
+ }
124
+ }
125
+ const result = installBundle({
126
+ command: "init",
127
+ packageRoot,
128
+ target,
129
+ agentId,
130
+ skillIds,
131
+ dryRun: opts.dryRun,
132
+ force: opts.force,
133
+ });
134
+ const base = target.kind === "project" ? target.root : target.home;
135
+ const destRoot = skillsDirForAgent(base, agentId);
136
+ if (opts.dryRun) {
137
+ process.stderr.write(`[dry-run] Copiaría ${result.copied.length} skills en ${destRoot} (${describeTarget(target)}).\n`);
138
+ }
139
+ else if (result.copied.length > 0) {
140
+ process.stderr.write(`Instalados ${result.copied.length} skills en ${destRoot} (${describeTarget(target)}).\n`);
141
+ }
142
+ for (const c of result.copied) {
143
+ process.stdout.write(`${opts.dryRun ? "[dry-run] " : "+ "}${c}\n`);
144
+ }
145
+ for (const s of result.skipped) {
146
+ process.stderr.write(`omitido: ${s.id} — ${s.reason}\n`);
147
+ }
148
+ if (result.skipped.length > 0 && !opts.force) {
149
+ process.stderr.write("\nAlgunos skills no se instalaron. Usa --force para sobrescribir o revisa los directorios.\n");
150
+ return 1;
151
+ }
152
+ return 0;
153
+ }
154
+ async function runUpdate(opts) {
155
+ if (opts.agent !== undefined && !isAgentId(opts.agent)) {
156
+ process.stderr.write(`Agente inválido: ${opts.agent}. Valores: ${AGENT_IDS.join(", ")}.\n`);
157
+ return 1;
158
+ }
159
+ let agentId = opts.agent && isAgentId(opts.agent) ? opts.agent : undefined;
160
+ const bundled = listBundledSkillIds(packageRoot);
161
+ if (!bundled.length) {
162
+ process.stderr.write("No hay skills empaquetados en templates/.\n");
163
+ return 1;
164
+ }
165
+ if (!agentId) {
166
+ if (!isInteractive()) {
167
+ process.stderr.write("Falta --agent en modo no interactivo.\n");
168
+ return 1;
169
+ }
170
+ agentId = await promptAgent();
171
+ }
172
+ const target = resolveTarget({
173
+ cwd: opts.cwd,
174
+ userOnly: opts.userOnly,
175
+ projectRoot: opts.projectRoot,
176
+ });
177
+ const skillIds = parseSkillList(opts.skills) ?? bundled;
178
+ if (!opts.yes && isInteractive()) {
179
+ const ok = await confirm({
180
+ message: `¿Sobrescribir skills del paquete para ${AGENTS[agentId].label} en ${describeTarget(target)}?`,
181
+ default: true,
182
+ });
183
+ if (!ok) {
184
+ process.stderr.write("Cancelado.\n");
185
+ return 0;
186
+ }
187
+ }
188
+ const result = installBundle({
189
+ command: "update",
190
+ packageRoot,
191
+ target,
192
+ agentId,
193
+ skillIds,
194
+ dryRun: opts.dryRun,
195
+ force: true,
196
+ });
197
+ if (opts.dryRun) {
198
+ process.stderr.write("[dry-run] Se actualizarían skills en el destino indicado.\n");
199
+ }
200
+ for (const c of result.copied) {
201
+ process.stdout.write(`${opts.dryRun ? "[dry-run] " : "= "}${c}\n`);
202
+ }
203
+ if (result.removed?.length) {
204
+ process.stderr.write(`Reemplazados ${result.removed.length} directorios de skill.\n`);
205
+ }
206
+ return 0;
207
+ }
208
+ async function main() {
209
+ let values;
210
+ let positionals;
211
+ try {
212
+ const parsed = parseArgs({
213
+ args: process.argv.slice(2),
214
+ allowPositionals: true,
215
+ options: {
216
+ agent: { type: "string" },
217
+ skills: { type: "string" },
218
+ yes: { type: "boolean", short: "y", default: false },
219
+ "dry-run": { type: "boolean", default: false },
220
+ force: { type: "boolean", default: false },
221
+ "user-only": { type: "boolean", default: false },
222
+ "project-root": { type: "string" },
223
+ help: { type: "boolean", short: "h", default: false },
224
+ },
225
+ });
226
+ values = parsed.values;
227
+ positionals = parsed.positionals;
228
+ }
229
+ catch (e) {
230
+ process.stderr.write(`${e}\n`);
231
+ printHelp();
232
+ return 1;
233
+ }
234
+ if (values.help) {
235
+ printHelp();
236
+ return 0;
237
+ }
238
+ if (positionals.length === 0) {
239
+ printHelp();
240
+ return 1;
241
+ }
242
+ const command = positionals[0];
243
+ const cwd = process.cwd();
244
+ if (command === "init") {
245
+ return runInit({
246
+ agent: values.agent,
247
+ skills: values.skills,
248
+ yes: values.yes ?? false,
249
+ dryRun: values["dry-run"] ?? false,
250
+ force: values.force ?? false,
251
+ userOnly: values["user-only"] ?? false,
252
+ projectRoot: values["project-root"],
253
+ cwd,
254
+ });
255
+ }
256
+ if (command === "update") {
257
+ return runUpdate({
258
+ agent: values.agent,
259
+ skills: values.skills,
260
+ yes: values.yes ?? false,
261
+ dryRun: values["dry-run"] ?? false,
262
+ userOnly: values["user-only"] ?? false,
263
+ projectRoot: values["project-root"],
264
+ cwd,
265
+ });
266
+ }
267
+ process.stderr.write(`Comando desconocido: ${command}\n`);
268
+ printHelp();
269
+ return 1;
270
+ }
271
+ main().then((code) => process.exit(code), (err) => {
272
+ process.stderr.write(`${err instanceof Error ? err.message : err}\n`);
273
+ process.exit(1);
274
+ });
275
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1,9 @@
1
+ export type AgentId = "cursor" | "claude-code" | "codex";
2
+ export declare const AGENT_IDS: readonly AgentId[];
3
+ export declare const AGENTS: Record<AgentId, {
4
+ label: string;
5
+ skillPathParts: readonly string[];
6
+ }>;
7
+ export declare function isAgentId(value: string): value is AgentId;
8
+ export declare function skillsDirForAgent(baseDir: string, agentId: AgentId): string;
9
+ //# sourceMappingURL=agents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/lib/agents.ts"],"names":[],"mappings":"AAEA,MAAM,MAAM,OAAO,GAAG,QAAQ,GAAG,aAAa,GAAG,OAAO,CAAC;AAEzD,eAAO,MAAM,SAAS,EAAE,SAAS,OAAO,EAI9B,CAAC;AAEX,eAAO,MAAM,MAAM,EAAE,MAAM,CACzB,OAAO,EACP;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,cAAc,EAAE,SAAS,MAAM,EAAE,CAAA;CAAE,CAcrD,CAAC;AAEF,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,KAAK,IAAI,OAAO,CAEzD;AAED,wBAAgB,iBAAiB,CAC/B,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,OAAO,GACf,MAAM,CAGR"}
package/lib/agents.js ADDED
@@ -0,0 +1,28 @@
1
+ import path from "node:path";
2
+ export const AGENT_IDS = [
3
+ "cursor",
4
+ "claude-code",
5
+ "codex",
6
+ ];
7
+ export const AGENTS = {
8
+ cursor: {
9
+ label: "Cursor",
10
+ skillPathParts: [".cursor", "skills"],
11
+ },
12
+ "claude-code": {
13
+ label: "Claude Code",
14
+ skillPathParts: [".claude", "skills"],
15
+ },
16
+ codex: {
17
+ label: "Codex",
18
+ skillPathParts: [".agents", "skills"],
19
+ },
20
+ };
21
+ export function isAgentId(value) {
22
+ return AGENT_IDS.includes(value);
23
+ }
24
+ export function skillsDirForAgent(baseDir, agentId) {
25
+ const { skillPathParts } = AGENTS[agentId];
26
+ return path.join(baseDir, ...skillPathParts);
27
+ }
28
+ //# sourceMappingURL=agents.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agents.js","sourceRoot":"","sources":["../../src/lib/agents.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAI7B,MAAM,CAAC,MAAM,SAAS,GAAuB;IAC3C,QAAQ;IACR,aAAa;IACb,OAAO;CACC,CAAC;AAEX,MAAM,CAAC,MAAM,MAAM,GAGf;IACF,MAAM,EAAE;QACN,KAAK,EAAE,QAAQ;QACf,cAAc,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;KACtC;IACD,aAAa,EAAE;QACb,KAAK,EAAE,aAAa;QACpB,cAAc,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;KACtC;IACD,KAAK,EAAE;QACL,KAAK,EAAE,OAAO;QACd,cAAc,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC;KACtC;CACF,CAAC;AAEF,MAAM,UAAU,SAAS,CAAC,KAAa;IACrC,OAAQ,SAA+B,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;AAC1D,CAAC;AAED,MAAM,UAAU,iBAAiB,CAC/B,OAAe,EACf,OAAgB;IAEhB,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,CAAC,OAAO,CAAC,CAAC;IAC3C,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,cAAc,CAAC,CAAC;AAC/C,CAAC"}
package/lib/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ export type { AgentId } from "./agents.js";
2
+ export { AGENTS, AGENT_IDS, isAgentId, skillsDirForAgent, } from "./agents.js";
3
+ export { describeTarget, resolveTarget, type ResolvedTarget, type ResolveTargetOptions, } from "./resolve-target.js";
4
+ export { installBundle, listBundledSkillIds, type InstallBundleOptions, type InstallBundleResult, type InstallCommand, } from "./install.js";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EACL,MAAM,EACN,SAAS,EACT,SAAS,EACT,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,cAAc,EACd,aAAa,EACb,KAAK,cAAc,EACnB,KAAK,oBAAoB,GAC1B,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,mBAAmB,EACnB,KAAK,oBAAoB,EACzB,KAAK,mBAAmB,EACxB,KAAK,cAAc,GACpB,MAAM,cAAc,CAAC"}
package/lib/index.js ADDED
@@ -0,0 +1,4 @@
1
+ export { AGENTS, AGENT_IDS, isAgentId, skillsDirForAgent, } from "./agents.js";
2
+ export { describeTarget, resolveTarget, } from "./resolve-target.js";
3
+ export { installBundle, listBundledSkillIds, } from "./install.js";
4
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/lib/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,MAAM,EACN,SAAS,EACT,SAAS,EACT,iBAAiB,GAClB,MAAM,aAAa,CAAC;AACrB,OAAO,EACL,cAAc,EACd,aAAa,GAGd,MAAM,qBAAqB,CAAC;AAC7B,OAAO,EACL,aAAa,EACb,mBAAmB,GAIpB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,24 @@
1
+ import type { AgentId } from "./agents.js";
2
+ import type { ResolvedTarget } from "./resolve-target.js";
3
+ export type InstallCommand = "init" | "update";
4
+ export type InstallBundleOptions = {
5
+ command: InstallCommand;
6
+ packageRoot: string;
7
+ target: ResolvedTarget;
8
+ agentId: AgentId;
9
+ skillIds: string[] | undefined;
10
+ dryRun: boolean;
11
+ /** For init: allow overwriting existing skill dirs */
12
+ force: boolean;
13
+ };
14
+ export type InstallBundleResult = {
15
+ copied: string[];
16
+ skipped: {
17
+ id: string;
18
+ reason: string;
19
+ }[];
20
+ removed?: string[];
21
+ };
22
+ export declare function listBundledSkillIds(packageRoot: string): string[];
23
+ export declare function installBundle(options: InstallBundleOptions): InstallBundleResult;
24
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../../src/lib/install.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAE3C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,MAAM,cAAc,GAAG,MAAM,GAAG,QAAQ,CAAC;AAE/C,MAAM,MAAM,oBAAoB,GAAG;IACjC,OAAO,EAAE,cAAc,CAAC;IACxB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,cAAc,CAAC;IACvB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;IAC/B,MAAM,EAAE,OAAO,CAAC;IAChB,sDAAsD;IACtD,KAAK,EAAE,OAAO,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,mBAAmB,GAAG;IAChC,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,OAAO,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;IAC1C,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;CACpB,CAAC;AAEF,wBAAgB,mBAAmB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,EAAE,CAUjE;AA2BD,wBAAgB,aAAa,CAC3B,OAAO,EAAE,oBAAoB,GAC5B,mBAAmB,CAqErB"}
package/lib/install.js ADDED
@@ -0,0 +1,84 @@
1
+ import fs from "node:fs";
2
+ import path from "node:path";
3
+ import { skillsDirForAgent } from "./agents.js";
4
+ export function listBundledSkillIds(packageRoot) {
5
+ const templatesRoot = path.join(packageRoot, "templates");
6
+ if (!fs.existsSync(templatesRoot)) {
7
+ return [];
8
+ }
9
+ return fs
10
+ .readdirSync(templatesRoot, { withFileTypes: true })
11
+ .filter((d) => d.isDirectory())
12
+ .map((d) => d.name)
13
+ .sort();
14
+ }
15
+ function templateDir(packageRoot, skillId) {
16
+ return path.join(packageRoot, "templates", skillId);
17
+ }
18
+ function assertTemplateExists(packageRoot, skillId) {
19
+ const skillMd = path.join(templateDir(packageRoot, skillId), "SKILL.md");
20
+ if (!fs.existsSync(skillMd)) {
21
+ throw new Error(`Plantilla incompleta: falta ${skillMd}`);
22
+ }
23
+ }
24
+ function skillDestination(target, agentId, skillId) {
25
+ const base = target.kind === "project" ? target.root : target.home;
26
+ const skillsRoot = skillsDirForAgent(base, agentId);
27
+ return path.join(skillsRoot, skillId);
28
+ }
29
+ function hasExistingSkill(destDir) {
30
+ return fs.existsSync(path.join(destDir, "SKILL.md"));
31
+ }
32
+ export function installBundle(options) {
33
+ const allIds = listBundledSkillIds(options.packageRoot);
34
+ if (allIds.length === 0) {
35
+ throw new Error(`No hay plantillas en ${path.join(options.packageRoot, "templates")}`);
36
+ }
37
+ const selected = options.skillIds && options.skillIds.length > 0
38
+ ? options.skillIds
39
+ : allIds;
40
+ for (const id of selected) {
41
+ if (!allIds.includes(id)) {
42
+ throw new Error(`Skill desconocido: ${id}`);
43
+ }
44
+ assertTemplateExists(options.packageRoot, id);
45
+ }
46
+ const copied = [];
47
+ const skipped = [];
48
+ const removed = [];
49
+ const base = options.target.kind === "project" ? options.target.root : options.target.home;
50
+ const skillsRoot = skillsDirForAgent(base, options.agentId);
51
+ if (!options.dryRun) {
52
+ fs.mkdirSync(skillsRoot, { recursive: true });
53
+ }
54
+ for (const skillId of selected) {
55
+ const src = templateDir(options.packageRoot, skillId);
56
+ const dest = skillDestination(options.target, options.agentId, skillId);
57
+ if (options.command === "init") {
58
+ if (hasExistingSkill(dest) && !options.force) {
59
+ skipped.push({
60
+ id: skillId,
61
+ reason: `ya existe ${path.join(dest, "SKILL.md")} (usa --force para sobrescribir)`,
62
+ });
63
+ continue;
64
+ }
65
+ if (options.force && !options.dryRun && fs.existsSync(dest)) {
66
+ fs.rmSync(dest, { recursive: true, force: true });
67
+ }
68
+ }
69
+ if (options.command === "update") {
70
+ if (!options.dryRun && fs.existsSync(dest)) {
71
+ fs.rmSync(dest, { recursive: true, force: true });
72
+ removed.push(dest);
73
+ }
74
+ }
75
+ if (options.dryRun) {
76
+ copied.push(dest);
77
+ continue;
78
+ }
79
+ fs.cpSync(src, dest, { recursive: true });
80
+ copied.push(dest);
81
+ }
82
+ return { copied, skipped, removed: removed.length ? removed : undefined };
83
+ }
84
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/lib/install.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ export type ResolvedTarget = {
2
+ kind: "project";
3
+ root: string;
4
+ } | {
5
+ kind: "user";
6
+ home: string;
7
+ };
8
+ export type ResolveTargetOptions = {
9
+ cwd: string;
10
+ userOnly?: boolean;
11
+ projectRoot?: string;
12
+ };
13
+ export declare function resolveTarget(options: ResolveTargetOptions): ResolvedTarget;
14
+ export declare function describeTarget(target: ResolvedTarget): string;
15
+ //# sourceMappingURL=resolve-target.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-target.d.ts","sourceRoot":"","sources":["../../src/lib/resolve-target.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,cAAc,GACtB;IAAE,IAAI,EAAE,SAAS,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACjC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAAC;AAEnC,MAAM,MAAM,oBAAoB,GAAG;IACjC,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,wBAAgB,aAAa,CAAC,OAAO,EAAE,oBAAoB,GAAG,cAAc,CAyB3E;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,cAAc,GAAG,MAAM,CAK7D"}
@@ -0,0 +1,33 @@
1
+ import { execFileSync } from "node:child_process";
2
+ import os from "node:os";
3
+ import path from "node:path";
4
+ export function resolveTarget(options) {
5
+ const home = os.homedir();
6
+ if (options.userOnly) {
7
+ return { kind: "user", home };
8
+ }
9
+ if (options.projectRoot) {
10
+ return { kind: "project", root: path.resolve(options.projectRoot) };
11
+ }
12
+ try {
13
+ const root = execFileSync("git", ["rev-parse", "--show-toplevel"], {
14
+ cwd: options.cwd,
15
+ encoding: "utf8",
16
+ stdio: ["ignore", "pipe", "ignore"],
17
+ }).trim();
18
+ if (root) {
19
+ return { kind: "project", root };
20
+ }
21
+ }
22
+ catch {
23
+ // not inside a git work tree
24
+ }
25
+ return { kind: "user", home };
26
+ }
27
+ export function describeTarget(target) {
28
+ if (target.kind === "project") {
29
+ return `proyecto: ${target.root}`;
30
+ }
31
+ return `usuario (home): ${target.home}`;
32
+ }
33
+ //# sourceMappingURL=resolve-target.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve-target.js","sourceRoot":"","sources":["../../src/lib/resolve-target.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAW7B,MAAM,UAAU,aAAa,CAAC,OAA6B;IACzD,MAAM,IAAI,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC;IAE1B,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;IAChC,CAAC;IAED,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;QACxB,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;IACtE,CAAC;IAED,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,iBAAiB,CAAC,EAAE;YACjE,GAAG,EAAE,OAAO,CAAC,GAAG;YAChB,QAAQ,EAAE,MAAM;YAChB,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAC;SACpC,CAAC,CAAC,IAAI,EAAE,CAAC;QACV,IAAI,IAAI,EAAE,CAAC;YACT,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC;QACnC,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,6BAA6B;IAC/B,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAChC,CAAC;AAED,MAAM,UAAU,cAAc,CAAC,MAAsB;IACnD,IAAI,MAAM,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;QAC9B,OAAO,aAAa,MAAM,CAAC,IAAI,EAAE,CAAC;IACpC,CAAC;IACD,OAAO,mBAAmB,MAAM,CAAC,IAAI,EAAE,CAAC;AAC1C,CAAC"}
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@factor_ec/ai-tools",
3
+ "version": "0.1.0",
4
+ "description": "CLI para instalar skills de desarrollo en Cursor, Claude Code y Codex (init / update).",
5
+ "type": "module",
6
+ "main": "./lib/index.js",
7
+ "types": "./lib/index.d.ts",
8
+ "bin": {
9
+ "ai-tools": "./cli.js"
10
+ },
11
+ "files": [
12
+ "lib",
13
+ "cli.js",
14
+ "templates"
15
+ ],
16
+ "engines": {
17
+ "node": ">=20"
18
+ },
19
+ "keywords": [
20
+ "cursor",
21
+ "claude",
22
+ "codex",
23
+ "skills",
24
+ "cli"
25
+ ],
26
+ "publishConfig": {
27
+ "access": "public"
28
+ },
29
+ "author": "Factor",
30
+ "license": "CC-BY-NC-ND-4.0",
31
+ "dependencies": {
32
+ "@inquirer/prompts": "^7.2.1"
33
+ }
34
+ }