uloop-cli 0.50.2 → 0.52.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.
@@ -1,16 +1,18 @@
1
1
  /**
2
- * Skills manager for installing/uninstalling/listing uloop skills.
3
- * Supports both bundled skills and project-local skills.
2
+ * Claude Code and other AI tools require skills to be in specific directories.
3
+ * This module bridges the gap between bundled/project skills and target tool
4
+ * configurations, handling path resolution and file synchronization.
4
5
  */
5
6
 
6
7
  // File paths are constructed from home directory and skill names, not from untrusted user input
7
8
  /* eslint-disable security/detect-non-literal-fs-filename */
8
9
 
9
10
  import { existsSync, mkdirSync, readFileSync, writeFileSync, rmSync, readdirSync } from 'fs';
10
- import { join } from 'path';
11
+ import { join, dirname } from 'path';
11
12
  import { homedir } from 'os';
12
13
  import { BUNDLED_SKILLS, BundledSkill } from './bundled-skills.js';
13
14
  import { TargetConfig } from './target-config.js';
15
+ import { findUnityProjectRoot } from '../project-root.js';
14
16
 
15
17
  export type SkillStatus = 'installed' | 'not_installed' | 'outdated';
16
18
 
@@ -35,7 +37,13 @@ function getGlobalSkillsDir(target: TargetConfig): string {
35
37
  }
36
38
 
37
39
  function getProjectSkillsDir(target: TargetConfig): string {
38
- return join(process.cwd(), target.projectDir, 'skills');
40
+ const projectRoot = findUnityProjectRoot();
41
+ if (!projectRoot) {
42
+ throw new Error(
43
+ 'Not inside a Unity project. Run this command from within a Unity project directory.',
44
+ );
45
+ }
46
+ return join(projectRoot, target.projectDir, 'skills');
39
47
  }
40
48
 
41
49
  function getSkillPath(skillDirName: string, target: TargetConfig, global: boolean): string {
@@ -57,12 +65,34 @@ function isSkillOutdated(
57
65
  target: TargetConfig,
58
66
  global: boolean,
59
67
  ): boolean {
60
- const skillPath = getSkillPath(skill.dirName, target, global);
68
+ const baseDir = global ? getGlobalSkillsDir(target) : getProjectSkillsDir(target);
69
+ const skillDir = join(baseDir, skill.dirName);
70
+ const skillPath = join(skillDir, target.skillFileName);
71
+
61
72
  if (!existsSync(skillPath)) {
62
73
  return false;
63
74
  }
75
+
64
76
  const installedContent = readFileSync(skillPath, 'utf-8');
65
- return installedContent !== skill.content;
77
+ if (installedContent !== skill.content) {
78
+ return true;
79
+ }
80
+
81
+ if ('additionalFiles' in skill && skill.additionalFiles) {
82
+ const additionalFiles: Record<string, string> = skill.additionalFiles;
83
+ for (const [relativePath, expectedContent] of Object.entries(additionalFiles)) {
84
+ const filePath = join(skillDir, relativePath);
85
+ if (!existsSync(filePath)) {
86
+ return true;
87
+ }
88
+ const installedFileContent = readFileSync(filePath, 'utf-8');
89
+ if (installedFileContent !== expectedContent) {
90
+ return true;
91
+ }
92
+ }
93
+ }
94
+
95
+ return false;
66
96
  }
67
97
 
68
98
  export function getSkillStatus(
@@ -178,7 +208,10 @@ function findEditorFolders(basePath: string, maxDepth: number = 2): string[] {
178
208
  }
179
209
 
180
210
  export function collectProjectSkills(): ProjectSkill[] {
181
- const projectRoot = process.cwd();
211
+ const projectRoot = findUnityProjectRoot();
212
+ if (!projectRoot) {
213
+ return [];
214
+ }
182
215
  const skills: ProjectSkill[] = [];
183
216
  const seenNames = new Set<string>();
184
217
 
@@ -249,6 +282,15 @@ export function installSkill(
249
282
 
250
283
  mkdirSync(skillDir, { recursive: true });
251
284
  writeFileSync(skillPath, skill.content, 'utf-8');
285
+
286
+ if ('additionalFiles' in skill && skill.additionalFiles) {
287
+ const additionalFiles: Record<string, string> = skill.additionalFiles;
288
+ for (const [relativePath, content] of Object.entries(additionalFiles)) {
289
+ const fullPath = join(skillDir, relativePath);
290
+ mkdirSync(dirname(fullPath), { recursive: true });
291
+ writeFileSync(fullPath, content, 'utf-8');
292
+ }
293
+ }
252
294
  }
253
295
 
254
296
  export function uninstallSkill(
package/src/version.ts CHANGED
@@ -4,4 +4,4 @@
4
4
  * This file exists to avoid bundling the entire package.json into the CLI bundle.
5
5
  * This version is automatically updated by release-please.
6
6
  */
7
- export const VERSION = '0.50.2'; // x-release-please-version
7
+ export const VERSION = '0.52.0'; // x-release-please-version