lnai 0.1.0 → 0.1.1
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 +51 -0
- package/dist/index.js +7 -20
- package/package.json +4 -3
- package/dist/index.js.map +0 -1
package/README.md
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img alt="LNAI Logo" src="apps/docs/public/lnai_white_on_black.png" width="200">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
# LNAI
|
|
6
|
+
|
|
7
|
+
Unified AI configuration management CLI. Define your AI tool configurations once in `.ai/` and sync them to native formats for Claude Code, Opencode, and more.
|
|
8
|
+
|
|
9
|
+
## Documentation
|
|
10
|
+
|
|
11
|
+
See the [documentation](https://lnai.sh) for detailed guides.
|
|
12
|
+
|
|
13
|
+
## Installation
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install -g lnai
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Quick Start
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
# Initialize a new .ai/ configuration
|
|
23
|
+
lnai init
|
|
24
|
+
|
|
25
|
+
# Validate your configuration
|
|
26
|
+
lnai validate
|
|
27
|
+
|
|
28
|
+
# Sync to native tool configs
|
|
29
|
+
lnai sync
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Commands
|
|
33
|
+
|
|
34
|
+
- `lnai init` - Create a new `.ai/` configuration directory
|
|
35
|
+
- `lnai validate` - Validate your `.ai/` configuration
|
|
36
|
+
- `lnai sync` - Export `.ai/` to native tool configs
|
|
37
|
+
|
|
38
|
+
## Configuration Structure
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
.ai/
|
|
42
|
+
├── config.json # Tool settings and enabled tools
|
|
43
|
+
├── settings.json # Permissions and MCP servers
|
|
44
|
+
├── AGENTS.md # Project instructions
|
|
45
|
+
├── rules/ # Path-based rules
|
|
46
|
+
└── skills/ # Custom commands
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## License
|
|
50
|
+
|
|
51
|
+
MIT
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from 'module';
|
|
2
3
|
import { Command } from 'commander';
|
|
3
|
-
import
|
|
4
|
-
import * as path from 'path';
|
|
5
|
-
import { hasUnifiedConfig, UNIFIED_DIR, initUnifiedConfig, runSyncPipeline, parseUnifiedConfig, validateUnifiedState, pluginRegistry } from '@lnai/core';
|
|
4
|
+
import { initUnifiedConfig, runSyncPipeline, parseUnifiedConfig, validateUnifiedState, pluginRegistry } from '@lnai/core';
|
|
6
5
|
import chalk3 from 'chalk';
|
|
7
6
|
import ora from 'ora';
|
|
8
7
|
|
|
@@ -10,23 +9,11 @@ var initCommand = new Command("init").description("Initialize a new .ai/ configu
|
|
|
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
19
|
console.log(chalk3.gray("\nCreated:"));
|
|
@@ -153,13 +140,13 @@ ${plugin} skipped features:`));
|
|
|
153
140
|
});
|
|
154
141
|
|
|
155
142
|
// src/index.ts
|
|
143
|
+
var require2 = createRequire(import.meta.url);
|
|
144
|
+
var pkg = require2("../package.json");
|
|
156
145
|
var program = new Command();
|
|
157
146
|
program.name("lnai").description(
|
|
158
147
|
"CLI tool that syncs a unified .ai/ config to native formats for AI coding tools"
|
|
159
|
-
).version(
|
|
148
|
+
).version(pkg.version);
|
|
160
149
|
program.addCommand(initCommand);
|
|
161
150
|
program.addCommand(syncCommand);
|
|
162
151
|
program.addCommand(validateCommand);
|
|
163
152
|
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.
|
|
3
|
+
"version": "0.1.1",
|
|
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",
|
|
@@ -28,13 +28,14 @@
|
|
|
28
28
|
"lnai": "./dist/index.js"
|
|
29
29
|
},
|
|
30
30
|
"files": [
|
|
31
|
-
"dist"
|
|
31
|
+
"dist",
|
|
32
|
+
"README.md"
|
|
32
33
|
],
|
|
33
34
|
"dependencies": {
|
|
34
35
|
"chalk": "^5.6.2",
|
|
35
36
|
"commander": "^14.0.2",
|
|
36
37
|
"ora": "^9.1.0",
|
|
37
|
-
"@lnai/core": "0.1.
|
|
38
|
+
"@lnai/core": "0.1.1"
|
|
38
39
|
},
|
|
39
40
|
"devDependencies": {
|
|
40
41
|
"@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":";;;;;;;;AAaO,IAAM,WAAA,GAAc,IAAI,OAAA,CAAQ,MAAM,EAC1C,WAAA,CAAY,+CAA+C,CAAA,CAC3D,MAAA,CAAO,SAAA,EAAW,mCAAmC,EACrD,MAAA,CAAO,WAAA,EAAa,6CAA6C,CAAA,CACjE,MAAA,CAAO,0BAA0B,4BAA4B,CAAA,CAC7D,MAAA,CAAO,OAAO,OAAA,KAAY;AACzB,EAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,EAAI;AAC5B,EAAA,MAAM,OAAA,GAAU,GAAA,CAAI,oCAAoC,CAAA,CAAE,KAAA,EAAM;AAEhE,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,gBAAA,CAAiB,OAAO,CAAA;AAE7C,IAAA,IAAI,MAAA,IAAU,CAAC,OAAA,CAAQ,KAAA,EAAO;AAC5B,MAAA,OAAA,CAAQ,IAAA;AAAA,QACN,aAAa,WAAW,CAAA,2CAAA;AAAA,OAC1B;AACA,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB;AAEA,IAAA,IAAI,MAAA,IAAU,QAAQ,KAAA,EAAO;AAC3B,MAAA,MAAS,EAAA,CAAA,EAAA,CAAQ,IAAA,CAAA,IAAA,CAAK,OAAA,EAAS,WAAW,CAAA,EAAG;AAAA,QAC3C,SAAA,EAAW,IAAA;AAAA,QACX,KAAA,EAAO;AAAA,OACR,CAAA;AAAA,IACH;AAEA,IAAA,MAAM,MAAA,GAAS,MAAM,iBAAA,CAAkB;AAAA,MACrC,OAAA;AAAA,MACA,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,SAAS,OAAA,CAAQ;AAAA,KAClB,CAAA;AAED,IAAA,OAAA,CAAQ,QAAQ,gCAAgC,CAAA;AAEhD,IAAA,OAAA,CAAQ,GAAA,CAAIA,MAAA,CAAM,IAAA,CAAK,YAAY,CAAC,CAAA;AACpC,IAAA,KAAA,MAAW,IAAA,IAAQ,OAAO,OAAA,EAAS;AACjC,MAAA,OAAA,CAAQ,IAAIA,MAAA,CAAM,KAAA,CAAM,CAAA,IAAA,EAAO,IAAI,EAAE,CAAC,CAAA;AAAA,IACxC;AAEA,IAAA,OAAA,CAAQ,GAAA;AAAA,MACNA,MAAA,CAAM,IAAA,CAAK,QAAQ,CAAA,GACjBA,MAAA,CAAM,KAAK,WAAW,CAAA,GACtBA,MAAA,CAAM,IAAA,CAAK,4BAA4B;AAAA,KAC3C;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAK,uBAAuB,CAAA;AACpC,IAAA,OAAA,CAAQ,KAAA;AAAA,MACNA,MAAA,CAAM,IAAI,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC;AAAA,KAClE;AACA,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF,CAAC,CAAA;AC3DI,IAAM,WAAA,GAAc,IAAIC,OAAAA,CAAQ,MAAM,EAC1C,WAAA,CAAY,+BAA+B,CAAA,CAC3C,MAAA,CAAO,WAAA,EAAa,yBAAyB,EAC7C,MAAA,CAAO,wBAAA,EAA0B,0BAA0B,CAAA,CAC3D,MAAA,CAAO,iBAAiB,iBAAiB,CAAA,CACzC,MAAA,CAAO,OAAO,OAAA,KAAY;AACzB,EAAA,MAAM,OAAA,GAAUC,GAAAA,CAAI,0BAA0B,CAAA,CAAE,KAAA,EAAM;AAEtD,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,MAAM,eAAA,CAAgB;AAAA,MACpC,OAAA,EAAS,QAAQ,GAAA,EAAI;AAAA,MACrB,QAAQ,OAAA,CAAQ,MAAA;AAAA,MAChB,OAAO,OAAA,CAAQ,KAAA;AAAA,MACf,SAAS,OAAA,CAAQ;AAAA,KAClB,CAAA;AAED,IAAA,OAAA,CAAQ,QAAQ,eAAe,CAAA;AAE/B,IAAA,IAAI,OAAA,CAAQ,WAAW,CAAA,EAAG;AACxB,MAAA,OAAA,CAAQ,GAAA,CAAIF,MAAAA,CAAM,MAAA,CAAO,mCAAmC,CAAC,CAAA;AAC7D,MAAA;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,MAAA,OAAA,CAAQ,GAAA,CAAIA,OAAM,IAAA,CAAK;AAAA,EAAK,MAAA,CAAO,IAAI,CAAA,CAAA,CAAG,CAAC,CAAA;AAE3C,MAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,MAAA,KAAW,CAAA,EAAG;AAC/B,QAAA,OAAA,CAAQ,GAAA,CAAIA,MAAAA,CAAM,IAAA,CAAK,cAAc,CAAC,CAAA;AAAA,MACxC;AAEA,MAAA,KAAA,MAAW,MAAA,IAAU,OAAO,OAAA,EAAS;AACnC,QAAA,MAAM,IAAA,GACJ,MAAA,CAAO,MAAA,KAAW,QAAA,GACdA,MAAAA,CAAM,MAAM,GAAG,CAAA,GACf,MAAA,CAAO,MAAA,KAAW,QAAA,GAChBA,MAAAA,CAAM,OAAO,GAAG,CAAA,GAChB,MAAA,CAAO,MAAA,KAAW,QAAA,GAChBA,MAAAA,CAAM,IAAI,GAAG,CAAA,GACbA,MAAAA,CAAM,IAAA,CAAK,GAAG,CAAA;AACxB,QAAA,OAAA,CAAQ,IAAI,CAAA,EAAA,EAAK,IAAI,CAAA,CAAA,EAAI,MAAA,CAAO,IAAI,CAAA,CAAE,CAAA;AAAA,MACxC;AAAA,IACF;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAK,aAAa,CAAA;AAC1B,IAAA,OAAA,CAAQ,KAAA;AAAA,MACNA,MAAAA,CAAM,IAAI,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC;AAAA,KAClE;AACA,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF,CAAC,CAAA;AC5CI,IAAM,eAAA,GAAkB,IAAIC,OAAAA,CAAQ,UAAU,EAClD,WAAA,CAAY,6BAA6B,CAAA,CACzC,MAAA,CAAO,wBAAA,EAA0B,0BAA0B,CAAA,CAC3D,MAAA,CAAO,OAAO,OAAA,KAAY;AACzB,EAAA,MAAM,OAAA,GAAUC,GAAAA,CAAI,6BAA6B,CAAA,CAAE,KAAA,EAAM;AAEzD,EAAA,IAAI;AACF,IAAA,MAAM,OAAA,GAAU,QAAQ,GAAA,EAAI;AAC5B,IAAA,MAAM,KAAA,GAAQ,MAAM,kBAAA,CAAmB,OAAO,CAAA;AAE9C,IAAA,MAAM,aAAA,GAAgB,qBAAqB,KAAK,CAAA;AAEhD,IAAA,IAAI,CAAC,cAAc,KAAA,EAAO;AACxB,MAAA,OAAA,CAAQ,KAAK,mBAAmB,CAAA;AAChC,MAAA,OAAA,CAAQ,GAAA,CAAIF,MAAAA,CAAM,GAAA,CAAI,0BAA0B,CAAC,CAAA;AACjD,MAAA,KAAA,MAAW,KAAA,IAAS,cAAc,MAAA,EAAQ;AACxC,QAAA,OAAA,CAAQ,GAAA;AAAA,UACNA,MAAAA,CAAM,GAAA,CAAI,CAAA,IAAA,EAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,OAAO,CAAA,CAAE;AAAA,SAC3D;AAAA,MACF;AACA,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB;AAEA,IAAA,MAAM,KAAA,GACH,OAAA,CAAQ,KAAA,IAAkC,cAAA,CAAe,MAAA,EAAO;AAEnE,IAAA,MAAM,aAGD,EAAC;AACN,IAAA,MAAM,eAGD,EAAC;AACN,IAAA,MAAM,cAGD,EAAC;AAEN,IAAA,KAAA,MAAW,UAAU,KAAA,EAAO;AAC1B,MAAA,MAAM,MAAA,GAAS,cAAA,CAAe,GAAA,CAAI,MAAM,CAAA;AACxC,MAAA,IAAI,CAAC,MAAA,EAAQ;AACX,QAAA;AAAA,MACF;AAEA,MAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,KAAK,CAAA;AAEpC,MAAA,IAAI,CAAC,OAAO,KAAA,EAAO;AACjB,QAAA,UAAA,CAAW,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAM,MAAA,EAAQ,MAAA,CAAO,QAAQ,CAAA;AAAA,MAChE;AAEA,MAAA,IAAI,MAAA,CAAO,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG;AAC9B,QAAA,YAAA,CAAa,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAM,QAAA,EAAU,MAAA,CAAO,UAAU,CAAA;AAAA,MACtE;AAEA,MAAA,IAAI,MAAA,CAAO,OAAA,CAAQ,MAAA,GAAS,CAAA,EAAG;AAC7B,QAAA,WAAA,CAAY,IAAA,CAAK,EAAE,MAAA,EAAQ,MAAA,CAAO,MAAM,OAAA,EAAS,MAAA,CAAO,SAAS,CAAA;AAAA,MACnE;AAAA,IACF;AAEA,IAAA,IAAI,UAAA,CAAW,SAAS,CAAA,EAAG;AACzB,MAAA,OAAA,CAAQ,KAAK,mBAAmB,CAAA;AAChC,MAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,MAAA,EAAO,IAAK,UAAA,EAAY;AAC3C,QAAA,OAAA,CAAQ,GAAA,CAAIA,OAAM,GAAA,CAAI;AAAA,EAAK,MAAM,UAAU,CAAC,CAAA;AAC5C,QAAA,KAAA,MAAW,SAAS,MAAA,EAAQ;AAC1B,UAAA,OAAA,CAAQ,GAAA;AAAA,YACNA,MAAAA,CAAM,GAAA,CAAI,CAAA,IAAA,EAAO,KAAA,CAAM,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAA,EAAK,KAAA,CAAM,OAAO,CAAA,CAAE;AAAA,WAC3D;AAAA,QACF;AAAA,MACF;AACA,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB;AAEA,IAAA,OAAA,CAAQ,QAAQ,mBAAmB,CAAA;AAEnC,IAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,QAAA,EAAS,IAAK,YAAA,EAAc;AAC/C,MAAA,OAAA,CAAQ,GAAA,CAAIA,OAAM,MAAA,CAAO;AAAA,EAAK,MAAM,YAAY,CAAC,CAAA;AACjD,MAAA,KAAA,MAAW,WAAW,QAAA,EAAU;AAC9B,QAAA,OAAA,CAAQ,GAAA;AAAA,UACNA,MAAAA,CAAM,MAAA,CAAO,CAAA,IAAA,EAAO,OAAA,CAAQ,IAAA,CAAK,IAAA,CAAK,GAAG,CAAC,CAAA,EAAA,EAAK,OAAA,CAAQ,OAAO,CAAA,CAAE;AAAA,SAClE;AAAA,MACF;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,EAAE,MAAA,EAAQ,OAAA,EAAQ,IAAK,WAAA,EAAa;AAC7C,MAAA,OAAA,CAAQ,GAAA,CAAIA,OAAM,IAAA,CAAK;AAAA,EAAK,MAAM,oBAAoB,CAAC,CAAA;AACvD,MAAA,KAAA,MAAW,QAAQ,OAAA,EAAS;AAC1B,QAAA,OAAA,CAAQ,GAAA,CAAIA,MAAAA,CAAM,IAAA,CAAK,CAAA,IAAA,EAAO,IAAA,CAAK,OAAO,CAAA,EAAA,EAAK,IAAA,CAAK,MAAM,CAAA,CAAE,CAAC,CAAA;AAAA,MAC/D;AAAA,IACF;AAAA,EACF,SAAS,KAAA,EAAO;AACd,IAAA,OAAA,CAAQ,KAAK,mBAAmB,CAAA;AAChC,IAAA,OAAA,CAAQ,KAAA;AAAA,MACNA,MAAAA,CAAM,IAAI,KAAA,YAAiB,KAAA,GAAQ,MAAM,OAAA,GAAU,MAAA,CAAO,KAAK,CAAC;AAAA,KAClE;AACA,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,EAChB;AACF,CAAC,CAAA;;;ACrGH,IAAM,OAAA,GAAU,IAAIC,OAAAA,EAAQ;AAE5B,OAAA,CACG,IAAA,CAAK,MAAM,CAAA,CACX,WAAA;AAAA,EACC;AACF,CAAA,CACC,QAAQ,OAAO,CAAA;AAElB,OAAA,CAAQ,WAAW,WAAW,CAAA;AAC9B,OAAA,CAAQ,WAAW,WAAW,CAAA;AAC9B,OAAA,CAAQ,WAAW,eAAe,CAAA;AAElC,OAAA,CAAQ,KAAA,EAAM","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"]}
|