@eve-horizon/cli 0.2.17 → 0.2.19

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.
Files changed (3) hide show
  1. package/README.md +1 -0
  2. package/dist/index.js +129 -20
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -111,6 +111,7 @@ eve org update org_xxx --name "New Name"
111
111
  ### Projects
112
112
 
113
113
  ```bash
114
+ eve project ensure --name my-project --slug MyProj
114
115
  eve project ensure --name my-project --slug MyProj --repo-url https://github.com/org/repo
115
116
  eve project list
116
117
  eve project get proj_xxx
package/dist/index.js CHANGED
@@ -48850,16 +48850,17 @@ var HELP = {
48850
48850
  },
48851
48851
  ensure: {
48852
48852
  description: "Create project if it doesn't exist, or return existing",
48853
- usage: "eve project ensure --name <name> --repo-url <url> [--org <org_id>] [--branch <branch>] [--slug <slug>]",
48853
+ usage: "eve project ensure --name <name> [--repo-url <url>] [--org <org_id>] [--branch <branch>] [--slug <slug>]",
48854
48854
  options: [
48855
48855
  "--name <name> Project name (required)",
48856
- "--repo-url <url> Git repository URL (required)",
48856
+ "--repo-url <url> Git repository URL (optional, can be set later)",
48857
48857
  "--org <id> Organization ID",
48858
48858
  "--branch <branch> Default branch (default: main)",
48859
48859
  "--slug <slug> Short memorable slug (4-8 chars, e.g., MyProj)",
48860
48860
  "--force Re-clone repo even if project exists"
48861
48861
  ],
48862
48862
  examples: [
48863
+ "eve project ensure --name my-app --slug MyApp",
48863
48864
  "eve project ensure --name my-app --slug MyApp --repo-url https://github.com/org/repo",
48864
48865
  "eve project ensure --name my-app --repo-url file:///path/to/repo --force # dev/test only"
48865
48866
  ]
@@ -50901,7 +50902,7 @@ function showMainHelp() {
50901
50902
  console.log("");
50902
50903
  console.log("Examples:");
50903
50904
  console.log(' eve org ensure "My Company"');
50904
- console.log(" eve project ensure --name my-app --slug MyApp --repo-url https://github.com/org/repo");
50905
+ console.log(" eve project ensure --name my-app --slug MyApp");
50905
50906
  console.log(' eve job create --description "Fix the bug in auth.ts"');
50906
50907
  console.log(" eve job list --phase ready");
50907
50908
  console.log(" eve job show MyProj-abc123");
@@ -51300,18 +51301,19 @@ async function handleProject(subcommand, positionals, flags, context2) {
51300
51301
  switch (subcommand) {
51301
51302
  case "ensure": {
51302
51303
  const name = typeof flags.name === "string" ? flags.name : "";
51303
- const repoUrl = typeof flags["repo-url"] === "string" ? flags["repo-url"] : "";
51304
+ const repoUrl = typeof flags["repo-url"] === "string" ? flags["repo-url"] : void 0;
51304
51305
  const branch = typeof flags.branch === "string" ? flags.branch : "main";
51305
51306
  const slug = typeof flags.slug === "string" ? flags.slug : void 0;
51306
51307
  const orgIdRaw = typeof flags.org === "string" ? flags.org : context2.orgId;
51307
51308
  const force = toBoolean(flags.force) ?? false;
51308
- if (!name || !repoUrl) {
51309
- throw new Error("Usage: eve project ensure --name <name> --repo-url <url> [--branch <branch>] [--slug <slug>]");
51309
+ if (!name) {
51310
+ throw new Error("Usage: eve project ensure --name <name> [--repo-url <url>] [--branch <branch>] [--slug <slug>]");
51310
51311
  }
51311
51312
  if (!orgIdRaw) {
51312
51313
  throw new Error("Missing org id. Provide --org or set a profile default.");
51313
51314
  }
51314
- const body = { org_id: orgIdRaw, name, repo_url: repoUrl, branch, force };
51315
+ const body = { org_id: orgIdRaw, name, branch, force };
51316
+ if (repoUrl) body.repo_url = repoUrl;
51315
51317
  if (slug) body.slug = slug;
51316
51318
  const project = await requestJson(context2, "/projects/ensure", {
51317
51319
  method: "POST",
@@ -56190,6 +56192,7 @@ var RepoUrlSchema = external_exports.string().refine((value) => {
56190
56192
  return false;
56191
56193
  }
56192
56194
  }, "repo_url must be an http(s), file://, or SSH git URL");
56195
+ var RepoUrlOrUnsetSchema = external_exports.union([RepoUrlSchema, external_exports.literal("")]);
56193
56196
  var SlugSchema = external_exports.string().regex(/^[A-Za-z][A-Za-z0-9]{3,7}$/, "slug must be 4-8 alphanumeric characters starting with a letter");
56194
56197
  var CreateProjectRequestSchema = external_exports.object({
56195
56198
  org_id: external_exports.string().regex(/^org_[a-zA-Z0-9]+$/, "Invalid org_id format"),
@@ -56200,6 +56203,7 @@ var CreateProjectRequestSchema = external_exports.object({
56200
56203
  branch: external_exports.string().min(1).default("main")
56201
56204
  });
56202
56205
  var EnsureProjectRequestSchema = CreateProjectRequestSchema.extend({
56206
+ repo_url: RepoUrlSchema.optional(),
56203
56207
  force: external_exports.boolean().optional()
56204
56208
  });
56205
56209
  var UpdateProjectRequestSchema = external_exports.object({
@@ -56213,7 +56217,7 @@ var ProjectResponseSchema = external_exports.object({
56213
56217
  org_id: external_exports.string(),
56214
56218
  name: external_exports.string(),
56215
56219
  slug: external_exports.string(),
56216
- repo_url: RepoUrlSchema,
56220
+ repo_url: RepoUrlOrUnsetSchema,
56217
56221
  branch: external_exports.string(),
56218
56222
  deleted: external_exports.boolean(),
56219
56223
  created_at: external_exports.string(),
@@ -68055,6 +68059,8 @@ function padRight5(str, width) {
68055
68059
  var fs2 = __toESM(require("node:fs"));
68056
68060
  var path4 = __toESM(require("node:path"));
68057
68061
  var import_node_child_process7 = require("node:child_process");
68062
+ var UNIVERSAL_SKILLS_DIR = path4.join(".agents", "skills");
68063
+ var PRIVATE_SKILLS_DIRNAME = "private-skills";
68058
68064
  async function handleSkills(subcommand, positionals, flags) {
68059
68065
  switch (subcommand) {
68060
68066
  case "install":
@@ -68070,7 +68076,7 @@ async function handleInstall(positionals, flags) {
68070
68076
  const projectRoot = process.cwd();
68071
68077
  const skillsBin = resolveSkillsBinary();
68072
68078
  const manifestPath = path4.join(projectRoot, "skills.txt");
68073
- const skillsDir = path4.join(projectRoot, ".agent", "skills");
68079
+ const skillsDir = path4.join(projectRoot, UNIVERSAL_SKILLS_DIR);
68074
68080
  const source = positionals[0];
68075
68081
  if (source) {
68076
68082
  const parsed = parseSkillSource(source);
@@ -68102,10 +68108,32 @@ async function handleInstall(positionals, flags) {
68102
68108
  }
68103
68109
  function installSkill(skillsBin, skill, projectRoot) {
68104
68110
  console.log(` Installing: ${skill.source} (${skill.type})`);
68111
+ const localDir = resolveLocalDirIfExists(skill, projectRoot);
68112
+ const wantsExcludePrivate = localDir !== null && fs2.existsSync(path4.join(localDir, PRIVATE_SKILLS_DIRNAME)) && !sourcePathExplicitlyTargetsPrivate(skill.source);
68105
68113
  try {
68106
68114
  const agents = ["claude-code", "codex", "gemini-cli"];
68115
+ if (wantsExcludePrivate && localDir) {
68116
+ const skillDirs = findSkillDirs(localDir, { fullDepth: true, excludePrivate: true });
68117
+ if (skillDirs.length === 0) {
68118
+ console.log(` No skills found under ${skill.source} (after excluding ${PRIVATE_SKILLS_DIRNAME}/)`);
68119
+ return;
68120
+ }
68121
+ console.log(` Installing ${skillDirs.length} public skill(s) (excluding ${PRIVATE_SKILLS_DIRNAME}/)...`);
68122
+ for (const dir of skillDirs) {
68123
+ const rel = path4.relative(projectRoot, dir);
68124
+ const installSource = rel.startsWith(".") ? rel : `./${rel}`;
68125
+ for (const agent of agents) {
68126
+ (0, import_node_child_process7.execSync)(`${skillsBin} add ${JSON.stringify(installSource)} -a ${agent} -s '*' -y --full-depth`, {
68127
+ cwd: projectRoot,
68128
+ stdio: "inherit",
68129
+ timeout: 12e4
68130
+ });
68131
+ }
68132
+ }
68133
+ return;
68134
+ }
68107
68135
  for (const agent of agents) {
68108
- (0, import_node_child_process7.execSync)(`${skillsBin} add ${JSON.stringify(skill.source)} -a ${agent} -s '*' -y`, {
68136
+ (0, import_node_child_process7.execSync)(`${skillsBin} add ${JSON.stringify(skill.source)} -a ${agent} -s '*' -y --full-depth`, {
68109
68137
  cwd: projectRoot,
68110
68138
  stdio: "inherit",
68111
68139
  timeout: 12e4
@@ -68173,7 +68201,7 @@ function expandGlobPattern(pattern, basePath) {
68173
68201
  console.warn(`Warning: Glob pattern base directory not found: ${searchRoot}`);
68174
68202
  return sources;
68175
68203
  }
68176
- const findSkillDirs = (dir, depth) => {
68204
+ const findSkillDirs2 = (dir, depth) => {
68177
68205
  try {
68178
68206
  const entries = fs2.readdirSync(dir, { withFileTypes: true });
68179
68207
  for (const entry of entries) {
@@ -68194,14 +68222,14 @@ function expandGlobPattern(pattern, basePath) {
68194
68222
  });
68195
68223
  }
68196
68224
  if (isRecursive || depth === 0) {
68197
- findSkillDirs(fullPath, depth + 1);
68225
+ findSkillDirs2(fullPath, depth + 1);
68198
68226
  }
68199
68227
  }
68200
68228
  } catch (err) {
68201
68229
  console.warn(`Warning: Error reading directory ${dir}:`, err);
68202
68230
  }
68203
68231
  };
68204
- findSkillDirs(searchRoot, 0);
68232
+ findSkillDirs2(searchRoot, 0);
68205
68233
  return sources;
68206
68234
  }
68207
68235
  function parseSkillsManifest(manifestPath) {
@@ -68276,7 +68304,7 @@ function getInstalledSkills(skillsDir) {
68276
68304
  return installed;
68277
68305
  }
68278
68306
  function ensureSkillsSymlink(projectRoot) {
68279
- const agentSkills = path4.join(projectRoot, ".agent", "skills");
68307
+ const agentSkills = path4.join(projectRoot, UNIVERSAL_SKILLS_DIR);
68280
68308
  const claudeDir = path4.join(projectRoot, ".claude");
68281
68309
  const claudeSkills = path4.join(claudeDir, "skills");
68282
68310
  if (!fs2.existsSync(agentSkills)) {
@@ -68285,11 +68313,27 @@ function ensureSkillsSymlink(projectRoot) {
68285
68313
  if (!fs2.existsSync(claudeDir)) {
68286
68314
  fs2.mkdirSync(claudeDir, { recursive: true });
68287
68315
  }
68316
+ if (fs2.existsSync(claudeSkills) && !fs2.lstatSync(claudeSkills).isSymbolicLink()) {
68317
+ try {
68318
+ const claudeStat = fs2.lstatSync(claudeSkills);
68319
+ if (claudeStat.isDirectory()) {
68320
+ const entries = fs2.readdirSync(agentSkills, { withFileTypes: true });
68321
+ for (const entry of entries) {
68322
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
68323
+ const dst = path4.join(claudeSkills, entry.name);
68324
+ if (fs2.existsSync(dst)) continue;
68325
+ fs2.symlinkSync(path4.join("..", "..", UNIVERSAL_SKILLS_DIR, entry.name), dst);
68326
+ }
68327
+ }
68328
+ } catch {
68329
+ }
68330
+ return;
68331
+ }
68288
68332
  if (fs2.existsSync(claudeSkills)) {
68289
68333
  const stat = fs2.lstatSync(claudeSkills);
68290
68334
  if (stat.isSymbolicLink()) {
68291
68335
  const target = fs2.readlinkSync(claudeSkills);
68292
- if (target === "../.agent/skills" || target === agentSkills) {
68336
+ if (target === `../${UNIVERSAL_SKILLS_DIR}` || target === agentSkills) {
68293
68337
  return;
68294
68338
  }
68295
68339
  fs2.unlinkSync(claudeSkills);
@@ -68299,12 +68343,61 @@ function ensureSkillsSymlink(projectRoot) {
68299
68343
  }
68300
68344
  }
68301
68345
  try {
68302
- fs2.symlinkSync("../.agent/skills", claudeSkills);
68303
- console.log("Linked .claude/skills -> .agent/skills");
68346
+ fs2.symlinkSync(`../${UNIVERSAL_SKILLS_DIR}`, claudeSkills);
68347
+ console.log(`Linked .claude/skills -> ${UNIVERSAL_SKILLS_DIR}`);
68304
68348
  } catch (err) {
68305
68349
  console.warn("Warning: Failed to create symlink:", err);
68306
68350
  }
68307
68351
  }
68352
+ function resolveLocalDirIfExists(skill, projectRoot) {
68353
+ if (skill.type !== "local") return null;
68354
+ let source = skill.source;
68355
+ if (source.startsWith("~")) {
68356
+ source = source.replace(/^~/, process.env.HOME || "~");
68357
+ }
68358
+ const abs = path4.isAbsolute(source) ? source : path4.resolve(projectRoot, source);
68359
+ try {
68360
+ if (!fs2.existsSync(abs)) return null;
68361
+ if (!fs2.statSync(abs).isDirectory()) return null;
68362
+ return abs;
68363
+ } catch {
68364
+ return null;
68365
+ }
68366
+ }
68367
+ function sourcePathExplicitlyTargetsPrivate(source) {
68368
+ const normalized = source.replace(/\\/g, "/");
68369
+ return normalized === PRIVATE_SKILLS_DIRNAME || normalized.includes(`/${PRIVATE_SKILLS_DIRNAME}/`);
68370
+ }
68371
+ function findSkillDirs(rootDir, opts) {
68372
+ const out = [];
68373
+ const shouldSkipDir = (_parentAbsDir, name) => {
68374
+ if (name.startsWith(".")) return true;
68375
+ if (name === "node_modules" || name === ".git") return true;
68376
+ if (opts.excludePrivate && name === PRIVATE_SKILLS_DIRNAME) return true;
68377
+ if (name === ".agents" || name === ".agent" || name === ".claude") return true;
68378
+ return false;
68379
+ };
68380
+ const walk = (dir) => {
68381
+ let entries;
68382
+ try {
68383
+ entries = fs2.readdirSync(dir, { withFileTypes: true });
68384
+ } catch {
68385
+ return;
68386
+ }
68387
+ const hasSkillMd = entries.some((e) => e.isFile() && e.name === "SKILL.md");
68388
+ if (hasSkillMd) {
68389
+ out.push(dir);
68390
+ if (!opts.fullDepth) return;
68391
+ }
68392
+ for (const entry of entries) {
68393
+ if (!entry.isDirectory()) continue;
68394
+ if (shouldSkipDir(dir, entry.name)) continue;
68395
+ walk(path4.join(dir, entry.name));
68396
+ }
68397
+ };
68398
+ walk(rootDir);
68399
+ return out;
68400
+ }
68308
68401
 
68309
68402
  // src/commands/admin.ts
68310
68403
  async function handleAdmin(subcommand, positionals, flags, context2) {
@@ -69377,7 +69470,7 @@ async function installSkills(projectRoot) {
69377
69470
  }
69378
69471
  }
69379
69472
  function ensureSkillsSymlink2(projectRoot) {
69380
- const agentSkills = path5.join(projectRoot, ".agent", "skills");
69473
+ const agentSkills = path5.join(projectRoot, ".agents", "skills");
69381
69474
  const claudeDir = path5.join(projectRoot, ".claude");
69382
69475
  const claudeSkills = path5.join(claudeDir, "skills");
69383
69476
  if (!fs3.existsSync(agentSkills)) {
@@ -69386,11 +69479,27 @@ function ensureSkillsSymlink2(projectRoot) {
69386
69479
  if (!fs3.existsSync(claudeDir)) {
69387
69480
  fs3.mkdirSync(claudeDir, { recursive: true });
69388
69481
  }
69482
+ if (fs3.existsSync(claudeSkills) && !fs3.lstatSync(claudeSkills).isSymbolicLink()) {
69483
+ try {
69484
+ const stat = fs3.lstatSync(claudeSkills);
69485
+ if (stat.isDirectory()) {
69486
+ const entries = fs3.readdirSync(agentSkills, { withFileTypes: true });
69487
+ for (const entry of entries) {
69488
+ if (!entry.isDirectory() || entry.name.startsWith(".")) continue;
69489
+ const dst = path5.join(claudeSkills, entry.name);
69490
+ if (fs3.existsSync(dst)) continue;
69491
+ fs3.symlinkSync(path5.join("..", "..", ".agents", "skills", entry.name), dst);
69492
+ }
69493
+ }
69494
+ } catch {
69495
+ }
69496
+ return;
69497
+ }
69389
69498
  if (fs3.existsSync(claudeSkills)) {
69390
69499
  const stat = fs3.lstatSync(claudeSkills);
69391
69500
  if (stat.isSymbolicLink()) {
69392
69501
  const target = fs3.readlinkSync(claudeSkills);
69393
- if (target === "../.agent/skills" || target === agentSkills) {
69502
+ if (target === "../.agents/skills" || target === agentSkills) {
69394
69503
  return;
69395
69504
  }
69396
69505
  fs3.unlinkSync(claudeSkills);
@@ -69399,7 +69508,7 @@ function ensureSkillsSymlink2(projectRoot) {
69399
69508
  }
69400
69509
  }
69401
69510
  try {
69402
- fs3.symlinkSync("../.agent/skills", claudeSkills);
69511
+ fs3.symlinkSync("../.agents/skills", claudeSkills);
69403
69512
  } catch {
69404
69513
  }
69405
69514
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eve-horizon/cli",
3
- "version": "0.2.17",
3
+ "version": "0.2.19",
4
4
  "description": "Eve Horizon CLI",
5
5
  "license": "MIT",
6
6
  "repository": {