lnai 0.1.0 → 0.2.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 +64 -0
- package/dist/index.js +45 -39
- package/package.json +5 -3
- package/dist/index.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img alt="LNAI Logo" src="https://raw.githubusercontent.com/KrystianJonca/lnai/main/apps/docs/public/lnai_white_on_black.png" width="200">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<p align="center">
|
|
6
|
+
<a href="https://www.npmjs.com/package/lnai">
|
|
7
|
+
<img alt="npm version" src="https://img.shields.io/npm/v/lnai">
|
|
8
|
+
</a>
|
|
9
|
+
<a href="https://github.com/KrystianJonca/lnai/stargazers">
|
|
10
|
+
<img alt="GitHub stars" src="https://img.shields.io/github/stars/KrystianJonca/lnai?style=social">
|
|
11
|
+
</a>
|
|
12
|
+
</p>
|
|
13
|
+
|
|
14
|
+
# LNAI
|
|
15
|
+
|
|
16
|
+
Unified AI configuration management CLI. Define your AI tool configurations once in `.ai/` and sync them to native formats for Claude Code, Cursor, OpenCode, and more.
|
|
17
|
+
|
|
18
|
+
## Documentation
|
|
19
|
+
|
|
20
|
+
See the [documentation](https://lnai.sh) for detailed guides.
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install -g lnai
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
# Initialize a new .ai/ configuration
|
|
32
|
+
lnai init
|
|
33
|
+
|
|
34
|
+
# Validate your configuration
|
|
35
|
+
lnai validate
|
|
36
|
+
|
|
37
|
+
# Sync to native tool configs
|
|
38
|
+
lnai sync
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Commands
|
|
42
|
+
|
|
43
|
+
- `lnai init` - Create a new `.ai/` configuration directory
|
|
44
|
+
- `lnai validate` - Validate your `.ai/` configuration
|
|
45
|
+
- `lnai sync` - Export `.ai/` to native tool configs
|
|
46
|
+
|
|
47
|
+
## Configuration Structure
|
|
48
|
+
|
|
49
|
+
```
|
|
50
|
+
.ai/
|
|
51
|
+
├── config.json # Tool settings and enabled tools
|
|
52
|
+
├── settings.json # Permissions and MCP servers
|
|
53
|
+
├── AGENTS.md # Project instructions
|
|
54
|
+
├── rules/ # Path-based rules
|
|
55
|
+
└── skills/ # Custom commands
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
MIT
|
|
61
|
+
|
|
62
|
+
---
|
|
63
|
+
|
|
64
|
+
If you find LNAI helpful, please [star us on GitHub](https://github.com/KrystianJonca/lnai)!
|
package/dist/index.js
CHANGED
|
@@ -1,45 +1,36 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'module';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import { hasUnifiedConfig, UNIFIED_DIR, initUnifiedConfig, runSyncPipeline, parseUnifiedConfig, validateUnifiedState, pluginRegistry } from '@lnai/core';
|
|
6
|
-
import chalk3 from 'chalk';
|
|
4
|
+
import { initUnifiedConfig, runSyncPipeline, parseUnifiedConfig, validateUnifiedState, pluginRegistry } from '@lnai/core';
|
|
5
|
+
import chalk2 from 'chalk';
|
|
7
6
|
import ora from 'ora';
|
|
8
7
|
|
|
9
8
|
var initCommand = new Command("init").description("Initialize a new .ai/ configuration directory").option("--force", "Overwrite existing .ai/ directory").option("--minimal", "Create only config.json (no subdirectories)").option("-t, --tools <tools...>", "Enable only specific tools").action(async (options) => {
|
|
10
9
|
const rootDir = process.cwd();
|
|
11
10
|
const spinner = ora("Initializing .ai/ configuration...").start();
|
|
12
11
|
try {
|
|
13
|
-
const exists = await hasUnifiedConfig(rootDir);
|
|
14
|
-
if (exists && !options.force) {
|
|
15
|
-
spinner.fail(
|
|
16
|
-
`Directory ${UNIFIED_DIR}/ already exists. Use --force to overwrite.`
|
|
17
|
-
);
|
|
18
|
-
process.exit(1);
|
|
19
|
-
}
|
|
20
|
-
if (exists && options.force) {
|
|
21
|
-
await fs.rm(path.join(rootDir, UNIFIED_DIR), {
|
|
22
|
-
recursive: true,
|
|
23
|
-
force: true
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
12
|
const result = await initUnifiedConfig({
|
|
27
13
|
rootDir,
|
|
28
14
|
tools: options.tools,
|
|
29
|
-
minimal: options.minimal
|
|
15
|
+
minimal: options.minimal,
|
|
16
|
+
force: options.force
|
|
30
17
|
});
|
|
31
18
|
spinner.succeed("Initialized .ai/ configuration");
|
|
32
|
-
console.log(
|
|
19
|
+
console.log(chalk2.gray("\nCreated:"));
|
|
33
20
|
for (const file of result.created) {
|
|
34
|
-
console.log(
|
|
21
|
+
console.log(chalk2.green(` + ${file}`));
|
|
35
22
|
}
|
|
36
23
|
console.log(
|
|
37
|
-
|
|
24
|
+
chalk2.gray("\nRun ") + chalk2.cyan("lnai sync") + chalk2.gray(" to generate tool configs.")
|
|
38
25
|
);
|
|
26
|
+
console.log(
|
|
27
|
+
chalk2.gray("\nIf you find LNAI helpful, please star us on GitHub:")
|
|
28
|
+
);
|
|
29
|
+
console.log(chalk2.blue("https://github.com/KrystianJonca/lnai"));
|
|
39
30
|
} catch (error) {
|
|
40
31
|
spinner.fail("Initialization failed");
|
|
41
32
|
console.error(
|
|
42
|
-
|
|
33
|
+
chalk2.red(error instanceof Error ? error.message : String(error))
|
|
43
34
|
);
|
|
44
35
|
process.exit(1);
|
|
45
36
|
}
|
|
@@ -55,24 +46,39 @@ var syncCommand = new Command("sync").description("Export .ai/ to native configs
|
|
|
55
46
|
});
|
|
56
47
|
spinner.succeed("Sync complete");
|
|
57
48
|
if (results.length === 0) {
|
|
58
|
-
console.log(
|
|
49
|
+
console.log(chalk2.yellow("\nNo tools configured or enabled."));
|
|
59
50
|
return;
|
|
60
51
|
}
|
|
61
52
|
for (const result of results) {
|
|
62
|
-
console.log(
|
|
53
|
+
console.log(chalk2.blue(`
|
|
63
54
|
${result.tool}:`));
|
|
64
55
|
if (result.changes.length === 0) {
|
|
65
|
-
console.log(
|
|
56
|
+
console.log(chalk2.gray(" No changes"));
|
|
66
57
|
}
|
|
67
58
|
for (const change of result.changes) {
|
|
68
|
-
const icon = change.action === "create" ?
|
|
59
|
+
const icon = change.action === "create" ? chalk2.green("+") : change.action === "update" ? chalk2.yellow("~") : change.action === "delete" ? chalk2.red("-") : chalk2.gray("=");
|
|
69
60
|
console.log(` ${icon} ${change.path}`);
|
|
70
61
|
}
|
|
71
62
|
}
|
|
63
|
+
for (const result of results) {
|
|
64
|
+
if (result.validation.warnings.length > 0) {
|
|
65
|
+
console.log(chalk2.yellow(`
|
|
66
|
+
${result.tool} warnings:`));
|
|
67
|
+
for (const warning of result.validation.warnings) {
|
|
68
|
+
console.log(
|
|
69
|
+
chalk2.yellow(` - ${warning.path.join(".")}: ${warning.message}`)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
console.log(
|
|
75
|
+
chalk2.gray("\nIf you find LNAI helpful, please star us on GitHub:")
|
|
76
|
+
);
|
|
77
|
+
console.log(chalk2.blue("https://github.com/KrystianJonca/lnai"));
|
|
72
78
|
} catch (error) {
|
|
73
79
|
spinner.fail("Sync failed");
|
|
74
80
|
console.error(
|
|
75
|
-
|
|
81
|
+
chalk2.red(error instanceof Error ? error.message : String(error))
|
|
76
82
|
);
|
|
77
83
|
process.exit(1);
|
|
78
84
|
}
|
|
@@ -85,10 +91,10 @@ var validateCommand = new Command("validate").description("Validate .ai/ configu
|
|
|
85
91
|
const unifiedResult = validateUnifiedState(state);
|
|
86
92
|
if (!unifiedResult.valid) {
|
|
87
93
|
spinner.fail("Validation failed");
|
|
88
|
-
console.log(
|
|
94
|
+
console.log(chalk2.red("\nUnified config errors:"));
|
|
89
95
|
for (const error of unifiedResult.errors) {
|
|
90
96
|
console.log(
|
|
91
|
-
|
|
97
|
+
chalk2.red(` - ${error.path.join(".")}: ${error.message}`)
|
|
92
98
|
);
|
|
93
99
|
}
|
|
94
100
|
process.exit(1);
|
|
@@ -116,11 +122,11 @@ var validateCommand = new Command("validate").description("Validate .ai/ configu
|
|
|
116
122
|
if (toolErrors.length > 0) {
|
|
117
123
|
spinner.fail("Validation failed");
|
|
118
124
|
for (const { plugin, errors } of toolErrors) {
|
|
119
|
-
console.log(
|
|
125
|
+
console.log(chalk2.red(`
|
|
120
126
|
${plugin} errors:`));
|
|
121
127
|
for (const error of errors) {
|
|
122
128
|
console.log(
|
|
123
|
-
|
|
129
|
+
chalk2.red(` - ${error.path.join(".")}: ${error.message}`)
|
|
124
130
|
);
|
|
125
131
|
}
|
|
126
132
|
}
|
|
@@ -128,38 +134,38 @@ ${plugin} errors:`));
|
|
|
128
134
|
}
|
|
129
135
|
spinner.succeed("Validation passed");
|
|
130
136
|
for (const { plugin, warnings } of toolWarnings) {
|
|
131
|
-
console.log(
|
|
137
|
+
console.log(chalk2.yellow(`
|
|
132
138
|
${plugin} warnings:`));
|
|
133
139
|
for (const warning of warnings) {
|
|
134
140
|
console.log(
|
|
135
|
-
|
|
141
|
+
chalk2.yellow(` - ${warning.path.join(".")}: ${warning.message}`)
|
|
136
142
|
);
|
|
137
143
|
}
|
|
138
144
|
}
|
|
139
145
|
for (const { plugin, skipped } of toolSkipped) {
|
|
140
|
-
console.log(
|
|
146
|
+
console.log(chalk2.gray(`
|
|
141
147
|
${plugin} skipped features:`));
|
|
142
148
|
for (const item of skipped) {
|
|
143
|
-
console.log(
|
|
149
|
+
console.log(chalk2.gray(` - ${item.feature}: ${item.reason}`));
|
|
144
150
|
}
|
|
145
151
|
}
|
|
146
152
|
} catch (error) {
|
|
147
153
|
spinner.fail("Validation failed");
|
|
148
154
|
console.error(
|
|
149
|
-
|
|
155
|
+
chalk2.red(error instanceof Error ? error.message : String(error))
|
|
150
156
|
);
|
|
151
157
|
process.exit(1);
|
|
152
158
|
}
|
|
153
159
|
});
|
|
154
160
|
|
|
155
161
|
// src/index.ts
|
|
162
|
+
var require2 = createRequire(import.meta.url);
|
|
163
|
+
var pkg = require2("../package.json");
|
|
156
164
|
var program = new Command();
|
|
157
165
|
program.name("lnai").description(
|
|
158
166
|
"CLI tool that syncs a unified .ai/ config to native formats for AI coding tools"
|
|
159
|
-
).version(
|
|
167
|
+
).version(pkg.version);
|
|
160
168
|
program.addCommand(initCommand);
|
|
161
169
|
program.addCommand(syncCommand);
|
|
162
170
|
program.addCommand(validateCommand);
|
|
163
171
|
program.parse();
|
|
164
|
-
//# sourceMappingURL=index.js.map
|
|
165
|
-
//# sourceMappingURL=index.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lnai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "CLI tool that syncs a unified .ai/ config to native formats for AI coding tools",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -19,6 +19,7 @@
|
|
|
19
19
|
"config",
|
|
20
20
|
"configuration",
|
|
21
21
|
"claude",
|
|
22
|
+
"cursor",
|
|
22
23
|
"opencode",
|
|
23
24
|
"cli",
|
|
24
25
|
"ai-tools",
|
|
@@ -28,13 +29,14 @@
|
|
|
28
29
|
"lnai": "./dist/index.js"
|
|
29
30
|
},
|
|
30
31
|
"files": [
|
|
31
|
-
"dist"
|
|
32
|
+
"dist",
|
|
33
|
+
"README.md"
|
|
32
34
|
],
|
|
33
35
|
"dependencies": {
|
|
34
36
|
"chalk": "^5.6.2",
|
|
35
37
|
"commander": "^14.0.2",
|
|
36
38
|
"ora": "^9.1.0",
|
|
37
|
-
"@lnai/core": "0.
|
|
39
|
+
"@lnai/core": "0.2.0"
|
|
38
40
|
},
|
|
39
41
|
"devDependencies": {
|
|
40
42
|
"@types/node": "^25.0.10",
|
package/dist/index.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/commands/init.ts","../src/commands/sync.ts","../src/commands/validate.ts","../src/index.ts"],"names":["chalk","Command","ora"],"mappings":"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","file":"index.js","sourcesContent":["import * as fs from \"node:fs/promises\";\nimport * as path from \"node:path\";\n\nimport {\n hasUnifiedConfig,\n initUnifiedConfig,\n type ToolId,\n UNIFIED_DIR,\n} from \"@lnai/core\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\n\nexport const initCommand = new Command(\"init\")\n .description(\"Initialize a new .ai/ configuration directory\")\n .option(\"--force\", \"Overwrite existing .ai/ directory\")\n .option(\"--minimal\", \"Create only config.json (no subdirectories)\")\n .option(\"-t, --tools <tools...>\", \"Enable only specific tools\")\n .action(async (options) => {\n const rootDir = process.cwd();\n const spinner = ora(\"Initializing .ai/ configuration...\").start();\n\n try {\n const exists = await hasUnifiedConfig(rootDir);\n\n if (exists && !options.force) {\n spinner.fail(\n `Directory ${UNIFIED_DIR}/ already exists. Use --force to overwrite.`\n );\n process.exit(1);\n }\n\n if (exists && options.force) {\n await fs.rm(path.join(rootDir, UNIFIED_DIR), {\n recursive: true,\n force: true,\n });\n }\n\n const result = await initUnifiedConfig({\n rootDir,\n tools: options.tools as ToolId[] | undefined,\n minimal: options.minimal,\n });\n\n spinner.succeed(\"Initialized .ai/ configuration\");\n\n console.log(chalk.gray(\"\\nCreated:\"));\n for (const file of result.created) {\n console.log(chalk.green(` + ${file}`));\n }\n\n console.log(\n chalk.gray(\"\\nRun \") +\n chalk.cyan(\"lnai sync\") +\n chalk.gray(\" to generate tool configs.\")\n );\n } catch (error) {\n spinner.fail(\"Initialization failed\");\n console.error(\n chalk.red(error instanceof Error ? error.message : String(error))\n );\n process.exit(1);\n }\n });\n","import { runSyncPipeline, type ToolId } from \"@lnai/core\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\n\nexport const syncCommand = new Command(\"sync\")\n .description(\"Export .ai/ to native configs\")\n .option(\"--dry-run\", \"Preview without writing\")\n .option(\"-t, --tools <tools...>\", \"Filter to specific tools\")\n .option(\"-v, --verbose\", \"Detailed output\")\n .action(async (options) => {\n const spinner = ora(\"Syncing configuration...\").start();\n\n try {\n const results = await runSyncPipeline({\n rootDir: process.cwd(),\n dryRun: options.dryRun,\n tools: options.tools as ToolId[] | undefined,\n verbose: options.verbose,\n });\n\n spinner.succeed(\"Sync complete\");\n\n if (results.length === 0) {\n console.log(chalk.yellow(\"\\nNo tools configured or enabled.\"));\n return;\n }\n\n for (const result of results) {\n console.log(chalk.blue(`\\n${result.tool}:`));\n\n if (result.changes.length === 0) {\n console.log(chalk.gray(\" No changes\"));\n }\n\n for (const change of result.changes) {\n const icon =\n change.action === \"create\"\n ? chalk.green(\"+\")\n : change.action === \"update\"\n ? chalk.yellow(\"~\")\n : change.action === \"delete\"\n ? chalk.red(\"-\")\n : chalk.gray(\"=\");\n console.log(` ${icon} ${change.path}`);\n }\n }\n } catch (error) {\n spinner.fail(\"Sync failed\");\n console.error(\n chalk.red(error instanceof Error ? error.message : String(error))\n );\n process.exit(1);\n }\n });\n","import {\n parseUnifiedConfig,\n pluginRegistry,\n type ToolId,\n validateUnifiedState,\n} from \"@lnai/core\";\nimport chalk from \"chalk\";\nimport { Command } from \"commander\";\nimport ora from \"ora\";\n\nexport const validateCommand = new Command(\"validate\")\n .description(\"Validate .ai/ configuration\")\n .option(\"-t, --tools <tools...>\", \"Filter to specific tools\")\n .action(async (options) => {\n const spinner = ora(\"Validating configuration...\").start();\n\n try {\n const rootDir = process.cwd();\n const state = await parseUnifiedConfig(rootDir);\n\n const unifiedResult = validateUnifiedState(state);\n\n if (!unifiedResult.valid) {\n spinner.fail(\"Validation failed\");\n console.log(chalk.red(\"\\nUnified config errors:\"));\n for (const error of unifiedResult.errors) {\n console.log(\n chalk.red(` - ${error.path.join(\".\")}: ${error.message}`)\n );\n }\n process.exit(1);\n }\n\n const tools =\n (options.tools as ToolId[] | undefined) ?? pluginRegistry.getIds();\n\n const toolErrors: Array<{\n plugin: string;\n errors: typeof unifiedResult.errors;\n }> = [];\n const toolWarnings: Array<{\n plugin: string;\n warnings: typeof unifiedResult.errors;\n }> = [];\n const toolSkipped: Array<{\n plugin: string;\n skipped: Array<{ feature: string; reason: string }>;\n }> = [];\n\n for (const toolId of tools) {\n const plugin = pluginRegistry.get(toolId);\n if (!plugin) {\n continue;\n }\n\n const result = plugin.validate(state);\n\n if (!result.valid) {\n toolErrors.push({ plugin: plugin.name, errors: result.errors });\n }\n\n if (result.warnings.length > 0) {\n toolWarnings.push({ plugin: plugin.name, warnings: result.warnings });\n }\n\n if (result.skipped.length > 0) {\n toolSkipped.push({ plugin: plugin.name, skipped: result.skipped });\n }\n }\n\n if (toolErrors.length > 0) {\n spinner.fail(\"Validation failed\");\n for (const { plugin, errors } of toolErrors) {\n console.log(chalk.red(`\\n${plugin} errors:`));\n for (const error of errors) {\n console.log(\n chalk.red(` - ${error.path.join(\".\")}: ${error.message}`)\n );\n }\n }\n process.exit(1);\n }\n\n spinner.succeed(\"Validation passed\");\n\n for (const { plugin, warnings } of toolWarnings) {\n console.log(chalk.yellow(`\\n${plugin} warnings:`));\n for (const warning of warnings) {\n console.log(\n chalk.yellow(` - ${warning.path.join(\".\")}: ${warning.message}`)\n );\n }\n }\n\n for (const { plugin, skipped } of toolSkipped) {\n console.log(chalk.gray(`\\n${plugin} skipped features:`));\n for (const item of skipped) {\n console.log(chalk.gray(` - ${item.feature}: ${item.reason}`));\n }\n }\n } catch (error) {\n spinner.fail(\"Validation failed\");\n console.error(\n chalk.red(error instanceof Error ? error.message : String(error))\n );\n process.exit(1);\n }\n });\n","import { Command } from \"commander\";\n\nimport { initCommand } from \"./commands/init.js\";\nimport { syncCommand } from \"./commands/sync.js\";\nimport { validateCommand } from \"./commands/validate.js\";\n\nconst program = new Command();\n\nprogram\n .name(\"lnai\")\n .description(\n \"CLI tool that syncs a unified .ai/ config to native formats for AI coding tools\"\n )\n .version(\"0.1.0\");\n\nprogram.addCommand(initCommand);\nprogram.addCommand(syncCommand);\nprogram.addCommand(validateCommand);\n\nprogram.parse();\n"]}
|