uda-cli 0.2.0 → 0.4.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/README.md +61 -30
- package/package.json +9 -3
- package/src/cli.js +8 -0
- package/src/commands/clean.js +134 -0
- package/src/commands/init.js +60 -3
- package/src/core/constants.js +6 -0
package/README.md
CHANGED
|
@@ -1,66 +1,96 @@
|
|
|
1
1
|
# UDA (Universal Dev AI)
|
|
2
2
|
|
|
3
|
-
AI-agnostic context engineering + RAG CLI tool for game development.
|
|
3
|
+
AI-agnostic context engineering + RAG CLI tool for game development. Local, file-based, zero cloud dependency.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
7
|
-
- **Local RAG**: LanceDB + MiniLM embeddings
|
|
7
|
+
- **Local RAG**: LanceDB + MiniLM embeddings — no API keys needed
|
|
8
8
|
- **Multi-AI Support**: Claude, Cursor, Windsurf, AGENTS.md, Raw export
|
|
9
9
|
- **Plugin System**: Git-based engine plugins (Unity, Godot, Unreal, etc.)
|
|
10
|
+
- **Guided Setup**: Interactive plugin installation during `uda init`
|
|
10
11
|
- **Workflow Engine**: YAML-defined AI-assisted workflows
|
|
11
|
-
- **
|
|
12
|
+
- **AI-Native Integration**: Generates CLAUDE.md, skills, and agent files automatically
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
|
15
16
|
```bash
|
|
16
|
-
npm install -g uda
|
|
17
|
+
npm install -g uda-cli
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or run directly:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npx uda-cli init
|
|
17
24
|
```
|
|
18
25
|
|
|
19
26
|
## Quick Start
|
|
20
27
|
|
|
21
28
|
```bash
|
|
22
|
-
# Initialize UDA in your project
|
|
29
|
+
# Initialize UDA in your game project (auto-detects engine)
|
|
23
30
|
uda init
|
|
24
31
|
|
|
25
|
-
#
|
|
26
|
-
uda
|
|
32
|
+
# The init wizard will:
|
|
33
|
+
# 1. Create .uda/ directory
|
|
34
|
+
# 2. Detect your engine (Unity/Godot/Unreal)
|
|
35
|
+
# 3. Prompt to install the official plugin
|
|
36
|
+
# 4. Scan and index knowledge
|
|
37
|
+
# 5. Generate AI tool files (CLAUDE.md, .cursorrules, etc.)
|
|
38
|
+
```
|
|
27
39
|
|
|
28
|
-
|
|
29
|
-
uda search "MonoBehaviour lifecycle"
|
|
40
|
+
### Init Options
|
|
30
41
|
|
|
31
|
-
|
|
32
|
-
uda
|
|
42
|
+
```bash
|
|
43
|
+
uda init # Interactive (auto-detect engine)
|
|
44
|
+
uda init --engine unity # Specify engine explicitly
|
|
45
|
+
uda init --skip-plugin # Skip plugin prompt (CI/automation)
|
|
33
46
|
```
|
|
34
47
|
|
|
35
48
|
## Commands
|
|
36
49
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
50
|
+
| Command | Description |
|
|
51
|
+
|---------|-------------|
|
|
52
|
+
| `uda init` | Initialize UDA in current project |
|
|
53
|
+
| `uda sync` | Generate AI tool files from knowledge base |
|
|
54
|
+
| `uda scan` | Scan project and index into RAG |
|
|
55
|
+
| `uda search <query>` | Search knowledge base |
|
|
56
|
+
| `uda learn <source>` | Teach knowledge to RAG |
|
|
57
|
+
| `uda logs` | View Unity console logs |
|
|
58
|
+
| `uda plugin add <repo>` | Install an engine plugin |
|
|
59
|
+
| `uda plugin update <name>` | Update an installed plugin |
|
|
60
|
+
| `uda plugin update-all` | Update all plugins |
|
|
61
|
+
| `uda export --format <type>` | Export knowledge to specific format |
|
|
62
|
+
| `uda status` | Show UDA system status |
|
|
63
|
+
| `uda config [key] [value]` | Manage UDA settings |
|
|
64
|
+
|
|
65
|
+
## Supported AI Tools
|
|
66
|
+
|
|
67
|
+
| Format | Generated Files | Status |
|
|
68
|
+
|--------|----------------|--------|
|
|
69
|
+
| **claude** | `CLAUDE.md`, `.claude/skills/`, `.claude/agents/` | Available |
|
|
70
|
+
| **cursor** | `.cursorrules` | Coming soon |
|
|
71
|
+
| **windsurf** | `.windsurfrules` | Coming soon |
|
|
72
|
+
| **agents-md** | `AGENTS.md` | Coming soon |
|
|
73
|
+
| **raw** | `full-context.md` | Coming soon |
|
|
53
74
|
|
|
54
75
|
## Plugin System
|
|
55
76
|
|
|
56
|
-
|
|
77
|
+
Plugins provide engine-specific knowledge, workflows, and agents. During `uda init`, you'll be prompted to install the default plugin for your detected engine.
|
|
57
78
|
|
|
58
79
|
```bash
|
|
59
|
-
|
|
80
|
+
# Manual plugin management
|
|
81
|
+
uda plugin add https://github.com/Orhonbey/uda-unity-plugin.git
|
|
60
82
|
uda plugin update unity
|
|
61
83
|
uda plugin update-all
|
|
62
84
|
```
|
|
63
85
|
|
|
86
|
+
### Available Plugins
|
|
87
|
+
|
|
88
|
+
| Engine | Plugin |
|
|
89
|
+
|--------|--------|
|
|
90
|
+
| Unity | [uda-unity-plugin](https://github.com/Orhonbey/uda-unity-plugin) |
|
|
91
|
+
| Godot | Coming soon |
|
|
92
|
+
| Unreal | Coming soon |
|
|
93
|
+
|
|
64
94
|
## Project Structure
|
|
65
95
|
|
|
66
96
|
```
|
|
@@ -70,8 +100,9 @@ uda plugin update-all
|
|
|
70
100
|
│ ├── engine/ # Engine plugins (Unity, Godot, etc.)
|
|
71
101
|
│ ├── project/ # Project-specific knowledge
|
|
72
102
|
│ └── community/ # Community contributions
|
|
73
|
-
├── workflows/ # AI-assisted workflows
|
|
103
|
+
├── workflows/ # AI-assisted workflows (YAML)
|
|
74
104
|
├── agents/ # Specialized AI agents
|
|
105
|
+
├── logs/ # Engine logs (console.jsonl)
|
|
75
106
|
├── state/
|
|
76
107
|
│ ├── current.md # Active work state
|
|
77
108
|
│ ├── features/ # Feature specifications
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uda-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Universal Dev AI — AI-agnostic context engineering + RAG for game development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./src/cli.js",
|
|
@@ -16,9 +16,11 @@
|
|
|
16
16
|
"LICENSE"
|
|
17
17
|
],
|
|
18
18
|
"scripts": {
|
|
19
|
-
"test": "node --test src/**/*.test.js",
|
|
19
|
+
"test": "node --test --test-concurrency=1 src/**/*.test.js",
|
|
20
20
|
"test:coverage": "node --test --experimental-test-coverage src/**/*.test.js",
|
|
21
|
-
"dev": "node bin/uda.js"
|
|
21
|
+
"dev": "node bin/uda.js",
|
|
22
|
+
"preversion": "npm test",
|
|
23
|
+
"postversion": "git push origin main --follow-tags"
|
|
22
24
|
},
|
|
23
25
|
"keywords": [
|
|
24
26
|
"ai",
|
|
@@ -32,6 +34,10 @@
|
|
|
32
34
|
"vector-database",
|
|
33
35
|
"embeddings"
|
|
34
36
|
],
|
|
37
|
+
"repository": {
|
|
38
|
+
"type": "git",
|
|
39
|
+
"url": "https://github.com/Orhonbey/uda"
|
|
40
|
+
},
|
|
35
41
|
"author": "UDA Contributors",
|
|
36
42
|
"license": "MIT",
|
|
37
43
|
"engines": {
|
package/src/cli.js
CHANGED
|
@@ -10,6 +10,7 @@ import { handleConfig } from './commands/config.js';
|
|
|
10
10
|
import { handlePluginUpdate } from './commands/plugin.js';
|
|
11
11
|
import { handleExport } from './commands/export.js';
|
|
12
12
|
import { handleLogs } from './commands/logs.js';
|
|
13
|
+
import { handleClean } from './commands/clean.js';
|
|
13
14
|
|
|
14
15
|
export function createCli() {
|
|
15
16
|
const program = new Command();
|
|
@@ -18,6 +19,7 @@ export function createCli() {
|
|
|
18
19
|
.command('init')
|
|
19
20
|
.description('Initialize UDA in current project')
|
|
20
21
|
.option('-e, --engine <name>', 'Engine plugin to install (e.g. unity)')
|
|
22
|
+
.option('--skip-plugin', 'Skip plugin installation prompt')
|
|
21
23
|
.action(handleInit);
|
|
22
24
|
|
|
23
25
|
program
|
|
@@ -102,5 +104,11 @@ export function createCli() {
|
|
|
102
104
|
.option('-l, --last <count>', 'Show last N entries')
|
|
103
105
|
.action(handleLogs);
|
|
104
106
|
|
|
107
|
+
program
|
|
108
|
+
.command('clean')
|
|
109
|
+
.description('Remove UDA from current project')
|
|
110
|
+
.option('-f, --force', 'Skip confirmation prompt')
|
|
111
|
+
.action(handleClean);
|
|
112
|
+
|
|
105
113
|
return program;
|
|
106
114
|
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
// src/commands/clean.js — Remove UDA from current project
|
|
2
|
+
import { access, readdir, rm, unlink } from 'fs/promises'
|
|
3
|
+
import { createInterface } from 'readline'
|
|
4
|
+
import { join } from 'path'
|
|
5
|
+
|
|
6
|
+
const CLEAN_TARGETS = {
|
|
7
|
+
dirs: ['.uda', '.claude/commands/uda'],
|
|
8
|
+
files: ['CLAUDE.md', '.cursorrules', 'AGENTS.md'],
|
|
9
|
+
agentGlob: '.claude/agents',
|
|
10
|
+
agentPrefix: 'uda-',
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
async function exists(p) {
|
|
14
|
+
try {
|
|
15
|
+
await access(p)
|
|
16
|
+
return true
|
|
17
|
+
} catch {
|
|
18
|
+
return false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function ask(question) {
|
|
23
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout })
|
|
24
|
+
return new Promise((resolve) => {
|
|
25
|
+
rl.question(question, (answer) => {
|
|
26
|
+
rl.close()
|
|
27
|
+
resolve(answer)
|
|
28
|
+
})
|
|
29
|
+
})
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export async function handleClean(options = {}) {
|
|
33
|
+
const targets = {
|
|
34
|
+
dirs: [],
|
|
35
|
+
files: [],
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Check if .uda exists
|
|
39
|
+
const hasUda = await exists('.uda')
|
|
40
|
+
if (!hasUda) {
|
|
41
|
+
console.error('Hata: Bu dizinde UDA kurulu degil.')
|
|
42
|
+
process.exitCode = 1
|
|
43
|
+
return
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// Collect directories
|
|
47
|
+
for (const dir of CLEAN_TARGETS.dirs) {
|
|
48
|
+
if (await exists(dir)) {
|
|
49
|
+
targets.dirs.push(dir)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Collect files
|
|
54
|
+
for (const file of CLEAN_TARGETS.files) {
|
|
55
|
+
if (await exists(file)) {
|
|
56
|
+
targets.files.push(file)
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Collect agent files (only uda-*.md)
|
|
61
|
+
if (await exists(CLEAN_TARGETS.agentGlob)) {
|
|
62
|
+
try {
|
|
63
|
+
const agentFiles = await readdir(CLEAN_TARGETS.agentGlob)
|
|
64
|
+
for (const f of agentFiles) {
|
|
65
|
+
if (f.startsWith(CLEAN_TARGETS.agentPrefix) && f.endsWith('.md')) {
|
|
66
|
+
targets.files.push(join(CLEAN_TARGETS.agentGlob, f))
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
} catch {
|
|
70
|
+
// Ignore errors reading agents dir
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Show what will be deleted
|
|
75
|
+
console.log('UDA Clean — Silinecek dosyalar:')
|
|
76
|
+
console.log()
|
|
77
|
+
|
|
78
|
+
if (targets.dirs.length > 0) {
|
|
79
|
+
console.log(' Dizinler:')
|
|
80
|
+
for (const d of targets.dirs) {
|
|
81
|
+
console.log(` ${d}/`)
|
|
82
|
+
}
|
|
83
|
+
console.log()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
if (targets.files.length > 0) {
|
|
87
|
+
console.log(' Dosyalar:')
|
|
88
|
+
for (const f of targets.files) {
|
|
89
|
+
console.log(` ${f}`)
|
|
90
|
+
}
|
|
91
|
+
console.log()
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (targets.dirs.length === 0 && targets.files.length === 0) {
|
|
95
|
+
console.log(' Silinecek dosya bulunamadi.')
|
|
96
|
+
return
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Ask for confirmation unless --force
|
|
100
|
+
if (!options.force) {
|
|
101
|
+
const answer = await ask('Bu islem geri alinamaz. Devam? (y/N): ')
|
|
102
|
+
if (answer.toLowerCase() !== 'y') {
|
|
103
|
+
console.log('Islem iptal edildi.')
|
|
104
|
+
return
|
|
105
|
+
}
|
|
106
|
+
console.log()
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Delete files first
|
|
110
|
+
let deletedFiles = 0
|
|
111
|
+
for (const f of targets.files) {
|
|
112
|
+
try {
|
|
113
|
+
await unlink(f)
|
|
114
|
+
deletedFiles++
|
|
115
|
+
} catch {
|
|
116
|
+
// Ignore errors
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Delete directories (in reverse order, nested first)
|
|
121
|
+
let deletedDirs = 0
|
|
122
|
+
const sortedDirs = [...targets.dirs].sort((a, b) => b.length - a.length)
|
|
123
|
+
for (const d of sortedDirs) {
|
|
124
|
+
try {
|
|
125
|
+
await rm(d, { recursive: true, force: true })
|
|
126
|
+
deletedDirs++
|
|
127
|
+
} catch {
|
|
128
|
+
// Ignore errors
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
console.log(`${deletedDirs} dizin, ${deletedFiles} dosya silindi.`)
|
|
133
|
+
console.log('UDA projeden kaldirildi.')
|
|
134
|
+
}
|
package/src/commands/init.js
CHANGED
|
@@ -1,7 +1,16 @@
|
|
|
1
|
+
import { createInterface } from 'readline';
|
|
2
|
+
import { readFileSync } from 'fs';
|
|
3
|
+
import { fileURLToPath } from 'url';
|
|
4
|
+
import { dirname, join } from 'path';
|
|
1
5
|
import { initProject } from '../core/init.js';
|
|
2
6
|
import { handleScan } from './scan.js';
|
|
3
7
|
import { handleSync } from './sync.js';
|
|
8
|
+
import { handlePluginAdd } from './plugin.js';
|
|
4
9
|
import { validateEngine } from '../core/validators.js';
|
|
10
|
+
import { DEFAULT_PLUGINS } from '../core/constants.js';
|
|
11
|
+
|
|
12
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
13
|
+
const pkg = JSON.parse(readFileSync(join(__dirname, '../../package.json'), 'utf8'));
|
|
5
14
|
|
|
6
15
|
export async function handleInit(options) {
|
|
7
16
|
const root = process.cwd();
|
|
@@ -16,7 +25,7 @@ export async function handleInit(options) {
|
|
|
16
25
|
}
|
|
17
26
|
}
|
|
18
27
|
|
|
19
|
-
console.log(
|
|
28
|
+
console.log(`UDA v${pkg.version}\n`);
|
|
20
29
|
|
|
21
30
|
// Step 1: Create directory structure
|
|
22
31
|
console.log('Creating project structure...');
|
|
@@ -29,11 +38,17 @@ export async function handleInit(options) {
|
|
|
29
38
|
}
|
|
30
39
|
console.log('✔ .uda/ directory created\n');
|
|
31
40
|
|
|
32
|
-
// Step 2: Engine detection
|
|
41
|
+
// Step 2: Engine detection + plugin install prompt
|
|
33
42
|
const engine = options.engine || await detectEngine(root);
|
|
34
43
|
if (engine) {
|
|
35
44
|
console.log(`✔ Engine detected: ${engine}`);
|
|
36
|
-
|
|
45
|
+
const defaultUrl = DEFAULT_PLUGINS[engine];
|
|
46
|
+
if (defaultUrl && !options.skipPlugin) {
|
|
47
|
+
await promptPluginInstall(engine, defaultUrl);
|
|
48
|
+
} else if (!defaultUrl) {
|
|
49
|
+
console.log(` No default plugin available for ${engine}.`);
|
|
50
|
+
console.log(` Run \`uda plugin add <repo>\` to install a ${engine} plugin\n`);
|
|
51
|
+
}
|
|
37
52
|
}
|
|
38
53
|
|
|
39
54
|
// Step 3: Initial scan
|
|
@@ -50,6 +65,48 @@ export async function handleInit(options) {
|
|
|
50
65
|
console.log(' uda plugin add <git-repo>');
|
|
51
66
|
}
|
|
52
67
|
|
|
68
|
+
async function promptPluginInstall(engine, defaultUrl) {
|
|
69
|
+
const answer = await ask(
|
|
70
|
+
`\n Install official ${engine} plugin?\n` +
|
|
71
|
+
` [Y] Yes, install default (${defaultUrl})\n` +
|
|
72
|
+
` [C] Custom — enter your own plugin URL\n` +
|
|
73
|
+
` [N] No, skip\n` +
|
|
74
|
+
` Choice (Y/c/n): `
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const choice = answer.trim().toLowerCase();
|
|
78
|
+
|
|
79
|
+
if (choice === 'n') {
|
|
80
|
+
console.log(' Skipped plugin installation.\n');
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
let repoUrl = defaultUrl;
|
|
85
|
+
|
|
86
|
+
if (choice === 'c') {
|
|
87
|
+
repoUrl = await ask(' Plugin git URL: ');
|
|
88
|
+
repoUrl = repoUrl.trim();
|
|
89
|
+
if (!repoUrl) {
|
|
90
|
+
console.log(' No URL provided. Skipped plugin installation.\n');
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
console.log(`\n Installing ${engine} plugin...`);
|
|
96
|
+
await handlePluginAdd(repoUrl);
|
|
97
|
+
console.log('');
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function ask(question) {
|
|
101
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
102
|
+
return new Promise((resolve) => {
|
|
103
|
+
rl.question(question, (answer) => {
|
|
104
|
+
rl.close();
|
|
105
|
+
resolve(answer);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
}
|
|
109
|
+
|
|
53
110
|
async function detectEngine(root) {
|
|
54
111
|
const { existsSync } = await import('fs');
|
|
55
112
|
const { join } = await import('path');
|
package/src/core/constants.js
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
// src/core/constants.js
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
|
|
4
|
+
export const DEFAULT_PLUGINS = {
|
|
5
|
+
unity: 'https://github.com/Orhonbey/uda-unity-plugin.git',
|
|
6
|
+
// godot: 'https://github.com/SunalSpaciel/uda-godot-plugin.git',
|
|
7
|
+
// unreal: 'https://github.com/SunalSpaciel/uda-unreal-plugin.git',
|
|
8
|
+
};
|
|
9
|
+
|
|
4
10
|
export const UDA_DIR = '.uda';
|
|
5
11
|
|
|
6
12
|
export function udaPaths(root) {
|