@lnai/core 0.4.1 → 0.5.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/dist/index.d.ts +6 -1
- package/dist/index.js +144 -11
- package/package.json +3 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
|
|
3
3
|
declare const UNIFIED_DIR = ".ai";
|
|
4
|
-
declare const TOOL_IDS: readonly ["claudeCode", "opencode", "cursor", "copilot", "windsurf"];
|
|
4
|
+
declare const TOOL_IDS: readonly ["claudeCode", "opencode", "cursor", "copilot", "windsurf", "gemini"];
|
|
5
5
|
type ToolId = (typeof TOOL_IDS)[number];
|
|
6
6
|
declare const CONFIG_FILES: {
|
|
7
7
|
readonly config: "config.json";
|
|
@@ -68,6 +68,7 @@ declare const toolIdSchema: z.ZodEnum<{
|
|
|
68
68
|
cursor: "cursor";
|
|
69
69
|
copilot: "copilot";
|
|
70
70
|
windsurf: "windsurf";
|
|
71
|
+
gemini: "gemini";
|
|
71
72
|
}>;
|
|
72
73
|
/** Settings configuration (Claude format as source of truth) */
|
|
73
74
|
declare const settingsSchema: z.ZodObject<{
|
|
@@ -111,6 +112,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
111
112
|
enabled: z.ZodBoolean;
|
|
112
113
|
versionControl: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
113
114
|
}, z.core.$strip>>;
|
|
115
|
+
gemini: z.ZodOptional<z.ZodObject<{
|
|
116
|
+
enabled: z.ZodBoolean;
|
|
117
|
+
versionControl: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
118
|
+
}, z.core.$strip>>;
|
|
114
119
|
}, z.core.$strip>>;
|
|
115
120
|
}, z.core.$strip>;
|
|
116
121
|
/** Skill frontmatter (name and description required) */
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,8 @@ var TOOL_IDS = [
|
|
|
11
11
|
"opencode",
|
|
12
12
|
"cursor",
|
|
13
13
|
"copilot",
|
|
14
|
-
"windsurf"
|
|
14
|
+
"windsurf",
|
|
15
|
+
"gemini"
|
|
15
16
|
];
|
|
16
17
|
var CONFIG_FILES = {
|
|
17
18
|
config: "config.json",
|
|
@@ -28,14 +29,16 @@ var TOOL_OUTPUT_DIRS = {
|
|
|
28
29
|
opencode: ".opencode",
|
|
29
30
|
cursor: ".cursor",
|
|
30
31
|
copilot: ".github",
|
|
31
|
-
windsurf: ".windsurf"
|
|
32
|
+
windsurf: ".windsurf",
|
|
33
|
+
gemini: ".gemini"
|
|
32
34
|
};
|
|
33
35
|
var OVERRIDE_DIRS = {
|
|
34
36
|
claudeCode: ".claude",
|
|
35
37
|
opencode: ".opencode",
|
|
36
38
|
cursor: ".cursor",
|
|
37
39
|
copilot: ".copilot",
|
|
38
|
-
windsurf: ".windsurf"
|
|
40
|
+
windsurf: ".windsurf",
|
|
41
|
+
gemini: ".gemini"
|
|
39
42
|
};
|
|
40
43
|
|
|
41
44
|
// src/errors.ts
|
|
@@ -61,10 +64,10 @@ var ParseError = class extends LnaiError {
|
|
|
61
64
|
var ValidationError = class extends LnaiError {
|
|
62
65
|
path;
|
|
63
66
|
value;
|
|
64
|
-
constructor(message,
|
|
67
|
+
constructor(message, path6, value) {
|
|
65
68
|
super(message, "VALIDATION_ERROR");
|
|
66
69
|
this.name = "ValidationError";
|
|
67
|
-
this.path =
|
|
70
|
+
this.path = path6;
|
|
68
71
|
this.value = value;
|
|
69
72
|
}
|
|
70
73
|
};
|
|
@@ -120,7 +123,8 @@ var toolIdSchema = z.enum([
|
|
|
120
123
|
"opencode",
|
|
121
124
|
"cursor",
|
|
122
125
|
"copilot",
|
|
123
|
-
"windsurf"
|
|
126
|
+
"windsurf",
|
|
127
|
+
"gemini"
|
|
124
128
|
]);
|
|
125
129
|
var settingsSchema = z.object({
|
|
126
130
|
permissions: permissionsSchema.optional(),
|
|
@@ -132,7 +136,8 @@ var configSchema = z.object({
|
|
|
132
136
|
opencode: toolConfigSchema,
|
|
133
137
|
cursor: toolConfigSchema,
|
|
134
138
|
copilot: toolConfigSchema,
|
|
135
|
-
windsurf: toolConfigSchema
|
|
139
|
+
windsurf: toolConfigSchema,
|
|
140
|
+
gemini: toolConfigSchema
|
|
136
141
|
}).partial().optional()
|
|
137
142
|
});
|
|
138
143
|
var skillFrontmatterSchema = z.object({
|
|
@@ -652,6 +657,7 @@ var copilotPlugin = {
|
|
|
652
657
|
},
|
|
653
658
|
validate(state) {
|
|
654
659
|
const warnings = [];
|
|
660
|
+
const skipped = [];
|
|
655
661
|
if (!state.agents) {
|
|
656
662
|
warnings.push({
|
|
657
663
|
path: ["AGENTS.md"],
|
|
@@ -661,9 +667,9 @@ var copilotPlugin = {
|
|
|
661
667
|
const permissions = state.settings?.permissions;
|
|
662
668
|
const hasPermissions = permissions && (permissions.allow && permissions.allow.length > 0 || permissions.ask && permissions.ask.length > 0 || permissions.deny && permissions.deny.length > 0);
|
|
663
669
|
if (hasPermissions) {
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
670
|
+
skipped.push({
|
|
671
|
+
feature: "permissions",
|
|
672
|
+
reason: "GitHub Copilot does not support declarative permissions"
|
|
667
673
|
});
|
|
668
674
|
}
|
|
669
675
|
const mcpServers = state.settings?.mcpServers;
|
|
@@ -684,7 +690,7 @@ var copilotPlugin = {
|
|
|
684
690
|
}
|
|
685
691
|
}
|
|
686
692
|
}
|
|
687
|
-
return { valid: true, errors: [], warnings, skipped
|
|
693
|
+
return { valid: true, errors: [], warnings, skipped };
|
|
688
694
|
}
|
|
689
695
|
};
|
|
690
696
|
|
|
@@ -901,6 +907,132 @@ function buildCliContent(permissions) {
|
|
|
901
907
|
}
|
|
902
908
|
return { permissions: permissionsResult.permissions };
|
|
903
909
|
}
|
|
910
|
+
function getDirFromGlob(glob) {
|
|
911
|
+
const cleanPath = glob.replace(/(\*\*|\*|\{.*,.*\}).*$/, "");
|
|
912
|
+
const dir = cleanPath.replace(/\/$/, "");
|
|
913
|
+
if (dir === glob) {
|
|
914
|
+
const dirname4 = path.dirname(dir);
|
|
915
|
+
return dirname4 === "." && !dir.includes("/") ? "." : dirname4;
|
|
916
|
+
}
|
|
917
|
+
if (!dir) {
|
|
918
|
+
return ".";
|
|
919
|
+
}
|
|
920
|
+
return dir;
|
|
921
|
+
}
|
|
922
|
+
|
|
923
|
+
// src/plugins/gemini/transforms.ts
|
|
924
|
+
function transformMcpToGemini(mcpServers) {
|
|
925
|
+
if (!mcpServers) {
|
|
926
|
+
return void 0;
|
|
927
|
+
}
|
|
928
|
+
const geminiMcp = {};
|
|
929
|
+
for (const [name, config] of Object.entries(mcpServers)) {
|
|
930
|
+
if (!config.command && !config.url && !config.type) {
|
|
931
|
+
continue;
|
|
932
|
+
}
|
|
933
|
+
geminiMcp[name] = {
|
|
934
|
+
command: config.command,
|
|
935
|
+
args: config.args,
|
|
936
|
+
env: config.env
|
|
937
|
+
};
|
|
938
|
+
if (config.url) {
|
|
939
|
+
geminiMcp[name].httpUrl = config.url;
|
|
940
|
+
}
|
|
941
|
+
}
|
|
942
|
+
return Object.keys(geminiMcp).length > 0 ? geminiMcp : void 0;
|
|
943
|
+
}
|
|
944
|
+
function groupRulesByDirectory(rules) {
|
|
945
|
+
const rulesMap = /* @__PURE__ */ new Map();
|
|
946
|
+
for (const rule of rules) {
|
|
947
|
+
for (const pathGlob of rule.frontmatter.paths) {
|
|
948
|
+
const dir = getDirFromGlob(pathGlob);
|
|
949
|
+
if (!rulesMap.has(dir)) {
|
|
950
|
+
rulesMap.set(dir, []);
|
|
951
|
+
}
|
|
952
|
+
const content = `## ${rule.path}
|
|
953
|
+
|
|
954
|
+
${rule.content}
|
|
955
|
+
`;
|
|
956
|
+
rulesMap.get(dir)?.push(content);
|
|
957
|
+
}
|
|
958
|
+
}
|
|
959
|
+
return rulesMap;
|
|
960
|
+
}
|
|
961
|
+
|
|
962
|
+
// src/plugins/gemini/index.ts
|
|
963
|
+
var geminiPlugin = {
|
|
964
|
+
id: "gemini",
|
|
965
|
+
name: "Gemini CLI",
|
|
966
|
+
async detect(_rootDir) {
|
|
967
|
+
return false;
|
|
968
|
+
},
|
|
969
|
+
async import(_rootDir) {
|
|
970
|
+
return null;
|
|
971
|
+
},
|
|
972
|
+
async export(state, rootDir) {
|
|
973
|
+
const files = [];
|
|
974
|
+
const outputDir = TOOL_OUTPUT_DIRS.gemini;
|
|
975
|
+
if (state.agents) {
|
|
976
|
+
files.push({
|
|
977
|
+
path: `${outputDir}/GEMINI.md`,
|
|
978
|
+
type: "symlink",
|
|
979
|
+
target: `../${UNIFIED_DIR}/AGENTS.md`
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
const rulesMap = groupRulesByDirectory(state.rules);
|
|
983
|
+
for (const [dir, contents] of rulesMap.entries()) {
|
|
984
|
+
const combinedContent = contents.join("\n---\n\n");
|
|
985
|
+
const filePath = dir === "." ? "GEMINI.md" : `${dir}/GEMINI.md`;
|
|
986
|
+
files.push({
|
|
987
|
+
path: filePath,
|
|
988
|
+
type: "text",
|
|
989
|
+
content: combinedContent
|
|
990
|
+
});
|
|
991
|
+
}
|
|
992
|
+
for (const skill of state.skills) {
|
|
993
|
+
files.push({
|
|
994
|
+
path: `${outputDir}/skills/${skill.path}`,
|
|
995
|
+
type: "symlink",
|
|
996
|
+
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
const mcpServers = transformMcpToGemini(state.settings?.mcpServers);
|
|
1000
|
+
if (mcpServers) {
|
|
1001
|
+
files.push({
|
|
1002
|
+
path: `${outputDir}/settings.json`,
|
|
1003
|
+
type: "json",
|
|
1004
|
+
content: { mcpServers }
|
|
1005
|
+
});
|
|
1006
|
+
}
|
|
1007
|
+
return applyFileOverrides(files, rootDir, "gemini");
|
|
1008
|
+
},
|
|
1009
|
+
validate(state) {
|
|
1010
|
+
const warnings = [];
|
|
1011
|
+
const skipped = [];
|
|
1012
|
+
if (!state.agents) {
|
|
1013
|
+
warnings.push({
|
|
1014
|
+
path: ["AGENTS.md"],
|
|
1015
|
+
message: "No AGENTS.md found - GEMINI.md will not be created"
|
|
1016
|
+
});
|
|
1017
|
+
}
|
|
1018
|
+
if (state.settings?.permissions) {
|
|
1019
|
+
const hasPermissions = (state.settings.permissions.allow?.length ?? 0) > 0 || (state.settings.permissions.ask?.length ?? 0) > 0 || (state.settings.permissions.deny?.length ?? 0) > 0;
|
|
1020
|
+
if (hasPermissions) {
|
|
1021
|
+
skipped.push({
|
|
1022
|
+
feature: "permissions",
|
|
1023
|
+
reason: "Gemini CLI does not support declarative permissions - permissions must be granted interactively"
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
if (state.rules.length > 0) {
|
|
1028
|
+
warnings.push({
|
|
1029
|
+
path: ["rules"],
|
|
1030
|
+
message: "Rules will be generated into GEMINI.md files in their respective subdirectories (e.g. apps/cli/GEMINI.md)."
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
return { valid: true, errors: [], warnings, skipped };
|
|
1034
|
+
}
|
|
1035
|
+
};
|
|
904
1036
|
|
|
905
1037
|
// src/plugins/opencode/transforms.ts
|
|
906
1038
|
function transformMcpToOpenCode(servers) {
|
|
@@ -1174,6 +1306,7 @@ pluginRegistry.register(copilotPlugin);
|
|
|
1174
1306
|
pluginRegistry.register(cursorPlugin);
|
|
1175
1307
|
pluginRegistry.register(opencodePlugin);
|
|
1176
1308
|
pluginRegistry.register(windsurfPlugin);
|
|
1309
|
+
pluginRegistry.register(geminiPlugin);
|
|
1177
1310
|
function computeHash(content) {
|
|
1178
1311
|
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
1179
1312
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lnai/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Core library for LNAI - unified AI config management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -20,6 +20,8 @@
|
|
|
20
20
|
"configuration",
|
|
21
21
|
"claude",
|
|
22
22
|
"cursor",
|
|
23
|
+
"gemini",
|
|
24
|
+
"antigravity",
|
|
23
25
|
"opencode",
|
|
24
26
|
"copilot",
|
|
25
27
|
"github-copilot",
|