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 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 * as fs from 'fs/promises';
4
- import * as path from 'path';
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(chalk3.gray("\nCreated:"));
19
+ console.log(chalk2.gray("\nCreated:"));
33
20
  for (const file of result.created) {
34
- console.log(chalk3.green(` + ${file}`));
21
+ console.log(chalk2.green(` + ${file}`));
35
22
  }
36
23
  console.log(
37
- chalk3.gray("\nRun ") + chalk3.cyan("lnai sync") + chalk3.gray(" to generate tool configs.")
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
- chalk3.red(error instanceof Error ? error.message : String(error))
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(chalk3.yellow("\nNo tools configured or enabled."));
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(chalk3.blue(`
53
+ console.log(chalk2.blue(`
63
54
  ${result.tool}:`));
64
55
  if (result.changes.length === 0) {
65
- console.log(chalk3.gray(" No changes"));
56
+ console.log(chalk2.gray(" No changes"));
66
57
  }
67
58
  for (const change of result.changes) {
68
- const icon = change.action === "create" ? chalk3.green("+") : change.action === "update" ? chalk3.yellow("~") : change.action === "delete" ? chalk3.red("-") : chalk3.gray("=");
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
- chalk3.red(error instanceof Error ? error.message : String(error))
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(chalk3.red("\nUnified config errors:"));
94
+ console.log(chalk2.red("\nUnified config errors:"));
89
95
  for (const error of unifiedResult.errors) {
90
96
  console.log(
91
- chalk3.red(` - ${error.path.join(".")}: ${error.message}`)
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(chalk3.red(`
125
+ console.log(chalk2.red(`
120
126
  ${plugin} errors:`));
121
127
  for (const error of errors) {
122
128
  console.log(
123
- chalk3.red(` - ${error.path.join(".")}: ${error.message}`)
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(chalk3.yellow(`
137
+ console.log(chalk2.yellow(`
132
138
  ${plugin} warnings:`));
133
139
  for (const warning of warnings) {
134
140
  console.log(
135
- chalk3.yellow(` - ${warning.path.join(".")}: ${warning.message}`)
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(chalk3.gray(`
146
+ console.log(chalk2.gray(`
141
147
  ${plugin} skipped features:`));
142
148
  for (const item of skipped) {
143
- console.log(chalk3.gray(` - ${item.feature}: ${item.reason}`));
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
- chalk3.red(error instanceof Error ? error.message : String(error))
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("0.1.0");
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.1.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.1.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"]}