@lnai/core 0.6.5 → 0.6.6
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 +3 -3
- package/dist/index.js +138 -176
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -283,7 +283,7 @@ declare const claudeCodePlugin: Plugin;
|
|
|
283
283
|
* Output structure:
|
|
284
284
|
* - AGENTS.md (symlink -> .ai/AGENTS.md) [at project root]
|
|
285
285
|
* - <dir>/AGENTS.md (generated from .ai/rules/*.md, per glob directory)
|
|
286
|
-
* - .
|
|
286
|
+
* - .agents/skills/<name>/ (symlink -> ../../.ai/skills/<name>)
|
|
287
287
|
* - .codex/config.toml (generated from settings.mcpServers)
|
|
288
288
|
* - .codex/<path> (symlink -> ../.ai/.codex/<path>) for override files
|
|
289
289
|
*/
|
|
@@ -295,7 +295,7 @@ declare const codexPlugin: Plugin;
|
|
|
295
295
|
* Output structure:
|
|
296
296
|
* - AGENTS.md (symlink -> .ai/AGENTS.md) [at project root]
|
|
297
297
|
* - .opencode/rules/ (symlink -> ../.ai/rules)
|
|
298
|
-
* - .
|
|
298
|
+
* - .agents/skills/<name>/ (symlink -> ../../.ai/skills/<name>)
|
|
299
299
|
* - opencode.json (generated config merged with .ai/.opencode/opencode.json)
|
|
300
300
|
* - .opencode/<path> (symlink -> ../.ai/.opencode/<path>) for other override files
|
|
301
301
|
*/
|
|
@@ -343,7 +343,7 @@ declare function writeFiles(files: OutputFile[], options: WriterOptions): Promis
|
|
|
343
343
|
/**
|
|
344
344
|
* Update .gitignore with paths that should not be version controlled.
|
|
345
345
|
* Manages a dedicated "lnai-generated" section to avoid conflicts with user entries.
|
|
346
|
-
*
|
|
346
|
+
* Replaces the managed section on each run so stale paths are removed.
|
|
347
347
|
*/
|
|
348
348
|
declare function updateGitignore(rootDir: string, paths: string[]): Promise<void>;
|
|
349
349
|
|
package/dist/index.js
CHANGED
|
@@ -413,6 +413,39 @@ function validateToolIds(tools) {
|
|
|
413
413
|
}
|
|
414
414
|
return { valid: true, errors: [], warnings: [], skipped: [] };
|
|
415
415
|
}
|
|
416
|
+
|
|
417
|
+
// src/utils/agents.ts
|
|
418
|
+
function createRootAgentsMdSymlink(state) {
|
|
419
|
+
if (!state.agents) {
|
|
420
|
+
return null;
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
path: "AGENTS.md",
|
|
424
|
+
type: "symlink",
|
|
425
|
+
target: `${UNIFIED_DIR}/AGENTS.md`
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
function createSkillSymlinks(state, outputDir) {
|
|
429
|
+
const depth = outputDir.split("/").length + 1;
|
|
430
|
+
const prefix = "../".repeat(depth);
|
|
431
|
+
return state.skills.map((skill) => ({
|
|
432
|
+
path: `${outputDir}/skills/${skill.path}`,
|
|
433
|
+
type: "symlink",
|
|
434
|
+
target: `${prefix}${UNIFIED_DIR}/skills/${skill.path}`
|
|
435
|
+
}));
|
|
436
|
+
}
|
|
437
|
+
function createNoAgentsMdWarning(outputDescription) {
|
|
438
|
+
return {
|
|
439
|
+
path: ["AGENTS.md"],
|
|
440
|
+
message: `No AGENTS.md found - ${outputDescription} will not be created`
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function hasPermissionsConfigured(permissions) {
|
|
444
|
+
if (!permissions) {
|
|
445
|
+
return false;
|
|
446
|
+
}
|
|
447
|
+
return (permissions.allow?.length ?? 0) > 0 || (permissions.ask?.length ?? 0) > 0 || (permissions.deny?.length ?? 0) > 0;
|
|
448
|
+
}
|
|
416
449
|
async function scanOverrideDirectory(rootDir, toolId) {
|
|
417
450
|
const overrideDir = path.join(rootDir, UNIFIED_DIR, OVERRIDE_DIRS[toolId]);
|
|
418
451
|
try {
|
|
@@ -457,6 +490,7 @@ async function applyFileOverrides(files, rootDir, toolId) {
|
|
|
457
490
|
}
|
|
458
491
|
|
|
459
492
|
// src/plugins/claude-code/index.ts
|
|
493
|
+
var OUTPUT_DIR = TOOL_OUTPUT_DIRS.claudeCode;
|
|
460
494
|
var claudeCodePlugin = {
|
|
461
495
|
id: "claudeCode",
|
|
462
496
|
name: "Claude Code",
|
|
@@ -468,28 +502,21 @@ var claudeCodePlugin = {
|
|
|
468
502
|
},
|
|
469
503
|
async export(state, rootDir) {
|
|
470
504
|
const files = [];
|
|
471
|
-
const outputDir = TOOL_OUTPUT_DIRS.claudeCode;
|
|
472
505
|
if (state.agents) {
|
|
473
506
|
files.push({
|
|
474
|
-
path: `${
|
|
507
|
+
path: `${OUTPUT_DIR}/CLAUDE.md`,
|
|
475
508
|
type: "symlink",
|
|
476
509
|
target: `../${UNIFIED_DIR}/AGENTS.md`
|
|
477
510
|
});
|
|
478
511
|
}
|
|
479
512
|
if (state.rules.length > 0) {
|
|
480
513
|
files.push({
|
|
481
|
-
path: `${
|
|
514
|
+
path: `${OUTPUT_DIR}/rules`,
|
|
482
515
|
type: "symlink",
|
|
483
516
|
target: `../${UNIFIED_DIR}/rules`
|
|
484
517
|
});
|
|
485
518
|
}
|
|
486
|
-
|
|
487
|
-
files.push({
|
|
488
|
-
path: `${outputDir}/skills/${skill.path}`,
|
|
489
|
-
type: "symlink",
|
|
490
|
-
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
491
|
-
});
|
|
492
|
-
}
|
|
519
|
+
files.push(...createSkillSymlinks(state, OUTPUT_DIR));
|
|
493
520
|
const settings = {};
|
|
494
521
|
if (state.settings?.permissions) {
|
|
495
522
|
settings["permissions"] = state.settings.permissions;
|
|
@@ -499,7 +526,7 @@ var claudeCodePlugin = {
|
|
|
499
526
|
}
|
|
500
527
|
if (Object.keys(settings).length > 0) {
|
|
501
528
|
files.push({
|
|
502
|
-
path: `${
|
|
529
|
+
path: `${OUTPUT_DIR}/settings.json`,
|
|
503
530
|
type: "json",
|
|
504
531
|
content: settings
|
|
505
532
|
});
|
|
@@ -509,10 +536,7 @@ var claudeCodePlugin = {
|
|
|
509
536
|
validate(state) {
|
|
510
537
|
const warnings = [];
|
|
511
538
|
if (!state.agents) {
|
|
512
|
-
warnings.push(
|
|
513
|
-
path: ["AGENTS.md"],
|
|
514
|
-
message: "No AGENTS.md found - .claude/CLAUDE.md will not be created"
|
|
515
|
-
});
|
|
539
|
+
warnings.push(createNoAgentsMdWarning(".claude/CLAUDE.md"));
|
|
516
540
|
}
|
|
517
541
|
return { valid: true, errors: [], warnings, skipped: [] };
|
|
518
542
|
}
|
|
@@ -554,6 +578,8 @@ ${rule.content}
|
|
|
554
578
|
}
|
|
555
579
|
|
|
556
580
|
// src/plugins/codex/index.ts
|
|
581
|
+
var OUTPUT_DIR2 = TOOL_OUTPUT_DIRS.codex;
|
|
582
|
+
var SKILLS_DIR = ".agents";
|
|
557
583
|
var codexPlugin = {
|
|
558
584
|
id: "codex",
|
|
559
585
|
name: "Codex",
|
|
@@ -565,13 +591,9 @@ var codexPlugin = {
|
|
|
565
591
|
},
|
|
566
592
|
async export(state, rootDir) {
|
|
567
593
|
const files = [];
|
|
568
|
-
const
|
|
569
|
-
if (
|
|
570
|
-
files.push(
|
|
571
|
-
path: "AGENTS.md",
|
|
572
|
-
type: "symlink",
|
|
573
|
-
target: `${UNIFIED_DIR}/AGENTS.md`
|
|
574
|
-
});
|
|
594
|
+
const agentsSymlink = createRootAgentsMdSymlink(state);
|
|
595
|
+
if (agentsSymlink) {
|
|
596
|
+
files.push(agentsSymlink);
|
|
575
597
|
}
|
|
576
598
|
const rulesMap = groupRulesByDirectory(state.rules);
|
|
577
599
|
for (const [dir, contents] of rulesMap.entries()) {
|
|
@@ -585,17 +607,11 @@ var codexPlugin = {
|
|
|
585
607
|
content: combinedContent
|
|
586
608
|
});
|
|
587
609
|
}
|
|
588
|
-
|
|
589
|
-
files.push({
|
|
590
|
-
path: `${outputDir}/skills/${skill.path}`,
|
|
591
|
-
type: "symlink",
|
|
592
|
-
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
593
|
-
});
|
|
594
|
-
}
|
|
610
|
+
files.push(...createSkillSymlinks(state, SKILLS_DIR));
|
|
595
611
|
const configToml = buildCodexConfigToml(state.settings?.mcpServers);
|
|
596
612
|
if (configToml) {
|
|
597
613
|
files.push({
|
|
598
|
-
path: `${
|
|
614
|
+
path: `${OUTPUT_DIR2}/config.toml`,
|
|
599
615
|
type: "text",
|
|
600
616
|
content: configToml
|
|
601
617
|
});
|
|
@@ -606,10 +622,7 @@ var codexPlugin = {
|
|
|
606
622
|
const warnings = [];
|
|
607
623
|
const skipped = [];
|
|
608
624
|
if (!state.agents) {
|
|
609
|
-
warnings.push(
|
|
610
|
-
path: ["AGENTS.md"],
|
|
611
|
-
message: "No AGENTS.md found - root AGENTS.md will not be created"
|
|
612
|
-
});
|
|
625
|
+
warnings.push(createNoAgentsMdWarning("root AGENTS.md"));
|
|
613
626
|
}
|
|
614
627
|
const rulesMap = groupRulesByDirectory(state.rules);
|
|
615
628
|
if (rulesMap.has(".")) {
|
|
@@ -629,14 +642,11 @@ var codexPlugin = {
|
|
|
629
642
|
}
|
|
630
643
|
}
|
|
631
644
|
}
|
|
632
|
-
if (state.settings?.permissions) {
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
reason: "Codex rules are not generated from LNAI permissions"
|
|
638
|
-
});
|
|
639
|
-
}
|
|
645
|
+
if (hasPermissionsConfigured(state.settings?.permissions)) {
|
|
646
|
+
skipped.push({
|
|
647
|
+
feature: "permissions",
|
|
648
|
+
reason: "Codex rules are not generated from LNAI permissions"
|
|
649
|
+
});
|
|
640
650
|
}
|
|
641
651
|
return { valid: true, errors: [], warnings, skipped };
|
|
642
652
|
}
|
|
@@ -826,6 +836,7 @@ function transformMcpToCopilot(servers) {
|
|
|
826
836
|
}
|
|
827
837
|
|
|
828
838
|
// src/plugins/copilot/index.ts
|
|
839
|
+
var OUTPUT_DIR3 = TOOL_OUTPUT_DIRS.copilot;
|
|
829
840
|
var copilotPlugin = {
|
|
830
841
|
id: "copilot",
|
|
831
842
|
name: "GitHub Copilot",
|
|
@@ -837,12 +848,9 @@ var copilotPlugin = {
|
|
|
837
848
|
},
|
|
838
849
|
async export(state, rootDir) {
|
|
839
850
|
const files = [];
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
type: "symlink",
|
|
844
|
-
target: `../${UNIFIED_DIR}/AGENTS.md`
|
|
845
|
-
});
|
|
851
|
+
const agentsSymlink = createRootAgentsMdSymlink(state);
|
|
852
|
+
if (agentsSymlink) {
|
|
853
|
+
files.push(agentsSymlink);
|
|
846
854
|
}
|
|
847
855
|
for (const rule of state.rules) {
|
|
848
856
|
const transformed = transformRuleToCopilot(rule);
|
|
@@ -852,18 +860,12 @@ var copilotPlugin = {
|
|
|
852
860
|
);
|
|
853
861
|
const outputFilename = rule.path.replace(/\.md$/, ".instructions.md");
|
|
854
862
|
files.push({
|
|
855
|
-
path:
|
|
863
|
+
path: `${OUTPUT_DIR3}/instructions/${outputFilename}`,
|
|
856
864
|
type: "text",
|
|
857
865
|
content: ruleContent
|
|
858
866
|
});
|
|
859
867
|
}
|
|
860
|
-
|
|
861
|
-
files.push({
|
|
862
|
-
path: `.github/skills/${skill.path}`,
|
|
863
|
-
type: "symlink",
|
|
864
|
-
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
865
|
-
});
|
|
866
|
-
}
|
|
868
|
+
files.push(...createSkillSymlinks(state, OUTPUT_DIR3));
|
|
867
869
|
const mcpConfig = transformMcpToCopilot(state.settings?.mcpServers);
|
|
868
870
|
if (mcpConfig) {
|
|
869
871
|
files.push({
|
|
@@ -878,14 +880,9 @@ var copilotPlugin = {
|
|
|
878
880
|
const warnings = [];
|
|
879
881
|
const skipped = [];
|
|
880
882
|
if (!state.agents) {
|
|
881
|
-
warnings.push(
|
|
882
|
-
path: ["AGENTS.md"],
|
|
883
|
-
message: "No AGENTS.md found - .github/copilot-instructions.md will not be created"
|
|
884
|
-
});
|
|
883
|
+
warnings.push(createNoAgentsMdWarning("root AGENTS.md"));
|
|
885
884
|
}
|
|
886
|
-
|
|
887
|
-
const hasPermissions = permissions && (permissions.allow && permissions.allow.length > 0 || permissions.ask && permissions.ask.length > 0 || permissions.deny && permissions.deny.length > 0);
|
|
888
|
-
if (hasPermissions) {
|
|
885
|
+
if (hasPermissionsConfigured(state.settings?.permissions)) {
|
|
889
886
|
skipped.push({
|
|
890
887
|
feature: "permissions",
|
|
891
888
|
reason: "GitHub Copilot does not support declarative permissions"
|
|
@@ -1017,6 +1014,7 @@ function transformPermissionRule(rule) {
|
|
|
1017
1014
|
}
|
|
1018
1015
|
|
|
1019
1016
|
// src/plugins/cursor/index.ts
|
|
1017
|
+
var OUTPUT_DIR4 = TOOL_OUTPUT_DIRS.cursor;
|
|
1020
1018
|
var cursorPlugin = {
|
|
1021
1019
|
id: "cursor",
|
|
1022
1020
|
name: "Cursor",
|
|
@@ -1028,13 +1026,9 @@ var cursorPlugin = {
|
|
|
1028
1026
|
},
|
|
1029
1027
|
async export(state, rootDir) {
|
|
1030
1028
|
const files = [];
|
|
1031
|
-
const
|
|
1032
|
-
if (
|
|
1033
|
-
files.push(
|
|
1034
|
-
path: "AGENTS.md",
|
|
1035
|
-
type: "symlink",
|
|
1036
|
-
target: `${UNIFIED_DIR}/AGENTS.md`
|
|
1037
|
-
});
|
|
1029
|
+
const agentsSymlink = createRootAgentsMdSymlink(state);
|
|
1030
|
+
if (agentsSymlink) {
|
|
1031
|
+
files.push(agentsSymlink);
|
|
1038
1032
|
}
|
|
1039
1033
|
for (const rule of state.rules) {
|
|
1040
1034
|
const transformed = transformRuleToCursor(rule);
|
|
@@ -1044,22 +1038,16 @@ var cursorPlugin = {
|
|
|
1044
1038
|
);
|
|
1045
1039
|
const outputFilename = rule.path.replace(/\.md$/, ".mdc");
|
|
1046
1040
|
files.push({
|
|
1047
|
-
path: `${
|
|
1041
|
+
path: `${OUTPUT_DIR4}/rules/${outputFilename}`,
|
|
1048
1042
|
type: "text",
|
|
1049
1043
|
content: ruleContent
|
|
1050
1044
|
});
|
|
1051
1045
|
}
|
|
1052
|
-
|
|
1053
|
-
files.push({
|
|
1054
|
-
path: `${outputDir}/skills/${skill.path}`,
|
|
1055
|
-
type: "symlink",
|
|
1056
|
-
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
1057
|
-
});
|
|
1058
|
-
}
|
|
1046
|
+
files.push(...createSkillSymlinks(state, OUTPUT_DIR4));
|
|
1059
1047
|
const mcpServers = transformMcpToCursor(state.settings?.mcpServers);
|
|
1060
1048
|
if (mcpServers) {
|
|
1061
1049
|
files.push({
|
|
1062
|
-
path: `${
|
|
1050
|
+
path: `${OUTPUT_DIR4}/mcp.json`,
|
|
1063
1051
|
type: "json",
|
|
1064
1052
|
content: { mcpServers }
|
|
1065
1053
|
});
|
|
@@ -1067,7 +1055,7 @@ var cursorPlugin = {
|
|
|
1067
1055
|
const cliContent = buildCliContent(state.settings?.permissions);
|
|
1068
1056
|
if (cliContent) {
|
|
1069
1057
|
files.push({
|
|
1070
|
-
path: `${
|
|
1058
|
+
path: `${OUTPUT_DIR4}/cli.json`,
|
|
1071
1059
|
type: "json",
|
|
1072
1060
|
content: cliContent
|
|
1073
1061
|
});
|
|
@@ -1077,10 +1065,7 @@ var cursorPlugin = {
|
|
|
1077
1065
|
validate(state) {
|
|
1078
1066
|
const warnings = [];
|
|
1079
1067
|
if (!state.agents) {
|
|
1080
|
-
warnings.push(
|
|
1081
|
-
path: ["AGENTS.md"],
|
|
1082
|
-
message: "No AGENTS.md found - root AGENTS.md will not be created"
|
|
1083
|
-
});
|
|
1068
|
+
warnings.push(createNoAgentsMdWarning("root AGENTS.md"));
|
|
1084
1069
|
}
|
|
1085
1070
|
const permissionsResult = transformPermissionsToCursor(
|
|
1086
1071
|
state.settings?.permissions
|
|
@@ -1131,6 +1116,7 @@ function transformMcpToGemini(mcpServers) {
|
|
|
1131
1116
|
}
|
|
1132
1117
|
|
|
1133
1118
|
// src/plugins/gemini/index.ts
|
|
1119
|
+
var OUTPUT_DIR5 = TOOL_OUTPUT_DIRS.gemini;
|
|
1134
1120
|
var geminiPlugin = {
|
|
1135
1121
|
id: "gemini",
|
|
1136
1122
|
name: "Gemini CLI",
|
|
@@ -1142,13 +1128,9 @@ var geminiPlugin = {
|
|
|
1142
1128
|
},
|
|
1143
1129
|
async export(state, rootDir) {
|
|
1144
1130
|
const files = [];
|
|
1145
|
-
const
|
|
1146
|
-
if (
|
|
1147
|
-
files.push(
|
|
1148
|
-
path: `${outputDir}/GEMINI.md`,
|
|
1149
|
-
type: "symlink",
|
|
1150
|
-
target: `../${UNIFIED_DIR}/AGENTS.md`
|
|
1151
|
-
});
|
|
1131
|
+
const agentsSymlink = createRootAgentsMdSymlink(state);
|
|
1132
|
+
if (agentsSymlink) {
|
|
1133
|
+
files.push(agentsSymlink);
|
|
1152
1134
|
}
|
|
1153
1135
|
const rulesMap = groupRulesByDirectory(state.rules);
|
|
1154
1136
|
for (const [dir, contents] of rulesMap.entries()) {
|
|
@@ -1160,19 +1142,21 @@ var geminiPlugin = {
|
|
|
1160
1142
|
content: combinedContent
|
|
1161
1143
|
});
|
|
1162
1144
|
}
|
|
1163
|
-
|
|
1164
|
-
files.push({
|
|
1165
|
-
path: `${outputDir}/skills/${skill.path}`,
|
|
1166
|
-
type: "symlink",
|
|
1167
|
-
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
1168
|
-
});
|
|
1169
|
-
}
|
|
1145
|
+
files.push(...createSkillSymlinks(state, OUTPUT_DIR5));
|
|
1170
1146
|
const mcpServers = transformMcpToGemini(state.settings?.mcpServers);
|
|
1171
|
-
|
|
1147
|
+
const hasAgents = !!state.agents;
|
|
1148
|
+
if (mcpServers || hasAgents) {
|
|
1149
|
+
const settingsContent = {};
|
|
1150
|
+
if (hasAgents) {
|
|
1151
|
+
settingsContent["context"] = { fileName: ["AGENTS.md"] };
|
|
1152
|
+
}
|
|
1153
|
+
if (mcpServers) {
|
|
1154
|
+
settingsContent["mcpServers"] = mcpServers;
|
|
1155
|
+
}
|
|
1172
1156
|
files.push({
|
|
1173
|
-
path: `${
|
|
1157
|
+
path: `${OUTPUT_DIR5}/settings.json`,
|
|
1174
1158
|
type: "json",
|
|
1175
|
-
content:
|
|
1159
|
+
content: settingsContent
|
|
1176
1160
|
});
|
|
1177
1161
|
}
|
|
1178
1162
|
return applyFileOverrides(files, rootDir, "gemini");
|
|
@@ -1181,19 +1165,13 @@ var geminiPlugin = {
|
|
|
1181
1165
|
const warnings = [];
|
|
1182
1166
|
const skipped = [];
|
|
1183
1167
|
if (!state.agents) {
|
|
1184
|
-
warnings.push(
|
|
1185
|
-
path: ["AGENTS.md"],
|
|
1186
|
-
message: "No AGENTS.md found - GEMINI.md will not be created"
|
|
1187
|
-
});
|
|
1168
|
+
warnings.push(createNoAgentsMdWarning("root AGENTS.md"));
|
|
1188
1169
|
}
|
|
1189
|
-
if (state.settings?.permissions) {
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1194
|
-
reason: "Gemini CLI does not support declarative permissions - permissions must be granted interactively"
|
|
1195
|
-
});
|
|
1196
|
-
}
|
|
1170
|
+
if (hasPermissionsConfigured(state.settings?.permissions)) {
|
|
1171
|
+
skipped.push({
|
|
1172
|
+
feature: "permissions",
|
|
1173
|
+
reason: "Gemini CLI does not support declarative permissions - permissions must be granted interactively"
|
|
1174
|
+
});
|
|
1197
1175
|
}
|
|
1198
1176
|
if (state.rules.length > 0) {
|
|
1199
1177
|
warnings.push({
|
|
@@ -1278,6 +1256,8 @@ function parsePermissionRuleForOpenCode(rule) {
|
|
|
1278
1256
|
}
|
|
1279
1257
|
|
|
1280
1258
|
// src/plugins/opencode/index.ts
|
|
1259
|
+
var OUTPUT_DIR6 = TOOL_OUTPUT_DIRS.opencode;
|
|
1260
|
+
var SKILLS_DIR2 = ".agents";
|
|
1281
1261
|
var opencodePlugin = {
|
|
1282
1262
|
id: "opencode",
|
|
1283
1263
|
name: "OpenCode",
|
|
@@ -1289,33 +1269,23 @@ var opencodePlugin = {
|
|
|
1289
1269
|
},
|
|
1290
1270
|
async export(state, rootDir) {
|
|
1291
1271
|
const files = [];
|
|
1292
|
-
const
|
|
1293
|
-
if (
|
|
1294
|
-
files.push(
|
|
1295
|
-
path: "AGENTS.md",
|
|
1296
|
-
type: "symlink",
|
|
1297
|
-
target: `${UNIFIED_DIR}/AGENTS.md`
|
|
1298
|
-
});
|
|
1272
|
+
const agentsSymlink = createRootAgentsMdSymlink(state);
|
|
1273
|
+
if (agentsSymlink) {
|
|
1274
|
+
files.push(agentsSymlink);
|
|
1299
1275
|
}
|
|
1300
1276
|
if (state.rules.length > 0) {
|
|
1301
1277
|
files.push({
|
|
1302
|
-
path: `${
|
|
1278
|
+
path: `${OUTPUT_DIR6}/rules`,
|
|
1303
1279
|
type: "symlink",
|
|
1304
1280
|
target: `../${UNIFIED_DIR}/rules`
|
|
1305
1281
|
});
|
|
1306
1282
|
}
|
|
1307
|
-
|
|
1308
|
-
files.push({
|
|
1309
|
-
path: `${outputDir}/skills/${skill.path}`,
|
|
1310
|
-
type: "symlink",
|
|
1311
|
-
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
1312
|
-
});
|
|
1313
|
-
}
|
|
1283
|
+
files.push(...createSkillSymlinks(state, SKILLS_DIR2));
|
|
1314
1284
|
const config = {
|
|
1315
1285
|
$schema: "https://opencode.ai/config.json"
|
|
1316
1286
|
};
|
|
1317
1287
|
if (state.rules.length > 0) {
|
|
1318
|
-
config["instructions"] = [`${
|
|
1288
|
+
config["instructions"] = [`${OUTPUT_DIR6}/rules/*.md`];
|
|
1319
1289
|
}
|
|
1320
1290
|
const mcp = transformMcpToOpenCode(state.settings?.mcpServers);
|
|
1321
1291
|
if (mcp) {
|
|
@@ -1337,10 +1307,7 @@ var opencodePlugin = {
|
|
|
1337
1307
|
validate(state) {
|
|
1338
1308
|
const warnings = [];
|
|
1339
1309
|
if (!state.agents) {
|
|
1340
|
-
warnings.push(
|
|
1341
|
-
path: ["AGENTS.md"],
|
|
1342
|
-
message: "No AGENTS.md found - root AGENTS.md will not be created"
|
|
1343
|
-
});
|
|
1310
|
+
warnings.push(createNoAgentsMdWarning("root AGENTS.md"));
|
|
1344
1311
|
}
|
|
1345
1312
|
warnings.push(
|
|
1346
1313
|
...validateMcpServers(state.settings?.mcpServers, [
|
|
@@ -1403,6 +1370,7 @@ function serializeWindsurfRule(frontmatter, content) {
|
|
|
1403
1370
|
}
|
|
1404
1371
|
|
|
1405
1372
|
// src/plugins/windsurf/index.ts
|
|
1373
|
+
var OUTPUT_DIR7 = TOOL_OUTPUT_DIRS.windsurf;
|
|
1406
1374
|
var windsurfPlugin = {
|
|
1407
1375
|
id: "windsurf",
|
|
1408
1376
|
name: "Windsurf",
|
|
@@ -1414,13 +1382,9 @@ var windsurfPlugin = {
|
|
|
1414
1382
|
},
|
|
1415
1383
|
async export(state, rootDir) {
|
|
1416
1384
|
const files = [];
|
|
1417
|
-
const
|
|
1418
|
-
if (
|
|
1419
|
-
files.push(
|
|
1420
|
-
path: "AGENTS.md",
|
|
1421
|
-
type: "symlink",
|
|
1422
|
-
target: `${UNIFIED_DIR}/AGENTS.md`
|
|
1423
|
-
});
|
|
1385
|
+
const agentsSymlink = createRootAgentsMdSymlink(state);
|
|
1386
|
+
if (agentsSymlink) {
|
|
1387
|
+
files.push(agentsSymlink);
|
|
1424
1388
|
}
|
|
1425
1389
|
for (const rule of state.rules) {
|
|
1426
1390
|
const transformed = transformRuleToWindsurf(rule);
|
|
@@ -1429,28 +1393,19 @@ var windsurfPlugin = {
|
|
|
1429
1393
|
transformed.content
|
|
1430
1394
|
);
|
|
1431
1395
|
files.push({
|
|
1432
|
-
path: `${
|
|
1396
|
+
path: `${OUTPUT_DIR7}/rules/${rule.path}`,
|
|
1433
1397
|
type: "text",
|
|
1434
1398
|
content: ruleContent
|
|
1435
1399
|
});
|
|
1436
1400
|
}
|
|
1437
|
-
|
|
1438
|
-
files.push({
|
|
1439
|
-
path: `${outputDir}/skills/${skill.path}`,
|
|
1440
|
-
type: "symlink",
|
|
1441
|
-
target: `../../${UNIFIED_DIR}/skills/${skill.path}`
|
|
1442
|
-
});
|
|
1443
|
-
}
|
|
1401
|
+
files.push(...createSkillSymlinks(state, OUTPUT_DIR7));
|
|
1444
1402
|
return applyFileOverrides(files, rootDir, "windsurf");
|
|
1445
1403
|
},
|
|
1446
1404
|
validate(state) {
|
|
1447
1405
|
const warnings = [];
|
|
1448
1406
|
const skipped = [];
|
|
1449
1407
|
if (!state.agents) {
|
|
1450
|
-
warnings.push(
|
|
1451
|
-
path: ["AGENTS.md"],
|
|
1452
|
-
message: "No AGENTS.md found - root AGENTS.md will not be created"
|
|
1453
|
-
});
|
|
1408
|
+
warnings.push(createNoAgentsMdWarning("root AGENTS.md"));
|
|
1454
1409
|
}
|
|
1455
1410
|
if (state.rules.length > 0) {
|
|
1456
1411
|
warnings.push({
|
|
@@ -1464,14 +1419,11 @@ var windsurfPlugin = {
|
|
|
1464
1419
|
reason: "Windsurf uses global MCP config at ~/.codeium/windsurf/mcp_config.json - project-level MCP servers are not exported"
|
|
1465
1420
|
});
|
|
1466
1421
|
}
|
|
1467
|
-
if (state.settings?.permissions) {
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
reason: "Windsurf does not support declarative permissions"
|
|
1473
|
-
});
|
|
1474
|
-
}
|
|
1422
|
+
if (hasPermissionsConfigured(state.settings?.permissions)) {
|
|
1423
|
+
skipped.push({
|
|
1424
|
+
feature: "permissions",
|
|
1425
|
+
reason: "Windsurf does not support declarative permissions"
|
|
1426
|
+
});
|
|
1475
1427
|
}
|
|
1476
1428
|
return { valid: true, errors: [], warnings, skipped };
|
|
1477
1429
|
}
|
|
@@ -1642,23 +1594,37 @@ async function writeFiles(files, options) {
|
|
|
1642
1594
|
async function updateGitignore(rootDir, paths) {
|
|
1643
1595
|
const gitignorePath = path.join(rootDir, ".gitignore");
|
|
1644
1596
|
let content = "";
|
|
1597
|
+
let hasExistingFile = true;
|
|
1645
1598
|
try {
|
|
1646
1599
|
content = await fs4.readFile(gitignorePath, "utf-8");
|
|
1647
1600
|
} catch {
|
|
1601
|
+
hasExistingFile = false;
|
|
1648
1602
|
}
|
|
1649
1603
|
const marker = "# lnai-generated";
|
|
1650
1604
|
const endMarker = "# end lnai-generated";
|
|
1651
|
-
const extractRegex = new RegExp(`${marker}\\n([\\s\\S]*?)${endMarker}`);
|
|
1652
|
-
const match = extractRegex.exec(content);
|
|
1653
|
-
const existingSection = match?.[1] ?? "";
|
|
1654
|
-
const existingPaths = existingSection.split("\n").map((line) => line.trim()).filter((line) => line && !line.startsWith("#"));
|
|
1655
1605
|
const markerRegex = new RegExp(`${marker}[\\s\\S]*?${endMarker}\\n?`, "g");
|
|
1606
|
+
const hasManagedSection = new RegExp(`${marker}[\\s\\S]*?${endMarker}`).test(
|
|
1607
|
+
content
|
|
1608
|
+
);
|
|
1656
1609
|
content = content.replace(markerRegex, "");
|
|
1657
|
-
|
|
1658
|
-
const uniquePaths = [
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1610
|
+
const baseContent = content.trimEnd();
|
|
1611
|
+
const uniquePaths = [...new Set(paths)].sort();
|
|
1612
|
+
if (uniquePaths.length === 0) {
|
|
1613
|
+
if (!hasManagedSection && !hasExistingFile) {
|
|
1614
|
+
return;
|
|
1615
|
+
}
|
|
1616
|
+
const cleanedContent = baseContent.length > 0 ? `${baseContent}
|
|
1617
|
+
` : baseContent;
|
|
1618
|
+
await fs4.writeFile(gitignorePath, cleanedContent, "utf-8");
|
|
1619
|
+
return;
|
|
1620
|
+
}
|
|
1621
|
+
const managedSection = [marker, ...uniquePaths, endMarker].join("\n");
|
|
1622
|
+
const nextContent = baseContent.length > 0 ? `${baseContent}
|
|
1623
|
+
|
|
1624
|
+
${managedSection}
|
|
1625
|
+
` : `${managedSection}
|
|
1626
|
+
`;
|
|
1627
|
+
await fs4.writeFile(gitignorePath, nextContent, "utf-8");
|
|
1662
1628
|
}
|
|
1663
1629
|
|
|
1664
1630
|
// src/manifest/index.ts
|
|
@@ -1777,7 +1743,6 @@ async function runSyncPipeline(options) {
|
|
|
1777
1743
|
}
|
|
1778
1744
|
let manifest = await readManifest(rootDir) ?? createEmptyManifest();
|
|
1779
1745
|
const results = [];
|
|
1780
|
-
const pathsToIgnore = [];
|
|
1781
1746
|
for (const toolId of toolsToSync) {
|
|
1782
1747
|
const plugin = pluginRegistry.get(toolId);
|
|
1783
1748
|
if (!plugin) {
|
|
@@ -1803,15 +1768,12 @@ async function runSyncPipeline(options) {
|
|
|
1803
1768
|
if (!dryRun) {
|
|
1804
1769
|
manifest = updateToolManifest(manifest, toolId, outputFiles);
|
|
1805
1770
|
}
|
|
1806
|
-
const toolConfig = state.config.tools?.[toolId];
|
|
1807
|
-
if (!toolConfig?.versionControl) {
|
|
1808
|
-
pathsToIgnore.push(...outputFiles.map((f) => f.path));
|
|
1809
|
-
}
|
|
1810
1771
|
}
|
|
1811
1772
|
if (!dryRun) {
|
|
1812
1773
|
await writeManifest(rootDir, manifest);
|
|
1813
|
-
|
|
1814
|
-
|
|
1774
|
+
const pathsToIgnore = Object.entries(manifest.tools).flatMap(
|
|
1775
|
+
([toolId, toolManifest]) => !state.config.tools?.[toolId]?.versionControl && toolManifest?.files ? toolManifest.files.map((file) => file.path) : []
|
|
1776
|
+
);
|
|
1815
1777
|
await updateGitignore(rootDir, pathsToIgnore);
|
|
1816
1778
|
}
|
|
1817
1779
|
return results;
|