@promptscript/cli 1.0.0-alpha.2 → 1.0.0-alpha.3
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/CHANGELOG.md +13 -0
- package/README.md +8 -0
- package/index.js +877 -385
- package/package.json +1 -1
- package/src/cli.d.ts.map +1 -1
- package/src/commands/compile.d.ts +2 -1
- package/src/commands/compile.d.ts.map +1 -1
- package/src/commands/init.d.ts.map +1 -1
- package/src/output/console.d.ts +4 -0
- package/src/output/console.d.ts.map +1 -1
- package/src/prettier/index.d.ts +2 -0
- package/src/prettier/index.d.ts.map +1 -0
- package/src/prettier/loader.d.ts +36 -0
- package/src/prettier/loader.d.ts.map +1 -0
- package/src/services.d.ts +1 -0
- package/src/services.d.ts.map +1 -1
- package/src/types.d.ts +2 -0
- package/src/types.d.ts.map +1 -1
package/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// packages/cli/src/cli.ts
|
|
2
2
|
import { Command } from "commander";
|
|
3
3
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4
|
-
import { dirname as
|
|
4
|
+
import { dirname as dirname7 } from "path";
|
|
5
5
|
|
|
6
6
|
// packages/core/src/types/constants.ts
|
|
7
7
|
var BLOCK_TYPES = [
|
|
@@ -86,6 +86,13 @@ function isBuiltInConvention(name) {
|
|
|
86
86
|
return name in BUILT_IN_CONVENTIONS;
|
|
87
87
|
}
|
|
88
88
|
|
|
89
|
+
// packages/core/src/types/prettier.ts
|
|
90
|
+
var DEFAULT_PRETTIER_OPTIONS = {
|
|
91
|
+
proseWrap: "preserve",
|
|
92
|
+
tabWidth: 2,
|
|
93
|
+
printWidth: 80
|
|
94
|
+
};
|
|
95
|
+
|
|
89
96
|
// packages/core/src/errors/base.ts
|
|
90
97
|
var PSError = class extends Error {
|
|
91
98
|
/** Error code */
|
|
@@ -291,7 +298,7 @@ function getPackageVersion(baseDir, relativePath = "../package.json") {
|
|
|
291
298
|
|
|
292
299
|
// packages/cli/src/commands/init.ts
|
|
293
300
|
import { fileURLToPath } from "url";
|
|
294
|
-
import { dirname } from "path";
|
|
301
|
+
import { dirname as dirname2 } from "path";
|
|
295
302
|
|
|
296
303
|
// packages/cli/src/services.ts
|
|
297
304
|
import { writeFile, mkdir, readFile, readdir } from "fs/promises";
|
|
@@ -308,7 +315,8 @@ var defaultFileSystem = {
|
|
|
308
315
|
var defaultPrompts = {
|
|
309
316
|
input: prompts.input,
|
|
310
317
|
confirm: prompts.confirm,
|
|
311
|
-
checkbox: prompts.checkbox
|
|
318
|
+
checkbox: prompts.checkbox,
|
|
319
|
+
select: prompts.select
|
|
312
320
|
};
|
|
313
321
|
var createDefaultServices = () => ({
|
|
314
322
|
fs: defaultFileSystem,
|
|
@@ -378,6 +386,13 @@ var ConsoleOutput = {
|
|
|
378
386
|
if (isQuiet()) return;
|
|
379
387
|
console.log(chalk.yellow(` \u26A0 ${message}`));
|
|
380
388
|
},
|
|
389
|
+
/**
|
|
390
|
+
* Print a skipped file message.
|
|
391
|
+
*/
|
|
392
|
+
skipped(message) {
|
|
393
|
+
if (isQuiet()) return;
|
|
394
|
+
console.log(chalk.yellow(` \u2298 ${message}`));
|
|
395
|
+
},
|
|
381
396
|
/**
|
|
382
397
|
* Print an info message.
|
|
383
398
|
*/
|
|
@@ -680,9 +695,114 @@ function formatDetectionResults(detection) {
|
|
|
680
695
|
return lines;
|
|
681
696
|
}
|
|
682
697
|
|
|
698
|
+
// packages/cli/src/prettier/loader.ts
|
|
699
|
+
import { existsSync as existsSync2 } from "fs";
|
|
700
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
701
|
+
import { join as join2, dirname, resolve } from "path";
|
|
702
|
+
import { parse as parseYaml } from "yaml";
|
|
703
|
+
var PRETTIER_CONFIG_FILES = [
|
|
704
|
+
".prettierrc",
|
|
705
|
+
".prettierrc.json",
|
|
706
|
+
".prettierrc.yaml",
|
|
707
|
+
".prettierrc.yml"
|
|
708
|
+
];
|
|
709
|
+
function findPrettierConfig(startDir = process.cwd()) {
|
|
710
|
+
let currentDir = resolve(startDir);
|
|
711
|
+
const root2 = dirname(currentDir);
|
|
712
|
+
while (currentDir !== root2) {
|
|
713
|
+
for (const configFile of PRETTIER_CONFIG_FILES) {
|
|
714
|
+
const configPath = join2(currentDir, configFile);
|
|
715
|
+
if (existsSync2(configPath)) {
|
|
716
|
+
return configPath;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
currentDir = dirname(currentDir);
|
|
720
|
+
}
|
|
721
|
+
for (const configFile of PRETTIER_CONFIG_FILES) {
|
|
722
|
+
const configPath = join2(currentDir, configFile);
|
|
723
|
+
if (existsSync2(configPath)) {
|
|
724
|
+
return configPath;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
return null;
|
|
728
|
+
}
|
|
729
|
+
async function loadPrettierConfig(configPath) {
|
|
730
|
+
try {
|
|
731
|
+
const content = await readFile2(configPath, "utf-8");
|
|
732
|
+
const isYaml = configPath.endsWith(".yaml") || configPath.endsWith(".yml");
|
|
733
|
+
let parsed;
|
|
734
|
+
if (isYaml || configPath.endsWith(".prettierrc")) {
|
|
735
|
+
try {
|
|
736
|
+
parsed = parseYaml(content);
|
|
737
|
+
} catch {
|
|
738
|
+
parsed = JSON.parse(content);
|
|
739
|
+
}
|
|
740
|
+
} else {
|
|
741
|
+
parsed = JSON.parse(content);
|
|
742
|
+
}
|
|
743
|
+
if (!parsed || typeof parsed !== "object") {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
const config = parsed;
|
|
747
|
+
const result = {};
|
|
748
|
+
if (typeof config["proseWrap"] === "string") {
|
|
749
|
+
const proseWrap = config["proseWrap"];
|
|
750
|
+
if (proseWrap === "always" || proseWrap === "never" || proseWrap === "preserve") {
|
|
751
|
+
result.proseWrap = proseWrap;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
if (typeof config["tabWidth"] === "number") {
|
|
755
|
+
result.tabWidth = config["tabWidth"];
|
|
756
|
+
}
|
|
757
|
+
if (typeof config["printWidth"] === "number") {
|
|
758
|
+
result.printWidth = config["printWidth"];
|
|
759
|
+
}
|
|
760
|
+
return result;
|
|
761
|
+
} catch {
|
|
762
|
+
return null;
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
async function resolvePrettierOptions(config, basePath = process.cwd()) {
|
|
766
|
+
const formatting = config?.formatting;
|
|
767
|
+
if (!formatting) {
|
|
768
|
+
return { ...DEFAULT_PRETTIER_OPTIONS };
|
|
769
|
+
}
|
|
770
|
+
const result = { ...DEFAULT_PRETTIER_OPTIONS };
|
|
771
|
+
const prettier = formatting.prettier;
|
|
772
|
+
if (prettier === true) {
|
|
773
|
+
const configPath = findPrettierConfig(basePath);
|
|
774
|
+
if (configPath) {
|
|
775
|
+
const loadedOptions = await loadPrettierConfig(configPath);
|
|
776
|
+
if (loadedOptions) {
|
|
777
|
+
Object.assign(result, loadedOptions);
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
} else if (typeof prettier === "string") {
|
|
781
|
+
const configPath = resolve(basePath, prettier);
|
|
782
|
+
if (existsSync2(configPath)) {
|
|
783
|
+
const loadedOptions = await loadPrettierConfig(configPath);
|
|
784
|
+
if (loadedOptions) {
|
|
785
|
+
Object.assign(result, loadedOptions);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
} else if (prettier && typeof prettier === "object") {
|
|
789
|
+
Object.assign(result, prettier);
|
|
790
|
+
}
|
|
791
|
+
if (formatting.proseWrap !== void 0) {
|
|
792
|
+
result.proseWrap = formatting.proseWrap;
|
|
793
|
+
}
|
|
794
|
+
if (formatting.tabWidth !== void 0) {
|
|
795
|
+
result.tabWidth = formatting.tabWidth;
|
|
796
|
+
}
|
|
797
|
+
if (formatting.printWidth !== void 0) {
|
|
798
|
+
result.printWidth = formatting.printWidth;
|
|
799
|
+
}
|
|
800
|
+
return result;
|
|
801
|
+
}
|
|
802
|
+
|
|
683
803
|
// packages/cli/src/commands/init.ts
|
|
684
804
|
var __filename = fileURLToPath(import.meta.url);
|
|
685
|
-
var __dirname =
|
|
805
|
+
var __dirname = dirname2(__filename);
|
|
686
806
|
async function initCommand(options, services = createDefaultServices()) {
|
|
687
807
|
const { fs: fs4 } = services;
|
|
688
808
|
if (fs4.existsSync("promptscript.yaml") && !options.force) {
|
|
@@ -693,7 +813,14 @@ async function initCommand(options, services = createDefaultServices()) {
|
|
|
693
813
|
try {
|
|
694
814
|
const projectInfo = await detectProject(services);
|
|
695
815
|
const aiToolsDetection = await detectAITools(services);
|
|
696
|
-
const
|
|
816
|
+
const prettierConfigPath = findPrettierConfig(process.cwd());
|
|
817
|
+
const config = await resolveConfig(
|
|
818
|
+
options,
|
|
819
|
+
projectInfo,
|
|
820
|
+
aiToolsDetection,
|
|
821
|
+
prettierConfigPath,
|
|
822
|
+
services
|
|
823
|
+
);
|
|
697
824
|
const spinner = createSpinner("Creating PromptScript configuration...").start();
|
|
698
825
|
await fs4.mkdir(".promptscript", { recursive: true });
|
|
699
826
|
const configContent = generateConfig(config);
|
|
@@ -716,6 +843,14 @@ async function initCommand(options, services = createDefaultServices()) {
|
|
|
716
843
|
ConsoleOutput.muted(` Registry: ${config.registry}`);
|
|
717
844
|
}
|
|
718
845
|
ConsoleOutput.newline();
|
|
846
|
+
if (config.prettierConfigPath) {
|
|
847
|
+
ConsoleOutput.info(`Prettier config detected: ${config.prettierConfigPath}`);
|
|
848
|
+
ConsoleOutput.muted(" Output formatting will respect your Prettier settings");
|
|
849
|
+
} else {
|
|
850
|
+
ConsoleOutput.muted("No Prettier config found");
|
|
851
|
+
ConsoleOutput.muted(" Default formatting options added to config (tabWidth: 2)");
|
|
852
|
+
}
|
|
853
|
+
ConsoleOutput.newline();
|
|
719
854
|
console.log("Next steps:");
|
|
720
855
|
ConsoleOutput.muted("1. Edit .promptscript/project.prs to customize your AI instructions");
|
|
721
856
|
ConsoleOutput.muted("2. Run: prs compile");
|
|
@@ -729,14 +864,15 @@ async function initCommand(options, services = createDefaultServices()) {
|
|
|
729
864
|
process.exit(1);
|
|
730
865
|
}
|
|
731
866
|
}
|
|
732
|
-
async function resolveConfig(options, projectInfo, aiToolsDetection, services) {
|
|
867
|
+
async function resolveConfig(options, projectInfo, aiToolsDetection, prettierConfigPath, services) {
|
|
733
868
|
if (options.yes) {
|
|
734
869
|
return {
|
|
735
870
|
projectId: options.name ?? projectInfo.name,
|
|
736
871
|
team: options.team,
|
|
737
872
|
inherit: options.inherit,
|
|
738
873
|
registry: options.registry ?? "./registry",
|
|
739
|
-
targets: options.targets ?? getSuggestedTargets(aiToolsDetection)
|
|
874
|
+
targets: options.targets ?? getSuggestedTargets(aiToolsDetection),
|
|
875
|
+
prettierConfigPath
|
|
740
876
|
};
|
|
741
877
|
}
|
|
742
878
|
if (!options.interactive && options.name && options.targets) {
|
|
@@ -745,12 +881,19 @@ async function resolveConfig(options, projectInfo, aiToolsDetection, services) {
|
|
|
745
881
|
team: options.team,
|
|
746
882
|
inherit: options.inherit,
|
|
747
883
|
registry: options.registry,
|
|
748
|
-
targets: options.targets
|
|
884
|
+
targets: options.targets,
|
|
885
|
+
prettierConfigPath
|
|
749
886
|
};
|
|
750
887
|
}
|
|
751
|
-
return await runInteractivePrompts(
|
|
888
|
+
return await runInteractivePrompts(
|
|
889
|
+
options,
|
|
890
|
+
projectInfo,
|
|
891
|
+
aiToolsDetection,
|
|
892
|
+
prettierConfigPath,
|
|
893
|
+
services
|
|
894
|
+
);
|
|
752
895
|
}
|
|
753
|
-
async function runInteractivePrompts(options, projectInfo, aiToolsDetection, services) {
|
|
896
|
+
async function runInteractivePrompts(options, projectInfo, aiToolsDetection, prettierConfigPath, services) {
|
|
754
897
|
const { prompts: prompts2 } = services;
|
|
755
898
|
ConsoleOutput.newline();
|
|
756
899
|
console.log("\u{1F680} PromptScript Setup");
|
|
@@ -768,6 +911,9 @@ async function runInteractivePrompts(options, projectInfo, aiToolsDetection, ser
|
|
|
768
911
|
for (const line of detectionLines) {
|
|
769
912
|
ConsoleOutput.muted(line);
|
|
770
913
|
}
|
|
914
|
+
if (prettierConfigPath) {
|
|
915
|
+
ConsoleOutput.muted(`Prettier: ${prettierConfigPath}`);
|
|
916
|
+
}
|
|
771
917
|
ConsoleOutput.newline();
|
|
772
918
|
const projectId = await prompts2.input({
|
|
773
919
|
message: "Project name:",
|
|
@@ -829,7 +975,8 @@ async function runInteractivePrompts(options, projectInfo, aiToolsDetection, ser
|
|
|
829
975
|
team,
|
|
830
976
|
inherit,
|
|
831
977
|
registry,
|
|
832
|
-
targets
|
|
978
|
+
targets,
|
|
979
|
+
prettierConfigPath
|
|
833
980
|
};
|
|
834
981
|
}
|
|
835
982
|
function formatTargetName(target) {
|
|
@@ -862,7 +1009,18 @@ function generateConfig(config) {
|
|
|
862
1009
|
for (const target of config.targets) {
|
|
863
1010
|
lines.push(` - ${target}`);
|
|
864
1011
|
}
|
|
865
|
-
lines.push("", "validation:", " rules:", " empty-block: warn"
|
|
1012
|
+
lines.push("", "validation:", " rules:", " empty-block: warn");
|
|
1013
|
+
lines.push("");
|
|
1014
|
+
if (config.prettierConfigPath) {
|
|
1015
|
+
lines.push("formatting:", " prettier: true # Auto-detected from project");
|
|
1016
|
+
} else {
|
|
1017
|
+
lines.push(
|
|
1018
|
+
"formatting:",
|
|
1019
|
+
" tabWidth: 2",
|
|
1020
|
+
" proseWrap: preserve # 'always' | 'never' | 'preserve'"
|
|
1021
|
+
);
|
|
1022
|
+
}
|
|
1023
|
+
lines.push("");
|
|
866
1024
|
return lines.join("\n");
|
|
867
1025
|
}
|
|
868
1026
|
function generateProjectPs(config, projectInfo) {
|
|
@@ -912,15 +1070,15 @@ ${frameworksLine}
|
|
|
912
1070
|
}
|
|
913
1071
|
|
|
914
1072
|
// packages/cli/src/commands/compile.ts
|
|
915
|
-
import { resolve as
|
|
916
|
-
import { writeFile as writeFile2, mkdir as mkdir2 } from "fs/promises";
|
|
917
|
-
import { existsSync as
|
|
1073
|
+
import { resolve as resolve4, dirname as dirname5 } from "path";
|
|
1074
|
+
import { writeFile as writeFile2, mkdir as mkdir2, readFile as readFile6 } from "fs/promises";
|
|
1075
|
+
import { existsSync as existsSync7 } from "fs";
|
|
918
1076
|
import chokidar from "chokidar";
|
|
919
1077
|
|
|
920
1078
|
// packages/cli/src/config/loader.ts
|
|
921
|
-
import { readFile as
|
|
922
|
-
import { existsSync as
|
|
923
|
-
import { parse as
|
|
1079
|
+
import { readFile as readFile3 } from "fs/promises";
|
|
1080
|
+
import { existsSync as existsSync3 } from "fs";
|
|
1081
|
+
import { parse as parseYaml2 } from "yaml";
|
|
924
1082
|
var CONFIG_FILES = [
|
|
925
1083
|
"promptscript.yaml",
|
|
926
1084
|
"promptscript.yml",
|
|
@@ -943,14 +1101,14 @@ function interpolateEnvVars(text) {
|
|
|
943
1101
|
}
|
|
944
1102
|
function findConfigFile(customPath) {
|
|
945
1103
|
if (customPath) {
|
|
946
|
-
return
|
|
1104
|
+
return existsSync3(customPath) ? customPath : null;
|
|
947
1105
|
}
|
|
948
1106
|
const envConfig = process.env["PROMPTSCRIPT_CONFIG"];
|
|
949
|
-
if (envConfig &&
|
|
1107
|
+
if (envConfig && existsSync3(envConfig)) {
|
|
950
1108
|
return envConfig;
|
|
951
1109
|
}
|
|
952
1110
|
for (const file of CONFIG_FILES) {
|
|
953
|
-
if (
|
|
1111
|
+
if (existsSync3(file)) {
|
|
954
1112
|
return file;
|
|
955
1113
|
}
|
|
956
1114
|
}
|
|
@@ -964,10 +1122,10 @@ async function loadConfig(customPath) {
|
|
|
964
1122
|
}
|
|
965
1123
|
throw new Error("No PromptScript configuration found. Run: prs init");
|
|
966
1124
|
}
|
|
967
|
-
let content = await
|
|
1125
|
+
let content = await readFile3(configFile, "utf-8");
|
|
968
1126
|
content = interpolateEnvVars(content);
|
|
969
1127
|
try {
|
|
970
|
-
return
|
|
1128
|
+
return parseYaml2(content);
|
|
971
1129
|
} catch (error) {
|
|
972
1130
|
const message = error instanceof Error ? error.message : "Unknown parse error";
|
|
973
1131
|
throw new Error(`Failed to parse ${configFile}: ${message}`);
|
|
@@ -977,7 +1135,17 @@ async function loadConfig(customPath) {
|
|
|
977
1135
|
// packages/formatters/src/convention-renderer.ts
|
|
978
1136
|
var ConventionRenderer = class {
|
|
979
1137
|
convention;
|
|
980
|
-
|
|
1138
|
+
prettierOptions;
|
|
1139
|
+
constructor(conventionOrOptions = "xml") {
|
|
1140
|
+
let convention;
|
|
1141
|
+
let prettier;
|
|
1142
|
+
if (typeof conventionOrOptions === "object" && ("convention" in conventionOrOptions || "prettier" in conventionOrOptions)) {
|
|
1143
|
+
const opts = conventionOrOptions;
|
|
1144
|
+
convention = opts.convention ?? "xml";
|
|
1145
|
+
prettier = opts.prettier;
|
|
1146
|
+
} else {
|
|
1147
|
+
convention = conventionOrOptions;
|
|
1148
|
+
}
|
|
981
1149
|
if (typeof convention === "string") {
|
|
982
1150
|
if (isBuiltInConvention(convention)) {
|
|
983
1151
|
this.convention = BUILT_IN_CONVENTIONS[convention];
|
|
@@ -989,6 +1157,16 @@ var ConventionRenderer = class {
|
|
|
989
1157
|
} else {
|
|
990
1158
|
this.convention = convention;
|
|
991
1159
|
}
|
|
1160
|
+
this.prettierOptions = {
|
|
1161
|
+
...DEFAULT_PRETTIER_OPTIONS,
|
|
1162
|
+
...prettier
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
/**
|
|
1166
|
+
* Get the current Prettier options.
|
|
1167
|
+
*/
|
|
1168
|
+
getPrettierOptions() {
|
|
1169
|
+
return this.prettierOptions;
|
|
992
1170
|
}
|
|
993
1171
|
/**
|
|
994
1172
|
* Get the current convention.
|
|
@@ -1008,16 +1186,24 @@ var ConventionRenderer = class {
|
|
|
1008
1186
|
const transformedName = this.transformName(name, renderer.nameTransform);
|
|
1009
1187
|
const start = this.applyTemplate(renderer.start, { name: transformedName, level });
|
|
1010
1188
|
const end = renderer.end ? this.applyTemplate(renderer.end, { name: transformedName, level }) : "";
|
|
1011
|
-
|
|
1189
|
+
let trimmedContent = content.trim();
|
|
1012
1190
|
if (!trimmedContent) {
|
|
1013
1191
|
return end ? `${start}
|
|
1014
1192
|
${end}` : start;
|
|
1015
1193
|
}
|
|
1194
|
+
if (this.convention.name === "markdown") {
|
|
1195
|
+
trimmedContent = this.escapeMarkdownSpecialChars(trimmedContent);
|
|
1196
|
+
}
|
|
1016
1197
|
const indentedContent = this.indentContent(trimmedContent, renderer, level);
|
|
1017
1198
|
if (end) {
|
|
1018
1199
|
return `${start}
|
|
1019
1200
|
${indentedContent}
|
|
1020
1201
|
${end}`;
|
|
1202
|
+
}
|
|
1203
|
+
if (this.convention.name === "markdown") {
|
|
1204
|
+
return `${start}
|
|
1205
|
+
|
|
1206
|
+
${indentedContent}`;
|
|
1021
1207
|
}
|
|
1022
1208
|
return `${start}
|
|
1023
1209
|
${indentedContent}`;
|
|
@@ -1105,13 +1291,22 @@ ${this.convention.rootWrapper.end}`;
|
|
|
1105
1291
|
}
|
|
1106
1292
|
return result;
|
|
1107
1293
|
}
|
|
1294
|
+
/**
|
|
1295
|
+
* Escape markdown special characters for Prettier compatibility.
|
|
1296
|
+
* - Escapes __ to \_\_ (to avoid emphasis)
|
|
1297
|
+
* - Escapes /* to /\* (to avoid glob patterns being interpreted)
|
|
1298
|
+
*/
|
|
1299
|
+
escapeMarkdownSpecialChars(content) {
|
|
1300
|
+
return content.replace(/__/g, "\\_\\_").replace(/\/\*/g, "/\\*");
|
|
1301
|
+
}
|
|
1108
1302
|
indentContent(content, renderer, level) {
|
|
1109
1303
|
const indent = renderer.indent ?? "";
|
|
1110
1304
|
if (!indent) {
|
|
1111
1305
|
return content;
|
|
1112
1306
|
}
|
|
1113
1307
|
if (this.convention.name === "xml") {
|
|
1114
|
-
const
|
|
1308
|
+
const indentStr = " ".repeat(this.prettierOptions.tabWidth);
|
|
1309
|
+
const baseIndent = indentStr.repeat(level);
|
|
1115
1310
|
return content.split("\n").map((line) => line.trim() ? `${baseIndent}${line}` : line).join("\n");
|
|
1116
1311
|
}
|
|
1117
1312
|
return content;
|
|
@@ -1130,7 +1325,19 @@ var BaseFormatter = class {
|
|
|
1130
1325
|
*/
|
|
1131
1326
|
createRenderer(options) {
|
|
1132
1327
|
const convention = options?.convention ?? this.defaultConvention;
|
|
1133
|
-
return new ConventionRenderer(
|
|
1328
|
+
return new ConventionRenderer({
|
|
1329
|
+
convention,
|
|
1330
|
+
prettier: options?.prettier
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
/**
|
|
1334
|
+
* Get resolved Prettier options, merging provided options with defaults.
|
|
1335
|
+
*/
|
|
1336
|
+
getPrettierOptions(options) {
|
|
1337
|
+
return {
|
|
1338
|
+
...DEFAULT_PRETTIER_OPTIONS,
|
|
1339
|
+
...options?.prettier
|
|
1340
|
+
};
|
|
1134
1341
|
}
|
|
1135
1342
|
/**
|
|
1136
1343
|
* Get the output path, respecting options override.
|
|
@@ -1183,6 +1390,14 @@ var BaseFormatter = class {
|
|
|
1183
1390
|
return {};
|
|
1184
1391
|
}
|
|
1185
1392
|
}
|
|
1393
|
+
/**
|
|
1394
|
+
* Format standards list from array of values (pass-through).
|
|
1395
|
+
* Returns array of strings for rendering as bullet list.
|
|
1396
|
+
*/
|
|
1397
|
+
formatStandardsList(items) {
|
|
1398
|
+
if (!Array.isArray(items)) return [];
|
|
1399
|
+
return items.map((item) => this.valueToString(item)).filter((s) => s.length > 0);
|
|
1400
|
+
}
|
|
1186
1401
|
/**
|
|
1187
1402
|
* Format an array as comma-separated string.
|
|
1188
1403
|
*/
|
|
@@ -1248,6 +1463,136 @@ var BaseFormatter = class {
|
|
|
1248
1463
|
const endPos = endCodeBlock + 3;
|
|
1249
1464
|
return text.substring(headerIndex, endPos);
|
|
1250
1465
|
}
|
|
1466
|
+
/**
|
|
1467
|
+
* Normalize markdown content to match Prettier formatting.
|
|
1468
|
+
* - Strips common leading indentation from lines
|
|
1469
|
+
* - Trims trailing whitespace from lines
|
|
1470
|
+
* - Normalizes markdown table formatting
|
|
1471
|
+
* - Adds blank lines before lists when preceded by text
|
|
1472
|
+
* - Escapes markdown special characters in paths
|
|
1473
|
+
*/
|
|
1474
|
+
normalizeMarkdownForPrettier(content) {
|
|
1475
|
+
const lines = content.split("\n");
|
|
1476
|
+
let minIndent = Infinity;
|
|
1477
|
+
let inCodeBlock = false;
|
|
1478
|
+
for (const line of lines) {
|
|
1479
|
+
const trimmed = line.trimEnd();
|
|
1480
|
+
if (trimmed.startsWith("```")) {
|
|
1481
|
+
inCodeBlock = !inCodeBlock;
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
if (inCodeBlock) continue;
|
|
1485
|
+
if (trimmed.length === 0) continue;
|
|
1486
|
+
const match = line.match(/^(\s*)/);
|
|
1487
|
+
const leadingSpaces = match?.[1]?.length ?? 0;
|
|
1488
|
+
minIndent = Math.min(minIndent, leadingSpaces);
|
|
1489
|
+
}
|
|
1490
|
+
if (minIndent === Infinity) minIndent = 0;
|
|
1491
|
+
const result = [];
|
|
1492
|
+
let inTable = false;
|
|
1493
|
+
let tableLines = [];
|
|
1494
|
+
inCodeBlock = false;
|
|
1495
|
+
for (const line of lines) {
|
|
1496
|
+
const trimmedLine = line.trimEnd();
|
|
1497
|
+
if (trimmedLine.trimStart().startsWith("```")) {
|
|
1498
|
+
inCodeBlock = !inCodeBlock;
|
|
1499
|
+
}
|
|
1500
|
+
const unindentedLine = minIndent > 0 ? trimmedLine.slice(minIndent) : trimmedLine;
|
|
1501
|
+
if (inCodeBlock || unindentedLine.startsWith("```")) {
|
|
1502
|
+
result.push(unindentedLine);
|
|
1503
|
+
continue;
|
|
1504
|
+
}
|
|
1505
|
+
let processedLine = unindentedLine;
|
|
1506
|
+
processedLine = processedLine.replace(/__([^_]+)__/g, "\\_\\_$1\\_\\_");
|
|
1507
|
+
processedLine = processedLine.replace(/\/\*/g, "/\\*");
|
|
1508
|
+
if (processedLine.trimStart().startsWith("|") && processedLine.trimEnd().endsWith("|")) {
|
|
1509
|
+
inTable = true;
|
|
1510
|
+
tableLines.push(processedLine.trim());
|
|
1511
|
+
} else {
|
|
1512
|
+
if (inTable && tableLines.length > 0) {
|
|
1513
|
+
result.push(...this.formatMarkdownTable(tableLines));
|
|
1514
|
+
tableLines = [];
|
|
1515
|
+
inTable = false;
|
|
1516
|
+
}
|
|
1517
|
+
const prevLine = result.length > 0 ? result[result.length - 1] : "";
|
|
1518
|
+
const isListItem = processedLine.trimStart().startsWith("- ");
|
|
1519
|
+
if (isListItem && prevLine && !prevLine.trimStart().startsWith("- ")) {
|
|
1520
|
+
result.push("");
|
|
1521
|
+
}
|
|
1522
|
+
result.push(processedLine);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
if (tableLines.length > 0) {
|
|
1526
|
+
result.push(...this.formatMarkdownTable(tableLines));
|
|
1527
|
+
}
|
|
1528
|
+
return result.join("\n");
|
|
1529
|
+
}
|
|
1530
|
+
/**
|
|
1531
|
+
* Strip all leading indentation from markdown content.
|
|
1532
|
+
* Used for AGENTS.md where content from multiple sources has inconsistent indentation.
|
|
1533
|
+
* Preserves indentation inside code blocks.
|
|
1534
|
+
*/
|
|
1535
|
+
stripAllIndent(content) {
|
|
1536
|
+
const lines = content.split("\n");
|
|
1537
|
+
const result = [];
|
|
1538
|
+
let inCodeBlock = false;
|
|
1539
|
+
for (const line of lines) {
|
|
1540
|
+
const trimmedEnd = line.trimEnd();
|
|
1541
|
+
if (trimmedEnd.trimStart().startsWith("```")) {
|
|
1542
|
+
if (!inCodeBlock) {
|
|
1543
|
+
const prevLine2 = result.length > 0 ? result[result.length - 1] : "";
|
|
1544
|
+
if (prevLine2 && prevLine2.trim()) {
|
|
1545
|
+
result.push("");
|
|
1546
|
+
}
|
|
1547
|
+
}
|
|
1548
|
+
inCodeBlock = !inCodeBlock;
|
|
1549
|
+
result.push(trimmedEnd.trimStart());
|
|
1550
|
+
continue;
|
|
1551
|
+
}
|
|
1552
|
+
if (inCodeBlock) {
|
|
1553
|
+
result.push(trimmedEnd);
|
|
1554
|
+
continue;
|
|
1555
|
+
}
|
|
1556
|
+
let stripped = trimmedEnd.trimStart();
|
|
1557
|
+
stripped = stripped.replace(/__/g, "\\_\\_");
|
|
1558
|
+
stripped = stripped.replace(/\/\*/g, "/\\*");
|
|
1559
|
+
const prevLine = result.length > 0 ? result[result.length - 1] : "";
|
|
1560
|
+
if (stripped.startsWith("- ") && prevLine && !prevLine.startsWith("- ")) {
|
|
1561
|
+
result.push("");
|
|
1562
|
+
}
|
|
1563
|
+
result.push(stripped);
|
|
1564
|
+
}
|
|
1565
|
+
return result.join("\n");
|
|
1566
|
+
}
|
|
1567
|
+
/**
|
|
1568
|
+
* Format a markdown table to match Prettier output.
|
|
1569
|
+
* Prettier removes trailing whitespace from cells.
|
|
1570
|
+
*/
|
|
1571
|
+
formatMarkdownTable(tableLines) {
|
|
1572
|
+
if (tableLines.length === 0) return [];
|
|
1573
|
+
const rows = tableLines.map(
|
|
1574
|
+
(line) => line.split("|").slice(1, -1).map((cell) => cell.trim())
|
|
1575
|
+
);
|
|
1576
|
+
const colCount = rows[0]?.length ?? 0;
|
|
1577
|
+
const colWidths = new Array(colCount).fill(0);
|
|
1578
|
+
for (const row of rows) {
|
|
1579
|
+
for (let i = 0; i < row.length; i++) {
|
|
1580
|
+
const cell = row[i] ?? "";
|
|
1581
|
+
const width = cell.match(/^-+$/) ? 3 : cell.length;
|
|
1582
|
+
colWidths[i] = Math.max(colWidths[i] ?? 0, width);
|
|
1583
|
+
}
|
|
1584
|
+
}
|
|
1585
|
+
return rows.map((row) => {
|
|
1586
|
+
const cells = row.map((cell, colIndex) => {
|
|
1587
|
+
const width = colWidths[colIndex] ?? 0;
|
|
1588
|
+
if (cell.match(/^-+$/)) {
|
|
1589
|
+
return "-".repeat(width);
|
|
1590
|
+
}
|
|
1591
|
+
return cell.padEnd(width);
|
|
1592
|
+
});
|
|
1593
|
+
return "| " + cells.join(" | ") + " |";
|
|
1594
|
+
});
|
|
1595
|
+
}
|
|
1251
1596
|
};
|
|
1252
1597
|
|
|
1253
1598
|
// packages/formatters/src/registry.ts
|
|
@@ -1327,6 +1672,51 @@ var GITHUB_VERSIONS = {
|
|
|
1327
1672
|
outputPath: ".github/copilot-instructions.md"
|
|
1328
1673
|
}
|
|
1329
1674
|
};
|
|
1675
|
+
var TOOL_NAME_MAPPING = {
|
|
1676
|
+
// Read tools
|
|
1677
|
+
Read: "read",
|
|
1678
|
+
NotebookRead: "read",
|
|
1679
|
+
// Edit tools
|
|
1680
|
+
Edit: "edit",
|
|
1681
|
+
MultiEdit: "edit",
|
|
1682
|
+
Write: "edit",
|
|
1683
|
+
NotebookEdit: "edit",
|
|
1684
|
+
// Search tools
|
|
1685
|
+
Grep: "search",
|
|
1686
|
+
Glob: "search",
|
|
1687
|
+
// Execute tools
|
|
1688
|
+
Bash: "execute",
|
|
1689
|
+
// Web tools
|
|
1690
|
+
WebFetch: "web",
|
|
1691
|
+
WebSearch: "web",
|
|
1692
|
+
// Agent tools
|
|
1693
|
+
Task: "agent",
|
|
1694
|
+
// Todo tools
|
|
1695
|
+
TodoWrite: "todo",
|
|
1696
|
+
TodoRead: "todo"
|
|
1697
|
+
};
|
|
1698
|
+
var MODEL_NAME_MAPPING = {
|
|
1699
|
+
// Claude models - default aliases map to latest versions (4.5)
|
|
1700
|
+
sonnet: "Claude Sonnet 4.5",
|
|
1701
|
+
opus: "Claude Opus 4.5",
|
|
1702
|
+
haiku: "Claude Haiku 4.5",
|
|
1703
|
+
// Explicit version mappings
|
|
1704
|
+
"sonnet-4": "Claude Sonnet 4",
|
|
1705
|
+
"sonnet-4.5": "Claude Sonnet 4.5",
|
|
1706
|
+
"opus-4": "Claude Opus 4",
|
|
1707
|
+
"opus-4.5": "Claude Opus 4.5",
|
|
1708
|
+
"haiku-4": "Claude Haiku 4",
|
|
1709
|
+
"haiku-4.5": "Claude Haiku 4.5",
|
|
1710
|
+
// OpenAI models (pass through if already in correct format)
|
|
1711
|
+
"gpt-4o": "GPT-4o",
|
|
1712
|
+
"gpt-4.1": "GPT-4.1",
|
|
1713
|
+
"gpt-5": "GPT-5",
|
|
1714
|
+
"gpt-5-mini": "GPT-5 mini",
|
|
1715
|
+
// Special values
|
|
1716
|
+
inherit: "",
|
|
1717
|
+
// Empty string means omit the model property
|
|
1718
|
+
auto: "Auto"
|
|
1719
|
+
};
|
|
1330
1720
|
var GitHubFormatter = class extends BaseFormatter {
|
|
1331
1721
|
name = "github";
|
|
1332
1722
|
outputPath = ".github/copilot-instructions.md";
|
|
@@ -1368,7 +1758,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1368
1758
|
this.addCommonSections(ast, renderer, sections);
|
|
1369
1759
|
return {
|
|
1370
1760
|
path: this.getOutputPath(options),
|
|
1371
|
-
content: sections.join("\n\n")
|
|
1761
|
+
content: sections.join("\n\n") + "\n"
|
|
1372
1762
|
};
|
|
1373
1763
|
}
|
|
1374
1764
|
// ============================================================
|
|
@@ -1392,7 +1782,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1392
1782
|
this.addCommonSections(ast, renderer, sections);
|
|
1393
1783
|
return {
|
|
1394
1784
|
path: this.getOutputPath(options),
|
|
1395
|
-
content: sections.join("\n\n"),
|
|
1785
|
+
content: sections.join("\n\n") + "\n",
|
|
1396
1786
|
additionalFiles: additionalFiles.length > 0 ? additionalFiles : void 0
|
|
1397
1787
|
};
|
|
1398
1788
|
}
|
|
@@ -1429,7 +1819,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1429
1819
|
this.addCommonSections(ast, renderer, sections);
|
|
1430
1820
|
return {
|
|
1431
1821
|
path: this.getOutputPath(options),
|
|
1432
|
-
content: sections.join("\n\n"),
|
|
1822
|
+
content: sections.join("\n\n") + "\n",
|
|
1433
1823
|
additionalFiles: additionalFiles.length > 0 ? additionalFiles : void 0
|
|
1434
1824
|
};
|
|
1435
1825
|
}
|
|
@@ -1600,10 +1990,9 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1600
1990
|
if (config.mode === "agent") {
|
|
1601
1991
|
lines.push("mode: agent");
|
|
1602
1992
|
if (config.tools && config.tools.length > 0) {
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
}
|
|
1993
|
+
const mappedTools = config.tools.map((tool) => TOOL_NAME_MAPPING[tool] ?? tool.toLowerCase()).filter((t, i, arr) => arr.indexOf(t) === i);
|
|
1994
|
+
const toolsArray = mappedTools.map((t) => `'${t}'`).join(", ");
|
|
1995
|
+
lines.push(`tools: [${toolsArray}]`);
|
|
1607
1996
|
}
|
|
1608
1997
|
}
|
|
1609
1998
|
lines.push("---");
|
|
@@ -1646,19 +2035,21 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1646
2035
|
generateSkillFile(config) {
|
|
1647
2036
|
const lines = [];
|
|
1648
2037
|
lines.push("---");
|
|
1649
|
-
lines.push(`name:
|
|
1650
|
-
|
|
2038
|
+
lines.push(`name: '${config.name}'`);
|
|
2039
|
+
const descQuote = config.description.includes("'") ? '"' : "'";
|
|
2040
|
+
lines.push(`description: ${descQuote}${config.description}${descQuote}`);
|
|
1651
2041
|
if (config.disableModelInvocation) {
|
|
1652
2042
|
lines.push("disable-model-invocation: true");
|
|
1653
2043
|
}
|
|
1654
2044
|
lines.push("---");
|
|
1655
2045
|
lines.push("");
|
|
1656
2046
|
if (config.content) {
|
|
1657
|
-
|
|
2047
|
+
const normalizedContent = this.normalizeMarkdownForPrettier(config.content);
|
|
2048
|
+
lines.push(normalizedContent);
|
|
1658
2049
|
}
|
|
1659
2050
|
return {
|
|
1660
2051
|
path: `.github/skills/${config.name}/SKILL.md`,
|
|
1661
|
-
content: lines.join("\n")
|
|
2052
|
+
content: lines.join("\n") + "\n"
|
|
1662
2053
|
};
|
|
1663
2054
|
}
|
|
1664
2055
|
// ============================================================
|
|
@@ -1679,7 +2070,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1679
2070
|
if (identityText) {
|
|
1680
2071
|
lines.push("## Identity");
|
|
1681
2072
|
lines.push("");
|
|
1682
|
-
lines.push(identityText);
|
|
2073
|
+
lines.push(this.stripAllIndent(identityText));
|
|
1683
2074
|
lines.push("");
|
|
1684
2075
|
}
|
|
1685
2076
|
const context = this.findBlock(ast, "context");
|
|
@@ -1688,7 +2079,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1688
2079
|
if (contextText) {
|
|
1689
2080
|
lines.push("## Context");
|
|
1690
2081
|
lines.push("");
|
|
1691
|
-
lines.push(contextText);
|
|
2082
|
+
lines.push(this.stripAllIndent(contextText));
|
|
1692
2083
|
lines.push("");
|
|
1693
2084
|
}
|
|
1694
2085
|
}
|
|
@@ -1701,12 +2092,11 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1701
2092
|
for (const item of items) {
|
|
1702
2093
|
lines.push(`- ${item}`);
|
|
1703
2094
|
}
|
|
1704
|
-
lines.push("");
|
|
1705
2095
|
}
|
|
1706
2096
|
}
|
|
1707
2097
|
return {
|
|
1708
2098
|
path: "AGENTS.md",
|
|
1709
|
-
content: lines.join("\n")
|
|
2099
|
+
content: lines.join("\n") + "\n"
|
|
1710
2100
|
};
|
|
1711
2101
|
}
|
|
1712
2102
|
/**
|
|
@@ -1757,12 +2147,26 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1757
2147
|
return agents;
|
|
1758
2148
|
}
|
|
1759
2149
|
/**
|
|
1760
|
-
* Parse tools array from a Value.
|
|
2150
|
+
* Parse tools array from a Value and map to GitHub Copilot canonical names.
|
|
2151
|
+
*
|
|
2152
|
+
* @see https://docs.github.com/en/copilot/reference/custom-agents-configuration
|
|
1761
2153
|
*/
|
|
1762
2154
|
parseToolsArray(value) {
|
|
1763
2155
|
if (!value || !Array.isArray(value)) return void 0;
|
|
1764
|
-
const
|
|
1765
|
-
|
|
2156
|
+
const mapped = value.map((v) => this.valueToString(v)).filter((s) => s.length > 0).map((tool) => TOOL_NAME_MAPPING[tool] ?? tool.toLowerCase());
|
|
2157
|
+
const unique = [...new Set(mapped)];
|
|
2158
|
+
return unique.length > 0 ? unique : void 0;
|
|
2159
|
+
}
|
|
2160
|
+
/**
|
|
2161
|
+
* Map a model name from PromptScript/Claude Code format to GitHub Copilot format.
|
|
2162
|
+
*
|
|
2163
|
+
* @returns The mapped model name, or undefined if the model should be omitted (e.g., "inherit")
|
|
2164
|
+
*/
|
|
2165
|
+
mapModelName(model) {
|
|
2166
|
+
if (!model) return void 0;
|
|
2167
|
+
const mapped = MODEL_NAME_MAPPING[model.toLowerCase()];
|
|
2168
|
+
if (mapped === "") return void 0;
|
|
2169
|
+
return mapped ?? model;
|
|
1766
2170
|
}
|
|
1767
2171
|
/**
|
|
1768
2172
|
* Generate a .github/agents/<name>.md file.
|
|
@@ -1775,13 +2179,12 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1775
2179
|
lines.push(`name: ${config.name}`);
|
|
1776
2180
|
lines.push(`description: ${config.description}`);
|
|
1777
2181
|
if (config.tools && config.tools.length > 0) {
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
lines.push(` - ${tool}`);
|
|
1781
|
-
}
|
|
2182
|
+
const toolsArray = config.tools.map((t) => `'${t}'`).join(", ");
|
|
2183
|
+
lines.push(`tools: [${toolsArray}]`);
|
|
1782
2184
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
2185
|
+
const mappedModel = this.mapModelName(config.model);
|
|
2186
|
+
if (mappedModel) {
|
|
2187
|
+
lines.push(`model: ${mappedModel}`);
|
|
1785
2188
|
}
|
|
1786
2189
|
lines.push("---");
|
|
1787
2190
|
lines.push("");
|
|
@@ -1790,7 +2193,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1790
2193
|
}
|
|
1791
2194
|
return {
|
|
1792
2195
|
path: `.github/agents/${config.name}.md`,
|
|
1793
|
-
content: lines.join("\n")
|
|
2196
|
+
content: lines.join("\n") + "\n"
|
|
1794
2197
|
};
|
|
1795
2198
|
}
|
|
1796
2199
|
// ============================================================
|
|
@@ -1837,7 +2240,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1837
2240
|
const identity2 = this.findBlock(ast, "identity");
|
|
1838
2241
|
if (!identity2) return null;
|
|
1839
2242
|
const content = this.extractText(identity2.content);
|
|
1840
|
-
return renderer.renderSection("project", content);
|
|
2243
|
+
return renderer.renderSection("project", this.stripAllIndent(content));
|
|
1841
2244
|
}
|
|
1842
2245
|
techStack(ast, renderer) {
|
|
1843
2246
|
const context = this.findBlock(ast, "context");
|
|
@@ -1875,50 +2278,30 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1875
2278
|
const archMatch = this.extractSectionWithCodeBlock(text, "## Architecture");
|
|
1876
2279
|
if (!archMatch) return null;
|
|
1877
2280
|
const content = archMatch.replace("## Architecture", "").trim();
|
|
1878
|
-
return renderer.renderSection("architecture", content);
|
|
2281
|
+
return renderer.renderSection("architecture", this.stripAllIndent(content));
|
|
1879
2282
|
}
|
|
1880
2283
|
codeStandards(ast, renderer) {
|
|
1881
2284
|
const standards = this.findBlock(ast, "standards");
|
|
1882
2285
|
if (!standards) return null;
|
|
1883
2286
|
const props = this.getProps(standards.content);
|
|
1884
2287
|
const subsections = [];
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
"
|
|
1890
|
-
|
|
1891
|
-
)
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
this.addStandardsSubsection(
|
|
1900
|
-
subsections,
|
|
1901
|
-
renderer,
|
|
1902
|
-
props["errors"],
|
|
1903
|
-
"error-handling",
|
|
1904
|
-
this.formatErrorStandards.bind(this)
|
|
1905
|
-
);
|
|
1906
|
-
this.addStandardsSubsection(
|
|
1907
|
-
subsections,
|
|
1908
|
-
renderer,
|
|
1909
|
-
props["testing"],
|
|
1910
|
-
"testing",
|
|
1911
|
-
this.formatTestingStandards.bind(this)
|
|
1912
|
-
);
|
|
1913
|
-
if (subsections.length === 0) return null;
|
|
1914
|
-
return renderer.renderSection("code-standards", subsections.join("\n"));
|
|
1915
|
-
}
|
|
1916
|
-
addStandardsSubsection(subsections, renderer, value, name, formatter) {
|
|
1917
|
-
if (!value || typeof value !== "object" || Array.isArray(value)) return;
|
|
1918
|
-
const items = formatter(value);
|
|
1919
|
-
if (items.length > 0) {
|
|
1920
|
-
subsections.push(renderer.renderSection(name, renderer.renderList(items), 2));
|
|
2288
|
+
const sectionMap = {
|
|
2289
|
+
typescript: "typescript",
|
|
2290
|
+
naming: "naming",
|
|
2291
|
+
errors: "error-handling",
|
|
2292
|
+
testing: "testing"
|
|
2293
|
+
};
|
|
2294
|
+
for (const [key, sectionName] of Object.entries(sectionMap)) {
|
|
2295
|
+
const value = props[key];
|
|
2296
|
+
if (Array.isArray(value)) {
|
|
2297
|
+
const items = this.formatStandardsList(value);
|
|
2298
|
+
if (items.length > 0) {
|
|
2299
|
+
subsections.push(renderer.renderSection(sectionName, renderer.renderList(items), 2));
|
|
2300
|
+
}
|
|
2301
|
+
}
|
|
1921
2302
|
}
|
|
2303
|
+
if (subsections.length === 0) return null;
|
|
2304
|
+
return renderer.renderSection("code-standards", subsections.join("\n\n"));
|
|
1922
2305
|
}
|
|
1923
2306
|
commands(ast, renderer) {
|
|
1924
2307
|
const knowledge = this.findBlock(ast, "knowledge");
|
|
@@ -1927,7 +2310,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1927
2310
|
const commandsMatch = this.extractSectionWithCodeBlock(text, "## Development Commands");
|
|
1928
2311
|
if (!commandsMatch) return null;
|
|
1929
2312
|
const content = commandsMatch.replace("## Development Commands", "").trim();
|
|
1930
|
-
return renderer.renderSection("commands", content);
|
|
2313
|
+
return renderer.renderSection("commands", this.stripAllIndent(content));
|
|
1931
2314
|
}
|
|
1932
2315
|
gitCommits(ast, renderer) {
|
|
1933
2316
|
const standards = this.findBlock(ast, "standards");
|
|
@@ -1978,7 +2361,7 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
1978
2361
|
subsections.push(renderer.renderSection("vite-vitest", `Vite root: ${value}`, 2));
|
|
1979
2362
|
}
|
|
1980
2363
|
if (subsections.length === 0) return null;
|
|
1981
|
-
return renderer.renderSection("configuration-files", subsections.join("\n"));
|
|
2364
|
+
return renderer.renderSection("configuration-files", subsections.join("\n\n"));
|
|
1982
2365
|
}
|
|
1983
2366
|
documentation(ast, renderer) {
|
|
1984
2367
|
const standards = this.findBlock(ast, "standards");
|
|
@@ -2014,8 +2397,11 @@ var GitHubFormatter = class extends BaseFormatter {
|
|
|
2014
2397
|
if (!postMatch) return null;
|
|
2015
2398
|
const intro = "After completing any code changes, run the following commands to ensure code quality:";
|
|
2016
2399
|
const content = postMatch.replace("## Post-Work Verification", "").trim();
|
|
2017
|
-
return renderer.renderSection(
|
|
2018
|
-
|
|
2400
|
+
return renderer.renderSection(
|
|
2401
|
+
"post-work-verification",
|
|
2402
|
+
`${intro}
|
|
2403
|
+
${this.stripAllIndent(content)}`
|
|
2404
|
+
);
|
|
2019
2405
|
}
|
|
2020
2406
|
restrictions(ast, renderer) {
|
|
2021
2407
|
const block = this.findBlock(ast, "restrictions");
|
|
@@ -2070,47 +2456,6 @@ ${content}`);
|
|
|
2070
2456
|
formatTechItem(arr) {
|
|
2071
2457
|
return arr.map(String).join(", ");
|
|
2072
2458
|
}
|
|
2073
|
-
formatStandardsObject(obj) {
|
|
2074
|
-
const items = [];
|
|
2075
|
-
if (obj["strictMode"]) items.push("Strict mode enabled, no `any` types");
|
|
2076
|
-
if (obj["useUnknown"]) items.push(`Use \`unknown\` ${this.valueToString(obj["useUnknown"])}`);
|
|
2077
|
-
if (obj["interfaces"])
|
|
2078
|
-
items.push(`Prefer \`interface\` ${this.valueToString(obj["interfaces"])}`);
|
|
2079
|
-
if (obj["types"]) items.push(`Use \`type\` ${this.valueToString(obj["types"])}`);
|
|
2080
|
-
if (obj["exports"]) items.push(`${this.capitalize(this.valueToString(obj["exports"]))}`);
|
|
2081
|
-
if (obj["returnTypes"])
|
|
2082
|
-
items.push(`Explicit return types ${this.valueToString(obj["returnTypes"])}`);
|
|
2083
|
-
return items;
|
|
2084
|
-
}
|
|
2085
|
-
formatNamingStandards(obj) {
|
|
2086
|
-
const items = [];
|
|
2087
|
-
if (obj["files"]) items.push(`Files: \`${this.valueToString(obj["files"])}\``);
|
|
2088
|
-
if (obj["classes"]) items.push(`Classes/Interfaces: \`${this.valueToString(obj["classes"])}\``);
|
|
2089
|
-
if (obj["functions"])
|
|
2090
|
-
items.push(`Functions/Variables: \`${this.valueToString(obj["functions"])}\``);
|
|
2091
|
-
if (obj["constants"]) items.push(`Constants: \`${this.valueToString(obj["constants"])}\``);
|
|
2092
|
-
return items;
|
|
2093
|
-
}
|
|
2094
|
-
formatErrorStandards(obj) {
|
|
2095
|
-
const items = [];
|
|
2096
|
-
if (obj["customClasses"])
|
|
2097
|
-
items.push(
|
|
2098
|
-
`Use custom error classes extending \`${this.valueToString(obj["customClasses"])}\``
|
|
2099
|
-
);
|
|
2100
|
-
if (obj["locationInfo"]) items.push("Always include location information");
|
|
2101
|
-
if (obj["messages"])
|
|
2102
|
-
items.push(`Provide ${this.valueToString(obj["messages"])} error messages`);
|
|
2103
|
-
return items;
|
|
2104
|
-
}
|
|
2105
|
-
formatTestingStandards(obj) {
|
|
2106
|
-
const items = [];
|
|
2107
|
-
if (obj["filePattern"]) items.push(`Test files: \`${this.valueToString(obj["filePattern"])}\``);
|
|
2108
|
-
if (obj["pattern"]) items.push(`Follow ${this.valueToString(obj["pattern"])} pattern`);
|
|
2109
|
-
if (obj["coverage"])
|
|
2110
|
-
items.push(`Target >${this.valueToString(obj["coverage"])}% coverage for libraries`);
|
|
2111
|
-
if (obj["fixtures"]) items.push(`Use fixtures ${this.valueToString(obj["fixtures"])}`);
|
|
2112
|
-
return items;
|
|
2113
|
-
}
|
|
2114
2459
|
formatRestriction(text) {
|
|
2115
2460
|
const formatted = text.replace(/^-\s*/, "").replace(/^"/, "").replace(/"$/, "").replace(/^Never\s+/i, "Don't ");
|
|
2116
2461
|
return formatted;
|
|
@@ -2385,8 +2730,9 @@ var ClaudeFormatter = class extends BaseFormatter {
|
|
|
2385
2730
|
generateSkillFile(config) {
|
|
2386
2731
|
const lines = [];
|
|
2387
2732
|
lines.push("---");
|
|
2388
|
-
lines.push(`name:
|
|
2389
|
-
|
|
2733
|
+
lines.push(`name: '${config.name}'`);
|
|
2734
|
+
const descQuote = config.description.includes("'") ? '"' : "'";
|
|
2735
|
+
lines.push(`description: ${descQuote}${config.description}${descQuote}`);
|
|
2390
2736
|
if (config.context) {
|
|
2391
2737
|
lines.push(`context: ${config.context}`);
|
|
2392
2738
|
}
|
|
@@ -2405,11 +2751,12 @@ var ClaudeFormatter = class extends BaseFormatter {
|
|
|
2405
2751
|
lines.push("---");
|
|
2406
2752
|
lines.push("");
|
|
2407
2753
|
if (config.content) {
|
|
2408
|
-
|
|
2754
|
+
const normalizedContent = this.normalizeMarkdownForPrettier(config.content);
|
|
2755
|
+
lines.push(normalizedContent);
|
|
2409
2756
|
}
|
|
2410
2757
|
return {
|
|
2411
2758
|
path: `.claude/skills/${config.name}/SKILL.md`,
|
|
2412
|
-
content: lines.join("\n")
|
|
2759
|
+
content: lines.join("\n") + "\n"
|
|
2413
2760
|
};
|
|
2414
2761
|
}
|
|
2415
2762
|
// ============================================================
|
|
@@ -2518,7 +2865,7 @@ var ClaudeFormatter = class extends BaseFormatter {
|
|
|
2518
2865
|
}
|
|
2519
2866
|
return {
|
|
2520
2867
|
path: `.claude/agents/${config.name}.md`,
|
|
2521
|
-
content: lines.join("\n")
|
|
2868
|
+
content: lines.join("\n") + "\n"
|
|
2522
2869
|
};
|
|
2523
2870
|
}
|
|
2524
2871
|
// ============================================================
|
|
@@ -3567,7 +3914,7 @@ var AntigravityFormatter = class extends BaseFormatter {
|
|
|
3567
3914
|
if (diagrams) sections.push(diagrams);
|
|
3568
3915
|
const restrictions = this.restrictions(ast, renderer);
|
|
3569
3916
|
if (restrictions) sections.push(restrictions);
|
|
3570
|
-
const content = sections.join("\n\n");
|
|
3917
|
+
const content = sections.join("\n\n") + "\n";
|
|
3571
3918
|
this.validateContentLength(content);
|
|
3572
3919
|
const mainOutput = {
|
|
3573
3920
|
path: this.getOutputPath(options),
|
|
@@ -3740,7 +4087,7 @@ var AntigravityFormatter = class extends BaseFormatter {
|
|
|
3740
4087
|
if (!content) return null;
|
|
3741
4088
|
return `## Project Identity
|
|
3742
4089
|
|
|
3743
|
-
${content}`;
|
|
4090
|
+
${this.stripAllIndent(content)}`;
|
|
3744
4091
|
}
|
|
3745
4092
|
/**
|
|
3746
4093
|
* Extract tech stack from @context block (same as GitHub/Cursor).
|
|
@@ -3794,7 +4141,7 @@ ${items.join("\n")}`;
|
|
|
3794
4141
|
const content = archMatch.replace("## Architecture", "").trim();
|
|
3795
4142
|
return `## Architecture
|
|
3796
4143
|
|
|
3797
|
-
${content}`;
|
|
4144
|
+
${this.stripAllIndent(content)}`;
|
|
3798
4145
|
}
|
|
3799
4146
|
const props = this.getProps(context.content);
|
|
3800
4147
|
const arch = props["architecture"];
|
|
@@ -3803,7 +4150,7 @@ ${content}`;
|
|
|
3803
4150
|
if (archText.trim()) {
|
|
3804
4151
|
return `## Architecture
|
|
3805
4152
|
|
|
3806
|
-
${archText.trim()}`;
|
|
4153
|
+
${this.stripAllIndent(archText.trim())}`;
|
|
3807
4154
|
}
|
|
3808
4155
|
}
|
|
3809
4156
|
}
|
|
@@ -3813,53 +4160,35 @@ ${archText.trim()}`;
|
|
|
3813
4160
|
if (content) {
|
|
3814
4161
|
return `## Architecture
|
|
3815
4162
|
|
|
3816
|
-
${content}`;
|
|
4163
|
+
${this.stripAllIndent(content)}`;
|
|
3817
4164
|
}
|
|
3818
4165
|
}
|
|
3819
4166
|
return null;
|
|
3820
4167
|
}
|
|
3821
4168
|
/**
|
|
3822
|
-
* Extract code standards from @standards block
|
|
4169
|
+
* Extract code standards from @standards block.
|
|
4170
|
+
* Expects arrays of strings (pass-through format).
|
|
3823
4171
|
*/
|
|
3824
4172
|
codeStandards(ast, _renderer) {
|
|
3825
4173
|
const standards = this.findBlock(ast, "standards");
|
|
3826
4174
|
if (!standards) return null;
|
|
3827
4175
|
const props = this.getProps(standards.content);
|
|
3828
4176
|
const subsections = [];
|
|
3829
|
-
const
|
|
3830
|
-
|
|
3831
|
-
|
|
3832
|
-
|
|
3833
|
-
|
|
3834
|
-
|
|
3835
|
-
|
|
3836
|
-
|
|
3837
|
-
|
|
3838
|
-
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
if (items.length > 0) {
|
|
3842
|
-
subsections.push(`### Naming Conventions
|
|
3843
|
-
|
|
3844
|
-
${items.map((i) => "- " + i).join("\n")}`);
|
|
3845
|
-
}
|
|
3846
|
-
}
|
|
3847
|
-
const errors = props["errors"];
|
|
3848
|
-
if (errors && typeof errors === "object" && !Array.isArray(errors)) {
|
|
3849
|
-
const items = this.formatErrorStandards(errors);
|
|
3850
|
-
if (items.length > 0) {
|
|
3851
|
-
subsections.push(`### Error Handling
|
|
3852
|
-
|
|
3853
|
-
${items.map((i) => "- " + i).join("\n")}`);
|
|
3854
|
-
}
|
|
3855
|
-
}
|
|
3856
|
-
const testing = props["testing"];
|
|
3857
|
-
if (testing && typeof testing === "object" && !Array.isArray(testing)) {
|
|
3858
|
-
const items = this.formatTestingStandards(testing);
|
|
3859
|
-
if (items.length > 0) {
|
|
3860
|
-
subsections.push(`### Testing
|
|
4177
|
+
const sectionMap = {
|
|
4178
|
+
typescript: "TypeScript",
|
|
4179
|
+
naming: "Naming Conventions",
|
|
4180
|
+
errors: "Error Handling",
|
|
4181
|
+
testing: "Testing"
|
|
4182
|
+
};
|
|
4183
|
+
for (const [key, title] of Object.entries(sectionMap)) {
|
|
4184
|
+
const value = props[key];
|
|
4185
|
+
if (Array.isArray(value)) {
|
|
4186
|
+
const items = this.formatStandardsList(value);
|
|
4187
|
+
if (items.length > 0) {
|
|
4188
|
+
subsections.push(`### ${title}
|
|
3861
4189
|
|
|
3862
4190
|
${items.map((i) => "- " + i).join("\n")}`);
|
|
4191
|
+
}
|
|
3863
4192
|
}
|
|
3864
4193
|
}
|
|
3865
4194
|
if (subsections.length === 0) return null;
|
|
@@ -3922,7 +4251,7 @@ ${items.map((i) => "- " + i).join("\n")}`;
|
|
|
3922
4251
|
}
|
|
3923
4252
|
const vite = configObj["viteRoot"];
|
|
3924
4253
|
if (vite) {
|
|
3925
|
-
const value = this.valueToString(vite);
|
|
4254
|
+
const value = this.valueToString(vite).replace(/__/g, "\\_\\_").replace(/\/\*/g, "/\\*");
|
|
3926
4255
|
subsections.push(`### Vite/Vitest
|
|
3927
4256
|
|
|
3928
4257
|
- Vite root: ${value}`);
|
|
@@ -3944,7 +4273,11 @@ ${subsections.join("\n\n")}`;
|
|
|
3944
4273
|
for (const [key, value] of Object.entries(props)) {
|
|
3945
4274
|
if (this.isWorkflow(value)) continue;
|
|
3946
4275
|
const valueStr = this.valueToString(value);
|
|
3947
|
-
|
|
4276
|
+
if (valueStr) {
|
|
4277
|
+
lines.push(`- **${key}**: ${valueStr}`);
|
|
4278
|
+
} else {
|
|
4279
|
+
lines.push(`- **${key}**:`);
|
|
4280
|
+
}
|
|
3948
4281
|
}
|
|
3949
4282
|
if (lines.length === 0) return null;
|
|
3950
4283
|
return `## Commands
|
|
@@ -3963,7 +4296,7 @@ ${lines.join("\n")}`;
|
|
|
3963
4296
|
const content = commandsMatch.replace("## Development Commands", "").trim();
|
|
3964
4297
|
return `## Development Commands
|
|
3965
4298
|
|
|
3966
|
-
${content}`;
|
|
4299
|
+
${this.stripAllIndent(content)}`;
|
|
3967
4300
|
}
|
|
3968
4301
|
/**
|
|
3969
4302
|
* Extract post-work verification from @knowledge block (same as GitHub/Cursor).
|
|
@@ -3979,7 +4312,7 @@ ${content}`;
|
|
|
3979
4312
|
return `## Post-Work Verification
|
|
3980
4313
|
|
|
3981
4314
|
${intro}
|
|
3982
|
-
${content}`;
|
|
4315
|
+
${this.stripAllIndent(content)}`;
|
|
3983
4316
|
}
|
|
3984
4317
|
/**
|
|
3985
4318
|
* Extract documentation standards from @standards.documentation (same as GitHub/Cursor).
|
|
@@ -4025,9 +4358,8 @@ ${items.map((i) => "- " + i).join("\n")}`;
|
|
|
4025
4358
|
const items = [];
|
|
4026
4359
|
const format2 = diagObj["format"];
|
|
4027
4360
|
if (format2) {
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
);
|
|
4361
|
+
const formatValue = this.valueToString(format2).replace(/__/g, "\\_\\_").replace(/\/\*/g, "/\\*");
|
|
4362
|
+
items.push(`Always use **${formatValue}** syntax for diagrams in documentation`);
|
|
4031
4363
|
}
|
|
4032
4364
|
const types = diagObj["types"];
|
|
4033
4365
|
if (types && Array.isArray(types)) {
|
|
@@ -4072,55 +4404,6 @@ ${items.map((i) => "- " + i).join("\n")}`;
|
|
|
4072
4404
|
formatRestriction(text) {
|
|
4073
4405
|
return text.replace(/^-\s*/, "").replace(/^"/, "").replace(/"$/, "").replace(/^Never\s+/i, "Don't ");
|
|
4074
4406
|
}
|
|
4075
|
-
// Helper methods for formatting standards
|
|
4076
|
-
formatTypeScriptStandards(obj) {
|
|
4077
|
-
const items = [];
|
|
4078
|
-
if (obj["strictMode"]) items.push("Strict mode enabled, no `any` types");
|
|
4079
|
-
if (obj["noAny"]) items.push("Never use `any` type - use `unknown` with type guards");
|
|
4080
|
-
if (obj["useUnknown"]) items.push(`Use \`unknown\` ${this.valueToString(obj["useUnknown"])}`);
|
|
4081
|
-
if (obj["interfaces"])
|
|
4082
|
-
items.push(`Prefer \`interface\` ${this.valueToString(obj["interfaces"])}`);
|
|
4083
|
-
if (obj["types"]) items.push(`Use \`type\` ${this.valueToString(obj["types"])}`);
|
|
4084
|
-
if (obj["exports"]) items.push(`${this.capitalize(this.valueToString(obj["exports"]))}`);
|
|
4085
|
-
if (obj["returnTypes"])
|
|
4086
|
-
items.push(`Explicit return types ${this.valueToString(obj["returnTypes"])}`);
|
|
4087
|
-
return items;
|
|
4088
|
-
}
|
|
4089
|
-
formatNamingStandards(obj) {
|
|
4090
|
-
const items = [];
|
|
4091
|
-
if (obj["files"]) items.push(`Files: \`${this.valueToString(obj["files"])}\``);
|
|
4092
|
-
if (obj["classes"]) items.push(`Classes/Interfaces: \`${this.valueToString(obj["classes"])}\``);
|
|
4093
|
-
if (obj["interfaces"]) items.push(`Interfaces: \`${this.valueToString(obj["interfaces"])}\``);
|
|
4094
|
-
if (obj["functions"])
|
|
4095
|
-
items.push(`Functions/Variables: \`${this.valueToString(obj["functions"])}\``);
|
|
4096
|
-
if (obj["variables"]) items.push(`Variables: \`${this.valueToString(obj["variables"])}\``);
|
|
4097
|
-
if (obj["constants"]) items.push(`Constants: \`${this.valueToString(obj["constants"])}\``);
|
|
4098
|
-
return items;
|
|
4099
|
-
}
|
|
4100
|
-
formatErrorStandards(obj) {
|
|
4101
|
-
const items = [];
|
|
4102
|
-
if (obj["customClasses"])
|
|
4103
|
-
items.push(
|
|
4104
|
-
`Use custom error classes extending \`${this.valueToString(obj["customClasses"])}\``
|
|
4105
|
-
);
|
|
4106
|
-
if (obj["locationInfo"]) items.push("Always include location information");
|
|
4107
|
-
if (obj["messages"])
|
|
4108
|
-
items.push(`Provide ${this.valueToString(obj["messages"])} error messages`);
|
|
4109
|
-
return items;
|
|
4110
|
-
}
|
|
4111
|
-
formatTestingStandards(obj) {
|
|
4112
|
-
const items = [];
|
|
4113
|
-
if (obj["filePattern"]) items.push(`Test files: \`${this.valueToString(obj["filePattern"])}\``);
|
|
4114
|
-
if (obj["pattern"]) items.push(`Follow ${this.valueToString(obj["pattern"])} pattern`);
|
|
4115
|
-
if (obj["framework"]) items.push(`Framework: ${this.valueToString(obj["framework"])}`);
|
|
4116
|
-
if (obj["coverage"])
|
|
4117
|
-
items.push(`Target >${this.valueToString(obj["coverage"])}% coverage for libraries`);
|
|
4118
|
-
if (obj["fixtures"]) items.push(`Use fixtures ${this.valueToString(obj["fixtures"])}`);
|
|
4119
|
-
return items;
|
|
4120
|
-
}
|
|
4121
|
-
capitalize(str) {
|
|
4122
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
4123
|
-
}
|
|
4124
4407
|
};
|
|
4125
4408
|
|
|
4126
4409
|
// packages/formatters/src/index.ts
|
|
@@ -14277,8 +14560,8 @@ function parse(source, options = {}) {
|
|
|
14277
14560
|
}
|
|
14278
14561
|
|
|
14279
14562
|
// packages/resolver/src/loader.ts
|
|
14280
|
-
import { readFile as
|
|
14281
|
-
import { resolve, dirname as
|
|
14563
|
+
import { readFile as readFile4 } from "fs/promises";
|
|
14564
|
+
import { resolve as resolve2, dirname as dirname3, isAbsolute } from "path";
|
|
14282
14565
|
var FileLoader = class {
|
|
14283
14566
|
registryPath;
|
|
14284
14567
|
localPath;
|
|
@@ -14295,7 +14578,7 @@ var FileLoader = class {
|
|
|
14295
14578
|
*/
|
|
14296
14579
|
async load(path) {
|
|
14297
14580
|
try {
|
|
14298
|
-
return await
|
|
14581
|
+
return await readFile4(path, "utf-8");
|
|
14299
14582
|
} catch (err) {
|
|
14300
14583
|
if (err.code === "ENOENT") {
|
|
14301
14584
|
throw new FileNotFoundError(path);
|
|
@@ -14324,11 +14607,11 @@ var FileLoader = class {
|
|
|
14324
14607
|
const namespace = match[1];
|
|
14325
14608
|
const segments = match[2];
|
|
14326
14609
|
const fileName2 = segments.endsWith(".prs") ? segments : `${segments}.prs`;
|
|
14327
|
-
return
|
|
14610
|
+
return resolve2(this.registryPath, `@${namespace}`, fileName2);
|
|
14328
14611
|
}
|
|
14329
14612
|
}
|
|
14330
14613
|
const fileName = path.endsWith(".prs") ? path : `${path}.prs`;
|
|
14331
|
-
return
|
|
14614
|
+
return resolve2(this.localPath, fileName);
|
|
14332
14615
|
}
|
|
14333
14616
|
/**
|
|
14334
14617
|
* Resolve a PathReference to an absolute path.
|
|
@@ -14339,9 +14622,9 @@ var FileLoader = class {
|
|
|
14339
14622
|
*/
|
|
14340
14623
|
resolveRef(ref, fromFile) {
|
|
14341
14624
|
if (ref.isRelative) {
|
|
14342
|
-
const dir =
|
|
14343
|
-
const
|
|
14344
|
-
return
|
|
14625
|
+
const dir = dirname3(fromFile);
|
|
14626
|
+
const rawPath = ref.raw.endsWith(".prs") ? ref.raw : `${ref.raw}.prs`;
|
|
14627
|
+
return resolve2(dir, rawPath);
|
|
14345
14628
|
}
|
|
14346
14629
|
return this.toAbsolutePath(ref.raw);
|
|
14347
14630
|
}
|
|
@@ -14665,9 +14948,7 @@ function mergeProperties2(source, target) {
|
|
|
14665
14948
|
sourceVal,
|
|
14666
14949
|
targetVal
|
|
14667
14950
|
);
|
|
14668
|
-
} else if (typeof sourceVal === typeof targetVal) {
|
|
14669
14951
|
} else {
|
|
14670
|
-
result[key] = deepCloneValue2(targetVal);
|
|
14671
14952
|
}
|
|
14672
14953
|
}
|
|
14673
14954
|
return result;
|
|
@@ -15001,6 +15282,115 @@ function uniqueConcat3(parent, child) {
|
|
|
15001
15282
|
return result;
|
|
15002
15283
|
}
|
|
15003
15284
|
|
|
15285
|
+
// packages/resolver/src/skills.ts
|
|
15286
|
+
import { readFile as readFile5, access } from "fs/promises";
|
|
15287
|
+
import { resolve as resolve3, dirname as dirname4 } from "path";
|
|
15288
|
+
function parseSkillMd(content) {
|
|
15289
|
+
const lines = content.split("\n");
|
|
15290
|
+
let inFrontmatter = false;
|
|
15291
|
+
let frontmatterStart = -1;
|
|
15292
|
+
let frontmatterEnd = -1;
|
|
15293
|
+
for (let i = 0; i < lines.length; i++) {
|
|
15294
|
+
const line = lines[i]?.trim() ?? "";
|
|
15295
|
+
if (line === "---") {
|
|
15296
|
+
if (!inFrontmatter) {
|
|
15297
|
+
inFrontmatter = true;
|
|
15298
|
+
frontmatterStart = i;
|
|
15299
|
+
} else {
|
|
15300
|
+
frontmatterEnd = i;
|
|
15301
|
+
break;
|
|
15302
|
+
}
|
|
15303
|
+
}
|
|
15304
|
+
}
|
|
15305
|
+
let name;
|
|
15306
|
+
let description;
|
|
15307
|
+
let bodyContent;
|
|
15308
|
+
if (frontmatterStart >= 0 && frontmatterEnd > frontmatterStart) {
|
|
15309
|
+
const frontmatterLines = lines.slice(frontmatterStart + 1, frontmatterEnd);
|
|
15310
|
+
for (const line of frontmatterLines) {
|
|
15311
|
+
const nameMatch = line.match(/^name:\s*(?:"([^"]+)"|'([^']+)'|(.+))\s*$/);
|
|
15312
|
+
if (nameMatch) {
|
|
15313
|
+
name = (nameMatch[1] ?? nameMatch[2] ?? nameMatch[3])?.trim();
|
|
15314
|
+
}
|
|
15315
|
+
const descMatch = line.match(/^description:\s*(?:"([^"]+)"|'([^']+)'|(.+))\s*$/);
|
|
15316
|
+
if (descMatch) {
|
|
15317
|
+
description = (descMatch[1] ?? descMatch[2] ?? descMatch[3])?.trim();
|
|
15318
|
+
}
|
|
15319
|
+
}
|
|
15320
|
+
bodyContent = lines.slice(frontmatterEnd + 1).join("\n").trim();
|
|
15321
|
+
} else {
|
|
15322
|
+
bodyContent = content.trim();
|
|
15323
|
+
}
|
|
15324
|
+
return { name, description, content: bodyContent };
|
|
15325
|
+
}
|
|
15326
|
+
async function fileExists(path) {
|
|
15327
|
+
try {
|
|
15328
|
+
await access(path);
|
|
15329
|
+
return true;
|
|
15330
|
+
} catch {
|
|
15331
|
+
return false;
|
|
15332
|
+
}
|
|
15333
|
+
}
|
|
15334
|
+
async function resolveNativeSkills(ast, registryPath, sourceFile) {
|
|
15335
|
+
const skillsBlock = ast.blocks.find((b) => b.name === "skills");
|
|
15336
|
+
if (!skillsBlock || skillsBlock.content.type !== "ObjectContent") {
|
|
15337
|
+
return ast;
|
|
15338
|
+
}
|
|
15339
|
+
const skillsContent = skillsBlock.content;
|
|
15340
|
+
const updatedProperties = { ...skillsContent.properties };
|
|
15341
|
+
let hasUpdates = false;
|
|
15342
|
+
const sourceDir = dirname4(sourceFile);
|
|
15343
|
+
const isSkillsDir = sourceDir.includes("@skills");
|
|
15344
|
+
for (const [skillName, skillValue] of Object.entries(skillsContent.properties)) {
|
|
15345
|
+
if (typeof skillValue !== "object" || skillValue === null || Array.isArray(skillValue)) {
|
|
15346
|
+
continue;
|
|
15347
|
+
}
|
|
15348
|
+
const skillObj = skillValue;
|
|
15349
|
+
let skillMdPath = null;
|
|
15350
|
+
if (isSkillsDir) {
|
|
15351
|
+
const basePath = sourceDir;
|
|
15352
|
+
skillMdPath = resolve3(basePath, skillName, "SKILL.md");
|
|
15353
|
+
} else {
|
|
15354
|
+
skillMdPath = resolve3(registryPath, "@skills", skillName, "SKILL.md");
|
|
15355
|
+
}
|
|
15356
|
+
if (skillMdPath && await fileExists(skillMdPath)) {
|
|
15357
|
+
try {
|
|
15358
|
+
const rawContent = await readFile5(skillMdPath, "utf-8");
|
|
15359
|
+
const parsed = parseSkillMd(rawContent);
|
|
15360
|
+
const updatedSkill = { ...skillObj };
|
|
15361
|
+
if (parsed.content) {
|
|
15362
|
+
updatedSkill["content"] = {
|
|
15363
|
+
type: "TextContent",
|
|
15364
|
+
value: parsed.content,
|
|
15365
|
+
loc: { file: skillMdPath, line: 1, column: 1, offset: 0 }
|
|
15366
|
+
};
|
|
15367
|
+
}
|
|
15368
|
+
if (parsed.description && (!skillObj["description"] || typeof skillObj["description"] === "string" && parsed.description.length > skillObj["description"].length)) {
|
|
15369
|
+
updatedSkill["description"] = parsed.description;
|
|
15370
|
+
}
|
|
15371
|
+
updatedProperties[skillName] = updatedSkill;
|
|
15372
|
+
hasUpdates = true;
|
|
15373
|
+
} catch {
|
|
15374
|
+
}
|
|
15375
|
+
}
|
|
15376
|
+
}
|
|
15377
|
+
if (!hasUpdates) {
|
|
15378
|
+
return ast;
|
|
15379
|
+
}
|
|
15380
|
+
const updatedSkillsBlock = {
|
|
15381
|
+
...skillsBlock,
|
|
15382
|
+
content: {
|
|
15383
|
+
...skillsContent,
|
|
15384
|
+
properties: updatedProperties
|
|
15385
|
+
}
|
|
15386
|
+
};
|
|
15387
|
+
const updatedBlocks = ast.blocks.map((b) => b.name === "skills" ? updatedSkillsBlock : b);
|
|
15388
|
+
return {
|
|
15389
|
+
...ast,
|
|
15390
|
+
blocks: updatedBlocks
|
|
15391
|
+
};
|
|
15392
|
+
}
|
|
15393
|
+
|
|
15004
15394
|
// packages/resolver/src/resolver.ts
|
|
15005
15395
|
var Resolver = class {
|
|
15006
15396
|
loader;
|
|
@@ -15053,6 +15443,7 @@ var Resolver = class {
|
|
|
15053
15443
|
ast = await this.resolveInherit(ast, absPath, sources, errors);
|
|
15054
15444
|
ast = await this.resolveImports(ast, absPath, sources, errors);
|
|
15055
15445
|
ast = applyExtends(ast);
|
|
15446
|
+
ast = await resolveNativeSkills(ast, this.loader.getRegistryPath(), absPath);
|
|
15056
15447
|
return {
|
|
15057
15448
|
ast,
|
|
15058
15449
|
sources: [...new Set(sources)],
|
|
@@ -15146,7 +15537,7 @@ var Resolver = class {
|
|
|
15146
15537
|
};
|
|
15147
15538
|
|
|
15148
15539
|
// packages/resolver/src/registry.ts
|
|
15149
|
-
import { existsSync as
|
|
15540
|
+
import { existsSync as existsSync4, promises as fs } from "fs";
|
|
15150
15541
|
import { join as join3 } from "path";
|
|
15151
15542
|
var FileSystemRegistry = class {
|
|
15152
15543
|
rootPath;
|
|
@@ -15173,7 +15564,7 @@ var FileSystemRegistry = class {
|
|
|
15173
15564
|
}
|
|
15174
15565
|
async exists(path) {
|
|
15175
15566
|
const fullPath = this.resolvePath(path);
|
|
15176
|
-
return
|
|
15567
|
+
return existsSync4(fullPath);
|
|
15177
15568
|
}
|
|
15178
15569
|
async list(path) {
|
|
15179
15570
|
const fullPath = this.resolvePath(path);
|
|
@@ -15229,7 +15620,7 @@ var HttpRegistry = class {
|
|
|
15229
15620
|
* Sleep for specified milliseconds.
|
|
15230
15621
|
*/
|
|
15231
15622
|
sleep(ms) {
|
|
15232
|
-
return new Promise((
|
|
15623
|
+
return new Promise((resolve9) => setTimeout(resolve9, ms));
|
|
15233
15624
|
}
|
|
15234
15625
|
/**
|
|
15235
15626
|
* Fetch with timeout.
|
|
@@ -15371,12 +15762,12 @@ function createHttpRegistry(options) {
|
|
|
15371
15762
|
}
|
|
15372
15763
|
|
|
15373
15764
|
// packages/resolver/src/git-registry.ts
|
|
15374
|
-
import { existsSync as
|
|
15765
|
+
import { existsSync as existsSync6, promises as fs3 } from "fs";
|
|
15375
15766
|
import { join as join5 } from "path";
|
|
15376
15767
|
import { simpleGit } from "simple-git";
|
|
15377
15768
|
|
|
15378
15769
|
// packages/resolver/src/git-cache-manager.ts
|
|
15379
|
-
import { existsSync as
|
|
15770
|
+
import { existsSync as existsSync5, promises as fs2 } from "fs";
|
|
15380
15771
|
import { join as join4 } from "path";
|
|
15381
15772
|
import { homedir } from "os";
|
|
15382
15773
|
|
|
@@ -15526,7 +15917,7 @@ var GitCacheManager = class {
|
|
|
15526
15917
|
*/
|
|
15527
15918
|
async get(url, ref) {
|
|
15528
15919
|
const cachePath = this.getCachePath(url, ref);
|
|
15529
|
-
if (!
|
|
15920
|
+
if (!existsSync5(cachePath)) {
|
|
15530
15921
|
return null;
|
|
15531
15922
|
}
|
|
15532
15923
|
const metadata = await this.readMetadata(cachePath);
|
|
@@ -15591,7 +15982,7 @@ var GitCacheManager = class {
|
|
|
15591
15982
|
*/
|
|
15592
15983
|
async remove(url, ref) {
|
|
15593
15984
|
const cachePath = this.getCachePath(url, ref);
|
|
15594
|
-
if (
|
|
15985
|
+
if (existsSync5(cachePath)) {
|
|
15595
15986
|
await fs2.rm(cachePath, { recursive: true, force: true });
|
|
15596
15987
|
}
|
|
15597
15988
|
}
|
|
@@ -15601,7 +15992,7 @@ var GitCacheManager = class {
|
|
|
15601
15992
|
* @returns Array of cache entries
|
|
15602
15993
|
*/
|
|
15603
15994
|
async list() {
|
|
15604
|
-
if (!
|
|
15995
|
+
if (!existsSync5(this.cacheDir)) {
|
|
15605
15996
|
return [];
|
|
15606
15997
|
}
|
|
15607
15998
|
const entries = [];
|
|
@@ -15636,7 +16027,7 @@ var GitCacheManager = class {
|
|
|
15636
16027
|
* Remove all cache entries.
|
|
15637
16028
|
*/
|
|
15638
16029
|
async clear() {
|
|
15639
|
-
if (
|
|
16030
|
+
if (existsSync5(this.cacheDir)) {
|
|
15640
16031
|
await fs2.rm(this.cacheDir, { recursive: true, force: true });
|
|
15641
16032
|
}
|
|
15642
16033
|
}
|
|
@@ -15646,7 +16037,7 @@ var GitCacheManager = class {
|
|
|
15646
16037
|
* @returns Total cache size in bytes
|
|
15647
16038
|
*/
|
|
15648
16039
|
async getSize() {
|
|
15649
|
-
if (!
|
|
16040
|
+
if (!existsSync5(this.cacheDir)) {
|
|
15650
16041
|
return 0;
|
|
15651
16042
|
}
|
|
15652
16043
|
return this.calculateDirSize(this.cacheDir);
|
|
@@ -15673,7 +16064,7 @@ var GitCacheManager = class {
|
|
|
15673
16064
|
*/
|
|
15674
16065
|
async readMetadata(cachePath) {
|
|
15675
16066
|
const metadataPath = join4(cachePath, METADATA_FILE);
|
|
15676
|
-
if (!
|
|
16067
|
+
if (!existsSync5(metadataPath)) {
|
|
15677
16068
|
return null;
|
|
15678
16069
|
}
|
|
15679
16070
|
try {
|
|
@@ -15756,7 +16147,7 @@ var GitRegistry = class {
|
|
|
15756
16147
|
const ref = version ?? this.defaultRef;
|
|
15757
16148
|
const repoPath = await this.ensureCloned(ref);
|
|
15758
16149
|
const filePath = this.resolveFilePath(repoPath, basePath);
|
|
15759
|
-
if (!
|
|
16150
|
+
if (!existsSync6(filePath)) {
|
|
15760
16151
|
throw new FileNotFoundError(path);
|
|
15761
16152
|
}
|
|
15762
16153
|
return fs3.readFile(filePath, "utf-8");
|
|
@@ -15773,7 +16164,7 @@ var GitRegistry = class {
|
|
|
15773
16164
|
const ref = version ?? this.defaultRef;
|
|
15774
16165
|
const repoPath = await this.ensureCloned(ref);
|
|
15775
16166
|
const filePath = this.resolveFilePath(repoPath, basePath);
|
|
15776
|
-
return
|
|
16167
|
+
return existsSync6(filePath);
|
|
15777
16168
|
} catch {
|
|
15778
16169
|
return false;
|
|
15779
16170
|
}
|
|
@@ -15790,7 +16181,7 @@ var GitRegistry = class {
|
|
|
15790
16181
|
const ref = version ?? this.defaultRef;
|
|
15791
16182
|
const repoPath = await this.ensureCloned(ref);
|
|
15792
16183
|
const dirPath = this.resolveDirectoryPath(repoPath, basePath);
|
|
15793
|
-
if (!
|
|
16184
|
+
if (!existsSync6(dirPath)) {
|
|
15794
16185
|
return [];
|
|
15795
16186
|
}
|
|
15796
16187
|
const entries = await fs3.readdir(dirPath, { withFileTypes: true });
|
|
@@ -15852,7 +16243,7 @@ var GitRegistry = class {
|
|
|
15852
16243
|
* Clone the repository to the specified path.
|
|
15853
16244
|
*/
|
|
15854
16245
|
async clone(targetPath, ref) {
|
|
15855
|
-
if (
|
|
16246
|
+
if (existsSync6(targetPath)) {
|
|
15856
16247
|
await fs3.rm(targetPath, { recursive: true, force: true });
|
|
15857
16248
|
}
|
|
15858
16249
|
await fs3.mkdir(targetPath, { recursive: true });
|
|
@@ -16644,12 +17035,12 @@ var Compiler = class _Compiler {
|
|
|
16644
17035
|
*/
|
|
16645
17036
|
async watch(entryPath, options = {}) {
|
|
16646
17037
|
const { default: chokidar2 } = await import("chokidar");
|
|
16647
|
-
const { dirname:
|
|
16648
|
-
const baseDir =
|
|
17038
|
+
const { dirname: dirname8, resolve: resolve9 } = await import("path");
|
|
17039
|
+
const baseDir = dirname8(resolve9(entryPath));
|
|
16649
17040
|
const includePatterns = options.include ?? ["**/*.prs"];
|
|
16650
17041
|
const excludePatterns = options.exclude ?? ["**/node_modules/**"];
|
|
16651
17042
|
const debounceMs = options.debounce ?? 300;
|
|
16652
|
-
const watchPatterns = includePatterns.map((p) =>
|
|
17043
|
+
const watchPatterns = includePatterns.map((p) => resolve9(baseDir, p));
|
|
16653
17044
|
let debounceTimer = null;
|
|
16654
17045
|
let pendingChanges = [];
|
|
16655
17046
|
const handleChange = async (changedFiles) => {
|
|
@@ -16704,14 +17095,13 @@ var Compiler = class _Compiler {
|
|
|
16704
17095
|
*/
|
|
16705
17096
|
getFormatOptionsForTarget(_targetName, config) {
|
|
16706
17097
|
const customConventions = this.options.customConventions;
|
|
16707
|
-
|
|
16708
|
-
return {};
|
|
16709
|
-
}
|
|
16710
|
-
const conventionName = config?.convention;
|
|
17098
|
+
const prettierOptions = this.options.prettier;
|
|
16711
17099
|
const options = {
|
|
16712
17100
|
outputPath: config?.output,
|
|
16713
|
-
version: config?.version
|
|
17101
|
+
version: config?.version,
|
|
17102
|
+
prettier: prettierOptions
|
|
16714
17103
|
};
|
|
17104
|
+
const conventionName = config?.convention;
|
|
16715
17105
|
if (conventionName && customConventions?.[conventionName]) {
|
|
16716
17106
|
options.convention = customConventions[conventionName];
|
|
16717
17107
|
} else if (conventionName) {
|
|
@@ -16788,7 +17178,86 @@ var Compiler = class _Compiler {
|
|
|
16788
17178
|
}
|
|
16789
17179
|
};
|
|
16790
17180
|
|
|
17181
|
+
// packages/cli/src/output/pager.ts
|
|
17182
|
+
import { spawn } from "child_process";
|
|
17183
|
+
function isTTY() {
|
|
17184
|
+
return process.stdout.isTTY === true;
|
|
17185
|
+
}
|
|
17186
|
+
function getPagerCommand() {
|
|
17187
|
+
return process.env["PAGER"] ?? "less";
|
|
17188
|
+
}
|
|
17189
|
+
var Pager = class {
|
|
17190
|
+
lines = [];
|
|
17191
|
+
enabled;
|
|
17192
|
+
constructor(enabled = true) {
|
|
17193
|
+
this.enabled = enabled && isTTY();
|
|
17194
|
+
}
|
|
17195
|
+
/**
|
|
17196
|
+
* Write a line to the pager buffer.
|
|
17197
|
+
*/
|
|
17198
|
+
write(line) {
|
|
17199
|
+
this.lines.push(line);
|
|
17200
|
+
}
|
|
17201
|
+
/**
|
|
17202
|
+
* Write multiple lines to the pager buffer.
|
|
17203
|
+
*/
|
|
17204
|
+
writeLines(lines) {
|
|
17205
|
+
this.lines.push(...lines);
|
|
17206
|
+
}
|
|
17207
|
+
/**
|
|
17208
|
+
* Flush all buffered content through the pager.
|
|
17209
|
+
* If pager is disabled or not a TTY, just prints to stdout.
|
|
17210
|
+
*/
|
|
17211
|
+
async flush() {
|
|
17212
|
+
const content = this.lines.join("\n");
|
|
17213
|
+
if (!this.enabled || this.lines.length === 0) {
|
|
17214
|
+
if (content) {
|
|
17215
|
+
console.log(content);
|
|
17216
|
+
}
|
|
17217
|
+
return;
|
|
17218
|
+
}
|
|
17219
|
+
return new Promise((resolve9) => {
|
|
17220
|
+
const pagerCmd = getPagerCommand();
|
|
17221
|
+
const [cmd, ...args] = pagerCmd.split(" ");
|
|
17222
|
+
if (cmd === "less" && !args.includes("-R")) {
|
|
17223
|
+
args.push("-R");
|
|
17224
|
+
}
|
|
17225
|
+
if (!cmd) {
|
|
17226
|
+
console.log(content);
|
|
17227
|
+
resolve9();
|
|
17228
|
+
return;
|
|
17229
|
+
}
|
|
17230
|
+
const pager = spawn(cmd, args, {
|
|
17231
|
+
stdio: ["pipe", "inherit", "inherit"],
|
|
17232
|
+
env: {
|
|
17233
|
+
...process.env,
|
|
17234
|
+
// Ensure less handles colors properly
|
|
17235
|
+
LESS: process.env["LESS"] ?? "-R"
|
|
17236
|
+
}
|
|
17237
|
+
});
|
|
17238
|
+
pager.on("error", (_err) => {
|
|
17239
|
+
console.log(content);
|
|
17240
|
+
resolve9();
|
|
17241
|
+
});
|
|
17242
|
+
pager.on("close", () => {
|
|
17243
|
+
resolve9();
|
|
17244
|
+
});
|
|
17245
|
+
if (pager.stdin) {
|
|
17246
|
+
pager.stdin.write(content);
|
|
17247
|
+
pager.stdin.end();
|
|
17248
|
+
} else {
|
|
17249
|
+
console.log(content);
|
|
17250
|
+
resolve9();
|
|
17251
|
+
}
|
|
17252
|
+
});
|
|
17253
|
+
}
|
|
17254
|
+
};
|
|
17255
|
+
function createPager(enabled = true) {
|
|
17256
|
+
return new Pager(enabled);
|
|
17257
|
+
}
|
|
17258
|
+
|
|
16791
17259
|
// packages/cli/src/commands/compile.ts
|
|
17260
|
+
var PROMPTSCRIPT_MARKER = "> Auto-generated by PromptScript";
|
|
16792
17261
|
function parseTargets(targets) {
|
|
16793
17262
|
return targets.map((entry) => {
|
|
16794
17263
|
if (typeof entry === "string") {
|
|
@@ -16802,6 +17271,28 @@ function parseTargets(targets) {
|
|
|
16802
17271
|
return { name, config };
|
|
16803
17272
|
}).filter((target) => target.config?.enabled !== false);
|
|
16804
17273
|
}
|
|
17274
|
+
async function isPromptScriptGenerated(filePath) {
|
|
17275
|
+
try {
|
|
17276
|
+
const content = await readFile6(filePath, "utf-8");
|
|
17277
|
+
const lines = content.split("\n").slice(0, 10);
|
|
17278
|
+
return lines.some((line) => line.includes(PROMPTSCRIPT_MARKER));
|
|
17279
|
+
} catch {
|
|
17280
|
+
return false;
|
|
17281
|
+
}
|
|
17282
|
+
}
|
|
17283
|
+
async function promptForOverwrite(filePath, services) {
|
|
17284
|
+
const response = await services.prompts.select({
|
|
17285
|
+
message: `File exists and was not generated by PromptScript: ${filePath}
|
|
17286
|
+
Overwrite?`,
|
|
17287
|
+
choices: [
|
|
17288
|
+
{ name: "No (skip this file)", value: "no" },
|
|
17289
|
+
{ name: "Yes (overwrite this file)", value: "yes" },
|
|
17290
|
+
{ name: "All (overwrite all remaining files)", value: "all" }
|
|
17291
|
+
],
|
|
17292
|
+
default: "no"
|
|
17293
|
+
});
|
|
17294
|
+
return response;
|
|
17295
|
+
}
|
|
16805
17296
|
function printErrors(errors) {
|
|
16806
17297
|
for (const err of errors) {
|
|
16807
17298
|
ConsoleOutput.error(err.message);
|
|
@@ -16810,17 +17301,84 @@ function printErrors(errors) {
|
|
|
16810
17301
|
}
|
|
16811
17302
|
}
|
|
16812
17303
|
}
|
|
16813
|
-
async function writeOutputs(outputs, options, _config) {
|
|
17304
|
+
async function writeOutputs(outputs, options, _config, services) {
|
|
17305
|
+
const result = { written: [], skipped: [] };
|
|
17306
|
+
let overwriteAll = false;
|
|
17307
|
+
const conflicts = [];
|
|
16814
17308
|
for (const output of outputs.values()) {
|
|
16815
|
-
const outputPath = options.output ?
|
|
17309
|
+
const outputPath = options.output ? resolve4(options.output, output.path) : resolve4(output.path);
|
|
17310
|
+
const fileExists2 = existsSync7(outputPath);
|
|
16816
17311
|
if (options.dryRun) {
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
17312
|
+
if (fileExists2) {
|
|
17313
|
+
const isGenerated2 = await isPromptScriptGenerated(outputPath);
|
|
17314
|
+
if (isGenerated2) {
|
|
17315
|
+
ConsoleOutput.dryRun(`Would overwrite: ${outputPath}`);
|
|
17316
|
+
} else {
|
|
17317
|
+
ConsoleOutput.warning(`Would conflict: ${outputPath} (not generated by PromptScript)`);
|
|
17318
|
+
}
|
|
17319
|
+
} else {
|
|
17320
|
+
ConsoleOutput.dryRun(`Would write: ${outputPath}`);
|
|
17321
|
+
}
|
|
17322
|
+
result.written.push(outputPath);
|
|
17323
|
+
continue;
|
|
17324
|
+
}
|
|
17325
|
+
if (!fileExists2) {
|
|
17326
|
+
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
17327
|
+
await writeFile2(outputPath, output.content, "utf-8");
|
|
17328
|
+
ConsoleOutput.success(outputPath);
|
|
17329
|
+
result.written.push(outputPath);
|
|
17330
|
+
continue;
|
|
17331
|
+
}
|
|
17332
|
+
const isGenerated = await isPromptScriptGenerated(outputPath);
|
|
17333
|
+
if (isGenerated) {
|
|
17334
|
+
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
16820
17335
|
await writeFile2(outputPath, output.content, "utf-8");
|
|
16821
17336
|
ConsoleOutput.success(outputPath);
|
|
17337
|
+
result.written.push(outputPath);
|
|
17338
|
+
continue;
|
|
17339
|
+
}
|
|
17340
|
+
if (options.force || overwriteAll) {
|
|
17341
|
+
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
17342
|
+
await writeFile2(outputPath, output.content, "utf-8");
|
|
17343
|
+
ConsoleOutput.success(outputPath);
|
|
17344
|
+
result.written.push(outputPath);
|
|
17345
|
+
continue;
|
|
17346
|
+
}
|
|
17347
|
+
if (!isTTY()) {
|
|
17348
|
+
conflicts.push(outputPath);
|
|
17349
|
+
continue;
|
|
17350
|
+
}
|
|
17351
|
+
const response = await promptForOverwrite(outputPath, services);
|
|
17352
|
+
switch (response) {
|
|
17353
|
+
case "yes":
|
|
17354
|
+
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
17355
|
+
await writeFile2(outputPath, output.content, "utf-8");
|
|
17356
|
+
ConsoleOutput.success(outputPath);
|
|
17357
|
+
result.written.push(outputPath);
|
|
17358
|
+
break;
|
|
17359
|
+
case "no":
|
|
17360
|
+
ConsoleOutput.skipped(outputPath);
|
|
17361
|
+
result.skipped.push(outputPath);
|
|
17362
|
+
break;
|
|
17363
|
+
case "all":
|
|
17364
|
+
overwriteAll = true;
|
|
17365
|
+
await mkdir2(dirname5(outputPath), { recursive: true });
|
|
17366
|
+
await writeFile2(outputPath, output.content, "utf-8");
|
|
17367
|
+
ConsoleOutput.success(outputPath);
|
|
17368
|
+
result.written.push(outputPath);
|
|
17369
|
+
break;
|
|
16822
17370
|
}
|
|
16823
17371
|
}
|
|
17372
|
+
if (conflicts.length > 0) {
|
|
17373
|
+
const fileList = conflicts.map((f) => ` - ${f}`).join("\n");
|
|
17374
|
+
throw new Error(
|
|
17375
|
+
`Cannot overwrite files not generated by PromptScript in non-interactive mode:
|
|
17376
|
+
${fileList}
|
|
17377
|
+
|
|
17378
|
+
Use --force to overwrite these files.`
|
|
17379
|
+
);
|
|
17380
|
+
}
|
|
17381
|
+
return result;
|
|
16824
17382
|
}
|
|
16825
17383
|
function printStats(stats) {
|
|
16826
17384
|
ConsoleOutput.newline();
|
|
@@ -16837,7 +17395,7 @@ function printWarnings(warnings) {
|
|
|
16837
17395
|
}
|
|
16838
17396
|
}
|
|
16839
17397
|
}
|
|
16840
|
-
async function compileCommand(options) {
|
|
17398
|
+
async function compileCommand(options, services = createDefaultServices()) {
|
|
16841
17399
|
const spinner = createSpinner("Loading configuration...").start();
|
|
16842
17400
|
try {
|
|
16843
17401
|
const config = await loadConfig(options.config);
|
|
@@ -16845,6 +17403,7 @@ async function compileCommand(options) {
|
|
|
16845
17403
|
const selectedTarget = options.target ?? options.format;
|
|
16846
17404
|
const targets = selectedTarget ? [{ name: selectedTarget }] : parseTargets(config.targets);
|
|
16847
17405
|
const registryPath = options.registry ?? config.registry?.path ?? "./registry";
|
|
17406
|
+
const prettierOptions = await resolvePrettierOptions(config, process.cwd());
|
|
16848
17407
|
const compiler = new Compiler({
|
|
16849
17408
|
resolver: {
|
|
16850
17409
|
registryPath,
|
|
@@ -16852,10 +17411,11 @@ async function compileCommand(options) {
|
|
|
16852
17411
|
},
|
|
16853
17412
|
validator: config.validation,
|
|
16854
17413
|
formatters: targets,
|
|
16855
|
-
customConventions: config.customConventions
|
|
17414
|
+
customConventions: config.customConventions,
|
|
17415
|
+
prettier: prettierOptions
|
|
16856
17416
|
});
|
|
16857
|
-
const entryPath =
|
|
16858
|
-
if (!
|
|
17417
|
+
const entryPath = resolve4("./.promptscript/project.prs");
|
|
17418
|
+
if (!existsSync7(entryPath)) {
|
|
16859
17419
|
spinner.fail("Entry file not found");
|
|
16860
17420
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
16861
17421
|
ConsoleOutput.muted("Run: prs init");
|
|
@@ -16870,15 +17430,27 @@ async function compileCommand(options) {
|
|
|
16870
17430
|
}
|
|
16871
17431
|
spinner.succeed("Compilation successful");
|
|
16872
17432
|
ConsoleOutput.newline();
|
|
16873
|
-
await writeOutputs(result.outputs, options, config);
|
|
17433
|
+
const writeResult = await writeOutputs(result.outputs, options, config, services);
|
|
17434
|
+
if (writeResult.skipped.length > 0) {
|
|
17435
|
+
ConsoleOutput.muted(`Skipped ${writeResult.skipped.length} file(s)`);
|
|
17436
|
+
}
|
|
16874
17437
|
printStats(result.stats);
|
|
16875
17438
|
printWarnings(result.warnings);
|
|
16876
17439
|
if (options.watch) {
|
|
16877
17440
|
ConsoleOutput.newline();
|
|
16878
17441
|
ConsoleOutput.info("Watching for changes... (Ctrl+C to stop)");
|
|
16879
|
-
watchForChanges(
|
|
17442
|
+
watchForChanges(
|
|
17443
|
+
"./.promptscript",
|
|
17444
|
+
() => compileCommand({ ...options, watch: false }, services)
|
|
17445
|
+
);
|
|
16880
17446
|
}
|
|
16881
17447
|
} catch (error) {
|
|
17448
|
+
if (error.name === "ExitPromptError") {
|
|
17449
|
+
spinner.stop();
|
|
17450
|
+
ConsoleOutput.newline();
|
|
17451
|
+
ConsoleOutput.muted("Compilation cancelled");
|
|
17452
|
+
return;
|
|
17453
|
+
}
|
|
16882
17454
|
spinner.fail("Error");
|
|
16883
17455
|
ConsoleOutput.error(error.message);
|
|
16884
17456
|
process.exit(1);
|
|
@@ -16919,8 +17491,8 @@ function watchForChanges(dir, callback) {
|
|
|
16919
17491
|
}
|
|
16920
17492
|
|
|
16921
17493
|
// packages/cli/src/commands/validate.ts
|
|
16922
|
-
import { resolve as
|
|
16923
|
-
import { existsSync as
|
|
17494
|
+
import { resolve as resolve5 } from "path";
|
|
17495
|
+
import { existsSync as existsSync8 } from "fs";
|
|
16924
17496
|
function printValidationErrors(errors) {
|
|
16925
17497
|
if (errors.length === 0) return;
|
|
16926
17498
|
console.log(`Errors (${errors.length}):`);
|
|
@@ -17010,8 +17582,8 @@ async function validateCommand(options) {
|
|
|
17010
17582
|
formatters: []
|
|
17011
17583
|
// No formatters needed for validation only
|
|
17012
17584
|
});
|
|
17013
|
-
const entryPath =
|
|
17014
|
-
if (!
|
|
17585
|
+
const entryPath = resolve5("./.promptscript/project.prs");
|
|
17586
|
+
if (!existsSync8(entryPath)) {
|
|
17015
17587
|
handleEntryNotFound(entryPath, isJsonFormat, spinner);
|
|
17016
17588
|
}
|
|
17017
17589
|
const result = await compiler.compile(entryPath);
|
|
@@ -17051,8 +17623,8 @@ function outputJsonResult(result) {
|
|
|
17051
17623
|
|
|
17052
17624
|
// packages/cli/src/commands/pull.ts
|
|
17053
17625
|
import { mkdir as mkdir3, writeFile as writeFile3 } from "fs/promises";
|
|
17054
|
-
import { existsSync as
|
|
17055
|
-
import { resolve as
|
|
17626
|
+
import { existsSync as existsSync9 } from "fs";
|
|
17627
|
+
import { resolve as resolve6, dirname as dirname6 } from "path";
|
|
17056
17628
|
async function pullCommand(options) {
|
|
17057
17629
|
const spinner = createSpinner("Loading configuration...").start();
|
|
17058
17630
|
try {
|
|
@@ -17075,8 +17647,8 @@ async function pullCommand(options) {
|
|
|
17075
17647
|
}
|
|
17076
17648
|
spinner.text = `Fetching ${inheritPath}...`;
|
|
17077
17649
|
const content = await registry.fetch(inheritPath);
|
|
17078
|
-
const destPath =
|
|
17079
|
-
if (
|
|
17650
|
+
const destPath = resolve6("./.promptscript/.inherited", inheritPath);
|
|
17651
|
+
if (existsSync9(destPath) && !options.force && !options.dryRun) {
|
|
17080
17652
|
spinner.warn("File already exists (use --force to overwrite)");
|
|
17081
17653
|
ConsoleOutput.muted(destPath);
|
|
17082
17654
|
return;
|
|
@@ -17086,12 +17658,12 @@ async function pullCommand(options) {
|
|
|
17086
17658
|
ConsoleOutput.newline();
|
|
17087
17659
|
ConsoleOutput.dryRun(`Would fetch: ${config.inherit}`);
|
|
17088
17660
|
ConsoleOutput.dryRun(` to: ${destPath}`);
|
|
17089
|
-
if (
|
|
17661
|
+
if (existsSync9(destPath)) {
|
|
17090
17662
|
ConsoleOutput.dryRun("(would overwrite existing file)");
|
|
17091
17663
|
}
|
|
17092
17664
|
return;
|
|
17093
17665
|
}
|
|
17094
|
-
await mkdir3(
|
|
17666
|
+
await mkdir3(dirname6(destPath), { recursive: true });
|
|
17095
17667
|
await writeFile3(destPath, content, "utf-8");
|
|
17096
17668
|
spinner.succeed("Pulled from registry");
|
|
17097
17669
|
ConsoleOutput.success(destPath);
|
|
@@ -17134,10 +17706,10 @@ async function createRegistry(config, options, spinner) {
|
|
|
17134
17706
|
}
|
|
17135
17707
|
const registryPath = config.registry?.path ?? "./registry";
|
|
17136
17708
|
spinner.text = `Using local registry: ${registryPath}...`;
|
|
17137
|
-
if (!
|
|
17709
|
+
if (!existsSync9(registryPath)) {
|
|
17138
17710
|
throw new Error(`Local registry path not found: ${registryPath}`);
|
|
17139
17711
|
}
|
|
17140
|
-
return createFileSystemRegistry(
|
|
17712
|
+
return createFileSystemRegistry(resolve6(registryPath));
|
|
17141
17713
|
}
|
|
17142
17714
|
function parseInheritPath(inheritPath) {
|
|
17143
17715
|
const versionIndex = inheritPath.lastIndexOf("@");
|
|
@@ -17184,89 +17756,9 @@ function handlePullError(error, spinner) {
|
|
|
17184
17756
|
}
|
|
17185
17757
|
|
|
17186
17758
|
// packages/cli/src/commands/diff.ts
|
|
17187
|
-
import { resolve as
|
|
17188
|
-
import { readFile as
|
|
17189
|
-
import { existsSync as
|
|
17190
|
-
|
|
17191
|
-
// packages/cli/src/output/pager.ts
|
|
17192
|
-
import { spawn } from "child_process";
|
|
17193
|
-
function isTTY() {
|
|
17194
|
-
return process.stdout.isTTY === true;
|
|
17195
|
-
}
|
|
17196
|
-
function getPagerCommand() {
|
|
17197
|
-
return process.env["PAGER"] ?? "less";
|
|
17198
|
-
}
|
|
17199
|
-
var Pager = class {
|
|
17200
|
-
lines = [];
|
|
17201
|
-
enabled;
|
|
17202
|
-
constructor(enabled = true) {
|
|
17203
|
-
this.enabled = enabled && isTTY();
|
|
17204
|
-
}
|
|
17205
|
-
/**
|
|
17206
|
-
* Write a line to the pager buffer.
|
|
17207
|
-
*/
|
|
17208
|
-
write(line) {
|
|
17209
|
-
this.lines.push(line);
|
|
17210
|
-
}
|
|
17211
|
-
/**
|
|
17212
|
-
* Write multiple lines to the pager buffer.
|
|
17213
|
-
*/
|
|
17214
|
-
writeLines(lines) {
|
|
17215
|
-
this.lines.push(...lines);
|
|
17216
|
-
}
|
|
17217
|
-
/**
|
|
17218
|
-
* Flush all buffered content through the pager.
|
|
17219
|
-
* If pager is disabled or not a TTY, just prints to stdout.
|
|
17220
|
-
*/
|
|
17221
|
-
async flush() {
|
|
17222
|
-
const content = this.lines.join("\n");
|
|
17223
|
-
if (!this.enabled || this.lines.length === 0) {
|
|
17224
|
-
if (content) {
|
|
17225
|
-
console.log(content);
|
|
17226
|
-
}
|
|
17227
|
-
return;
|
|
17228
|
-
}
|
|
17229
|
-
return new Promise((resolve7) => {
|
|
17230
|
-
const pagerCmd = getPagerCommand();
|
|
17231
|
-
const [cmd, ...args] = pagerCmd.split(" ");
|
|
17232
|
-
if (cmd === "less" && !args.includes("-R")) {
|
|
17233
|
-
args.push("-R");
|
|
17234
|
-
}
|
|
17235
|
-
if (!cmd) {
|
|
17236
|
-
console.log(content);
|
|
17237
|
-
resolve7();
|
|
17238
|
-
return;
|
|
17239
|
-
}
|
|
17240
|
-
const pager = spawn(cmd, args, {
|
|
17241
|
-
stdio: ["pipe", "inherit", "inherit"],
|
|
17242
|
-
env: {
|
|
17243
|
-
...process.env,
|
|
17244
|
-
// Ensure less handles colors properly
|
|
17245
|
-
LESS: process.env["LESS"] ?? "-R"
|
|
17246
|
-
}
|
|
17247
|
-
});
|
|
17248
|
-
pager.on("error", (_err) => {
|
|
17249
|
-
console.log(content);
|
|
17250
|
-
resolve7();
|
|
17251
|
-
});
|
|
17252
|
-
pager.on("close", () => {
|
|
17253
|
-
resolve7();
|
|
17254
|
-
});
|
|
17255
|
-
if (pager.stdin) {
|
|
17256
|
-
pager.stdin.write(content);
|
|
17257
|
-
pager.stdin.end();
|
|
17258
|
-
} else {
|
|
17259
|
-
console.log(content);
|
|
17260
|
-
resolve7();
|
|
17261
|
-
}
|
|
17262
|
-
});
|
|
17263
|
-
}
|
|
17264
|
-
};
|
|
17265
|
-
function createPager(enabled = true) {
|
|
17266
|
-
return new Pager(enabled);
|
|
17267
|
-
}
|
|
17268
|
-
|
|
17269
|
-
// packages/cli/src/commands/diff.ts
|
|
17759
|
+
import { resolve as resolve7 } from "path";
|
|
17760
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
17761
|
+
import { existsSync as existsSync10 } from "fs";
|
|
17270
17762
|
import chalk2 from "chalk";
|
|
17271
17763
|
function configureColors(options) {
|
|
17272
17764
|
if (options.color === false) {
|
|
@@ -17300,16 +17792,16 @@ function printNewFilePreview(content, showFull, pager) {
|
|
|
17300
17792
|
}
|
|
17301
17793
|
}
|
|
17302
17794
|
async function compareOutput(_name, output, _config, showFull, pager) {
|
|
17303
|
-
const outputPath =
|
|
17795
|
+
const outputPath = resolve7(output.path);
|
|
17304
17796
|
const newContent = output.content;
|
|
17305
|
-
if (!
|
|
17797
|
+
if (!existsSync10(outputPath)) {
|
|
17306
17798
|
pager.write(chalk2.green(`+ ${outputPath} (new file)`));
|
|
17307
17799
|
pager.write("");
|
|
17308
17800
|
printNewFilePreview(newContent, showFull, pager);
|
|
17309
17801
|
pager.write("");
|
|
17310
17802
|
return true;
|
|
17311
17803
|
}
|
|
17312
|
-
const existingContent = await
|
|
17804
|
+
const existingContent = await readFile7(outputPath, "utf-8");
|
|
17313
17805
|
if (existingContent === newContent) {
|
|
17314
17806
|
pager.write(chalk2.gray(` ${outputPath} (no changes)`));
|
|
17315
17807
|
return false;
|
|
@@ -17338,8 +17830,8 @@ async function diffCommand(options) {
|
|
|
17338
17830
|
formatters: targets,
|
|
17339
17831
|
customConventions: config.customConventions
|
|
17340
17832
|
});
|
|
17341
|
-
const entryPath =
|
|
17342
|
-
if (!
|
|
17833
|
+
const entryPath = resolve7("./.promptscript/project.prs");
|
|
17834
|
+
if (!existsSync10(entryPath)) {
|
|
17343
17835
|
spinner.fail("Entry file not found");
|
|
17344
17836
|
ConsoleOutput.error(`File not found: ${entryPath}`);
|
|
17345
17837
|
ConsoleOutput.muted("Run: prs init");
|
|
@@ -17405,8 +17897,8 @@ function printSimpleDiff(existingLines, newLines, showFull, pager) {
|
|
|
17405
17897
|
}
|
|
17406
17898
|
|
|
17407
17899
|
// packages/cli/src/commands/check.ts
|
|
17408
|
-
import { existsSync as
|
|
17409
|
-
import { resolve as
|
|
17900
|
+
import { existsSync as existsSync11 } from "fs";
|
|
17901
|
+
import { resolve as resolve8 } from "path";
|
|
17410
17902
|
async function checkCommand(_options) {
|
|
17411
17903
|
const spinner = createSpinner("Checking project health...").start();
|
|
17412
17904
|
const results = [];
|
|
@@ -17468,7 +17960,7 @@ async function checkCommand(_options) {
|
|
|
17468
17960
|
});
|
|
17469
17961
|
}
|
|
17470
17962
|
const entryPath = config.input?.entry ?? ".promptscript/project.prs";
|
|
17471
|
-
if (
|
|
17963
|
+
if (existsSync11(entryPath)) {
|
|
17472
17964
|
results.push({
|
|
17473
17965
|
name: "Entry file",
|
|
17474
17966
|
status: "ok",
|
|
@@ -17483,8 +17975,8 @@ async function checkCommand(_options) {
|
|
|
17483
17975
|
hasErrors = true;
|
|
17484
17976
|
}
|
|
17485
17977
|
if (config.registry?.path) {
|
|
17486
|
-
const registryPath =
|
|
17487
|
-
if (
|
|
17978
|
+
const registryPath = resolve8(config.registry.path);
|
|
17979
|
+
if (existsSync11(registryPath)) {
|
|
17488
17980
|
results.push({
|
|
17489
17981
|
name: "Registry path",
|
|
17490
17982
|
status: "ok",
|
|
@@ -17567,7 +18059,7 @@ function printResults(results) {
|
|
|
17567
18059
|
|
|
17568
18060
|
// packages/cli/src/cli.ts
|
|
17569
18061
|
var __filename2 = fileURLToPath2(import.meta.url);
|
|
17570
|
-
var __dirname2 =
|
|
18062
|
+
var __dirname2 = dirname7(__filename2);
|
|
17571
18063
|
var program = new Command();
|
|
17572
18064
|
program.name("prs").description("PromptScript CLI - Standardize AI instructions").version(getPackageVersion(__dirname2, "./package.json")).option("--verbose", "Enable verbose output").option("--quiet", "Suppress non-error output").hook("preAction", (thisCommand) => {
|
|
17573
18065
|
const opts = thisCommand.opts();
|
|
@@ -17581,7 +18073,7 @@ program.name("prs").description("PromptScript CLI - Standardize AI instructions"
|
|
|
17581
18073
|
}
|
|
17582
18074
|
});
|
|
17583
18075
|
program.command("init").description("Initialize PromptScript in current directory").option("-n, --name <name>", "Project name (auto-detected from package.json, etc.)").option("-t, --team <team>", "Team namespace").option("--inherit <path>", "Inheritance path (e.g., @company/team)").option("--registry <path>", "Registry path").option("--targets <targets...>", "Target AI tools (github, claude, cursor)").option("-i, --interactive", "Force interactive mode").option("-y, --yes", "Skip prompts, use defaults").option("-f, --force", "Force reinitialize even if already initialized").action((opts) => initCommand(opts));
|
|
17584
|
-
program.command("compile").description("Compile PromptScript to target formats").option("-t, --target <target>", "Specific target (github, claude, cursor)").option("-f, --format <format>", "Output format (alias for --target)").option("-a, --all", "All configured targets", true).option("-w, --watch", "Watch mode").option("-o, --output <dir>", "Output directory").option("--dry-run", "Preview changes").option("--registry <path>", "Registry path (overrides config)").option("-c, --config <path>", "Path to custom config file").action(compileCommand);
|
|
18076
|
+
program.command("compile").description("Compile PromptScript to target formats").option("-t, --target <target>", "Specific target (github, claude, cursor)").option("-f, --format <format>", "Output format (alias for --target)").option("-a, --all", "All configured targets", true).option("-w, --watch", "Watch mode").option("-o, --output <dir>", "Output directory").option("--dry-run", "Preview changes").option("--registry <path>", "Registry path (overrides config)").option("-c, --config <path>", "Path to custom config file").option("--force", "Force overwrite existing files without prompts").action(compileCommand);
|
|
17585
18077
|
program.command("validate").description("Validate PromptScript files").option("--strict", "Treat warnings as errors").option("--format <format>", "Output format (text, json)", "text").action(validateCommand);
|
|
17586
18078
|
program.command("pull").description("Pull updates from registry").option("-f, --force", "Force overwrite").option("--dry-run", "Preview changes without pulling").option("-b, --branch <name>", "Git branch to pull from").option("--tag <name>", "Git tag to pull from").option("--commit <hash>", "Git commit to pull from").option("--refresh", "Force re-fetch from remote (ignore cache)").action(pullCommand);
|
|
17587
18079
|
program.command("diff").description("Show diff for compiled output").option("-t, --target <target>", "Specific target").option("-a, --all", "Show diff for all targets at once").option("--full", "Show full diff without truncation").option("--no-pager", "Disable pager output").option("--color", "Force colored output").option("--no-color", "Disable colored output").action(diffCommand);
|