@lnai/core 0.3.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/dist/index.d.ts +8 -2
- package/dist/index.js +137 -12
- package/package.json +2 -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"];
|
|
4
|
+
declare const TOOL_IDS: readonly ["claudeCode", "opencode", "cursor", "copilot", "windsurf"];
|
|
5
5
|
type ToolId = (typeof TOOL_IDS)[number];
|
|
6
6
|
declare const CONFIG_FILES: {
|
|
7
7
|
readonly config: "config.json";
|
|
@@ -67,6 +67,7 @@ declare const toolIdSchema: z.ZodEnum<{
|
|
|
67
67
|
opencode: "opencode";
|
|
68
68
|
cursor: "cursor";
|
|
69
69
|
copilot: "copilot";
|
|
70
|
+
windsurf: "windsurf";
|
|
70
71
|
}>;
|
|
71
72
|
/** Settings configuration (Claude format as source of truth) */
|
|
72
73
|
declare const settingsSchema: z.ZodObject<{
|
|
@@ -106,6 +107,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
106
107
|
enabled: z.ZodBoolean;
|
|
107
108
|
versionControl: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
108
109
|
}, z.core.$strip>>;
|
|
110
|
+
windsurf: z.ZodOptional<z.ZodObject<{
|
|
111
|
+
enabled: z.ZodBoolean;
|
|
112
|
+
versionControl: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
113
|
+
}, z.core.$strip>>;
|
|
109
114
|
}, z.core.$strip>>;
|
|
110
115
|
}, z.core.$strip>;
|
|
111
116
|
/** Skill frontmatter (name and description required) */
|
|
@@ -301,12 +306,13 @@ interface InitOptions {
|
|
|
301
306
|
tools?: ToolId[];
|
|
302
307
|
minimal?: boolean;
|
|
303
308
|
force?: boolean;
|
|
309
|
+
versionControl?: Record<ToolId, boolean>;
|
|
304
310
|
}
|
|
305
311
|
interface InitResult {
|
|
306
312
|
created: string[];
|
|
307
313
|
}
|
|
308
314
|
declare function initUnifiedConfig(options: InitOptions): Promise<InitResult>;
|
|
309
315
|
declare function hasUnifiedConfig(rootDir: string): Promise<boolean>;
|
|
310
|
-
declare function generateDefaultConfig(tools?: ToolId[]): Config;
|
|
316
|
+
declare function generateDefaultConfig(tools?: ToolId[], versionControl?: Record<ToolId, boolean>): Config;
|
|
311
317
|
|
|
312
318
|
export { CONFIG_DIRS, CONFIG_FILES, type ChangeResult, type Config, FileNotFoundError, type InitOptions, type InitResult, LnaiError, type MarkdownFile, type MarkdownFrontmatter, type McpServer, type OutputFile, ParseError, type PermissionLevel, type Permissions, type Plugin, PluginError, type RuleFrontmatter, type Settings, type SkillFrontmatter, type SkippedFeatureDetail, type SyncOptions, type SyncResult, TOOL_IDS, TOOL_OUTPUT_DIRS, type ToolConfig, type ToolId, UNIFIED_DIR, type UnifiedState, ValidationError, type ValidationErrorDetail, type ValidationResult, type ValidationWarningDetail, WriteError, type WriterOptions, claudeCodePlugin, computeHash, configSchema, generateDefaultConfig, hasUnifiedConfig, initUnifiedConfig, mcpServerSchema, opencodePlugin, parseFrontmatter, parseUnifiedConfig, permissionsSchema, pluginRegistry, ruleFrontmatterSchema, runSyncPipeline, settingsSchema, skillFrontmatterSchema, toolConfigSchema, toolIdSchema, updateGitignore, validateConfig, validateSettings, validateUnifiedState, writeFiles };
|
package/dist/index.js
CHANGED
|
@@ -6,7 +6,13 @@ import * as crypto from 'crypto';
|
|
|
6
6
|
|
|
7
7
|
// src/constants.ts
|
|
8
8
|
var UNIFIED_DIR = ".ai";
|
|
9
|
-
var TOOL_IDS = [
|
|
9
|
+
var TOOL_IDS = [
|
|
10
|
+
"claudeCode",
|
|
11
|
+
"opencode",
|
|
12
|
+
"cursor",
|
|
13
|
+
"copilot",
|
|
14
|
+
"windsurf"
|
|
15
|
+
];
|
|
10
16
|
var CONFIG_FILES = {
|
|
11
17
|
config: "config.json",
|
|
12
18
|
settings: "settings.json",
|
|
@@ -21,13 +27,15 @@ var TOOL_OUTPUT_DIRS = {
|
|
|
21
27
|
claudeCode: ".claude",
|
|
22
28
|
opencode: ".opencode",
|
|
23
29
|
cursor: ".cursor",
|
|
24
|
-
copilot: ".github"
|
|
30
|
+
copilot: ".github",
|
|
31
|
+
windsurf: ".windsurf"
|
|
25
32
|
};
|
|
26
33
|
var OVERRIDE_DIRS = {
|
|
27
34
|
claudeCode: ".claude",
|
|
28
35
|
opencode: ".opencode",
|
|
29
36
|
cursor: ".cursor",
|
|
30
|
-
copilot: ".copilot"
|
|
37
|
+
copilot: ".copilot",
|
|
38
|
+
windsurf: ".windsurf"
|
|
31
39
|
};
|
|
32
40
|
|
|
33
41
|
// src/errors.ts
|
|
@@ -107,7 +115,13 @@ var toolConfigSchema = z.object({
|
|
|
107
115
|
enabled: z.boolean(),
|
|
108
116
|
versionControl: z.boolean().optional().default(false)
|
|
109
117
|
});
|
|
110
|
-
var toolIdSchema = z.enum([
|
|
118
|
+
var toolIdSchema = z.enum([
|
|
119
|
+
"claudeCode",
|
|
120
|
+
"opencode",
|
|
121
|
+
"cursor",
|
|
122
|
+
"copilot",
|
|
123
|
+
"windsurf"
|
|
124
|
+
]);
|
|
111
125
|
var settingsSchema = z.object({
|
|
112
126
|
permissions: permissionsSchema.optional(),
|
|
113
127
|
mcpServers: z.record(z.string(), mcpServerSchema).optional()
|
|
@@ -117,7 +131,8 @@ var configSchema = z.object({
|
|
|
117
131
|
claudeCode: toolConfigSchema,
|
|
118
132
|
opencode: toolConfigSchema,
|
|
119
133
|
cursor: toolConfigSchema,
|
|
120
|
-
copilot: toolConfigSchema
|
|
134
|
+
copilot: toolConfigSchema,
|
|
135
|
+
windsurf: toolConfigSchema
|
|
121
136
|
}).partial().optional()
|
|
122
137
|
});
|
|
123
138
|
var skillFrontmatterSchema = z.object({
|
|
@@ -1049,11 +1064,116 @@ var PluginRegistry = class {
|
|
|
1049
1064
|
};
|
|
1050
1065
|
var pluginRegistry = new PluginRegistry();
|
|
1051
1066
|
|
|
1067
|
+
// src/plugins/windsurf/transforms.ts
|
|
1068
|
+
function transformRuleToWindsurf(rule) {
|
|
1069
|
+
const frontmatter = {
|
|
1070
|
+
trigger: "manual"
|
|
1071
|
+
};
|
|
1072
|
+
return {
|
|
1073
|
+
frontmatter,
|
|
1074
|
+
content: rule.content
|
|
1075
|
+
};
|
|
1076
|
+
}
|
|
1077
|
+
function serializeWindsurfRule(frontmatter, content) {
|
|
1078
|
+
const lines = ["---"];
|
|
1079
|
+
lines.push(`trigger: ${frontmatter.trigger}`);
|
|
1080
|
+
if (frontmatter.globs && frontmatter.globs.length > 0) {
|
|
1081
|
+
lines.push("globs:");
|
|
1082
|
+
for (const glob of frontmatter.globs) {
|
|
1083
|
+
lines.push(` - ${glob}`);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
if (frontmatter.description) {
|
|
1087
|
+
const escaped = frontmatter.description.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
|
|
1088
|
+
lines.push(`description: "${escaped}"`);
|
|
1089
|
+
}
|
|
1090
|
+
lines.push("---");
|
|
1091
|
+
lines.push("");
|
|
1092
|
+
lines.push(content);
|
|
1093
|
+
return lines.join("\n");
|
|
1094
|
+
}
|
|
1095
|
+
|
|
1096
|
+
// src/plugins/windsurf/index.ts
|
|
1097
|
+
var windsurfPlugin = {
|
|
1098
|
+
id: "windsurf",
|
|
1099
|
+
name: "Windsurf",
|
|
1100
|
+
async detect(_rootDir) {
|
|
1101
|
+
return false;
|
|
1102
|
+
},
|
|
1103
|
+
async import(_rootDir) {
|
|
1104
|
+
return null;
|
|
1105
|
+
},
|
|
1106
|
+
async export(state, rootDir) {
|
|
1107
|
+
const files = [];
|
|
1108
|
+
const outputDir = TOOL_OUTPUT_DIRS.windsurf;
|
|
1109
|
+
if (state.agents) {
|
|
1110
|
+
files.push({
|
|
1111
|
+
path: "AGENTS.md",
|
|
1112
|
+
type: "symlink",
|
|
1113
|
+
target: `${UNIFIED_DIR}/AGENTS.md`
|
|
1114
|
+
});
|
|
1115
|
+
}
|
|
1116
|
+
for (const rule of state.rules) {
|
|
1117
|
+
const transformed = transformRuleToWindsurf(rule);
|
|
1118
|
+
const ruleContent = serializeWindsurfRule(
|
|
1119
|
+
transformed.frontmatter,
|
|
1120
|
+
transformed.content
|
|
1121
|
+
);
|
|
1122
|
+
files.push({
|
|
1123
|
+
path: `${outputDir}/rules/${rule.path}`,
|
|
1124
|
+
type: "text",
|
|
1125
|
+
content: ruleContent
|
|
1126
|
+
});
|
|
1127
|
+
}
|
|
1128
|
+
for (const skill of state.skills) {
|
|
1129
|
+
files.push({
|
|
1130
|
+
path: `${outputDir}/skills/${skill.path}`,
|
|
1131
|
+
type: "symlink",
|
|
1132
|
+
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
return applyFileOverrides(files, rootDir, "windsurf");
|
|
1136
|
+
},
|
|
1137
|
+
validate(state) {
|
|
1138
|
+
const warnings = [];
|
|
1139
|
+
const skipped = [];
|
|
1140
|
+
if (!state.agents) {
|
|
1141
|
+
warnings.push({
|
|
1142
|
+
path: ["AGENTS.md"],
|
|
1143
|
+
message: "No AGENTS.md found - root AGENTS.md will not be created"
|
|
1144
|
+
});
|
|
1145
|
+
}
|
|
1146
|
+
if (state.rules.length > 0) {
|
|
1147
|
+
warnings.push({
|
|
1148
|
+
path: [".windsurf/rules"],
|
|
1149
|
+
message: "Rules are exported with 'trigger: manual' and require explicit @mention to invoke"
|
|
1150
|
+
});
|
|
1151
|
+
}
|
|
1152
|
+
if (state.settings?.mcpServers && Object.keys(state.settings.mcpServers).length > 0) {
|
|
1153
|
+
skipped.push({
|
|
1154
|
+
feature: "mcpServers",
|
|
1155
|
+
reason: "Windsurf uses global MCP config at ~/.codeium/windsurf/mcp_config.json - project-level MCP servers are not exported"
|
|
1156
|
+
});
|
|
1157
|
+
}
|
|
1158
|
+
if (state.settings?.permissions) {
|
|
1159
|
+
const hasPermissions = (state.settings.permissions.allow?.length ?? 0) > 0 || (state.settings.permissions.ask?.length ?? 0) > 0 || (state.settings.permissions.deny?.length ?? 0) > 0;
|
|
1160
|
+
if (hasPermissions) {
|
|
1161
|
+
skipped.push({
|
|
1162
|
+
feature: "permissions",
|
|
1163
|
+
reason: "Windsurf does not support declarative permissions"
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
return { valid: true, errors: [], warnings, skipped };
|
|
1168
|
+
}
|
|
1169
|
+
};
|
|
1170
|
+
|
|
1052
1171
|
// src/plugins/index.ts
|
|
1053
1172
|
pluginRegistry.register(claudeCodePlugin);
|
|
1054
1173
|
pluginRegistry.register(copilotPlugin);
|
|
1055
1174
|
pluginRegistry.register(cursorPlugin);
|
|
1056
1175
|
pluginRegistry.register(opencodePlugin);
|
|
1176
|
+
pluginRegistry.register(windsurfPlugin);
|
|
1057
1177
|
function computeHash(content) {
|
|
1058
1178
|
return crypto.createHash("sha256").update(content, "utf-8").digest("hex");
|
|
1059
1179
|
}
|
|
@@ -1166,9 +1286,8 @@ async function updateGitignore(rootDir, paths) {
|
|
|
1166
1286
|
const markerRegex = new RegExp(`${marker}[\\s\\S]*?${endMarker}\\n?`, "g");
|
|
1167
1287
|
content = content.replace(markerRegex, "");
|
|
1168
1288
|
content = content.trimEnd();
|
|
1169
|
-
const
|
|
1170
|
-
|
|
1171
|
-
);
|
|
1289
|
+
const uniquePaths = [...new Set(paths)];
|
|
1290
|
+
const newSection = ["", marker, ...uniquePaths, endMarker, ""].join("\n");
|
|
1172
1291
|
content = content + newSection;
|
|
1173
1292
|
await fs3.writeFile(gitignorePath, content, "utf-8");
|
|
1174
1293
|
}
|
|
@@ -1244,10 +1363,16 @@ async function runSyncPipeline(options) {
|
|
|
1244
1363
|
return results;
|
|
1245
1364
|
}
|
|
1246
1365
|
async function initUnifiedConfig(options) {
|
|
1247
|
-
const {
|
|
1366
|
+
const {
|
|
1367
|
+
rootDir,
|
|
1368
|
+
tools,
|
|
1369
|
+
minimal = false,
|
|
1370
|
+
force = false,
|
|
1371
|
+
versionControl
|
|
1372
|
+
} = options;
|
|
1248
1373
|
const aiDir = path.join(rootDir, UNIFIED_DIR);
|
|
1249
1374
|
const created = [];
|
|
1250
|
-
const config = generateDefaultConfig(tools);
|
|
1375
|
+
const config = generateDefaultConfig(tools, versionControl);
|
|
1251
1376
|
const exists = await hasUnifiedConfig(rootDir);
|
|
1252
1377
|
if (exists && !force) {
|
|
1253
1378
|
throw new ValidationError(
|
|
@@ -1289,7 +1414,7 @@ async function hasUnifiedConfig(rootDir) {
|
|
|
1289
1414
|
return false;
|
|
1290
1415
|
}
|
|
1291
1416
|
}
|
|
1292
|
-
function generateDefaultConfig(tools) {
|
|
1417
|
+
function generateDefaultConfig(tools, versionControl) {
|
|
1293
1418
|
if (tools) {
|
|
1294
1419
|
const validation = validateToolIds(tools);
|
|
1295
1420
|
if (!validation.valid) {
|
|
@@ -1306,7 +1431,7 @@ function generateDefaultConfig(tools) {
|
|
|
1306
1431
|
for (const toolId of TOOL_IDS) {
|
|
1307
1432
|
toolsConfig[toolId] = {
|
|
1308
1433
|
enabled: enabledTools.includes(toolId),
|
|
1309
|
-
versionControl: false
|
|
1434
|
+
versionControl: versionControl?.[toolId] ?? false
|
|
1310
1435
|
};
|
|
1311
1436
|
}
|
|
1312
1437
|
return { tools: toolsConfig };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lnai/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Core library for LNAI - unified AI config management",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"opencode",
|
|
24
24
|
"copilot",
|
|
25
25
|
"github-copilot",
|
|
26
|
+
"windsurf",
|
|
26
27
|
"cli",
|
|
27
28
|
"ai-tools"
|
|
28
29
|
],
|