@skillkit/core 1.7.9 → 1.7.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -713,8 +713,8 @@ function validateSkill(skillPath) {
713
713
  return { valid: errors.length === 0, errors, warnings };
714
714
  }
715
715
  function isPathInside(child, parent) {
716
- const relative4 = child.replace(parent, "");
717
- return !relative4.startsWith("..") && !relative4.includes("/..");
716
+ const relative5 = child.replace(parent, "");
717
+ return !relative5.startsWith("..") && !relative5.includes("/..");
718
718
  }
719
719
 
720
720
  // src/config.ts
@@ -18516,11 +18516,1316 @@ function getQualityGrade(score) {
18516
18516
  function isHighQuality(score) {
18517
18517
  return score.overall >= 80 && score.warnings.length <= 2;
18518
18518
  }
18519
+
18520
+ // src/primer/types.ts
18521
+ import { z as z6 } from "zod";
18522
+ var PrimerLanguage = z6.enum([
18523
+ "typescript",
18524
+ "javascript",
18525
+ "python",
18526
+ "go",
18527
+ "rust",
18528
+ "java",
18529
+ "kotlin",
18530
+ "swift",
18531
+ "ruby",
18532
+ "php",
18533
+ "csharp",
18534
+ "cpp"
18535
+ ]);
18536
+ var PackageManager = z6.enum([
18537
+ "npm",
18538
+ "pnpm",
18539
+ "yarn",
18540
+ "bun",
18541
+ "pip",
18542
+ "poetry",
18543
+ "uv",
18544
+ "cargo",
18545
+ "go",
18546
+ "maven",
18547
+ "gradle",
18548
+ "composer",
18549
+ "bundler",
18550
+ "cocoapods",
18551
+ "swift-package-manager",
18552
+ "nuget"
18553
+ ]);
18554
+ var CodeConvention = z6.object({
18555
+ namingStyle: z6.enum(["camelCase", "snake_case", "PascalCase", "kebab-case"]).optional(),
18556
+ indentation: z6.enum(["tabs", "spaces-2", "spaces-4"]).optional(),
18557
+ quotes: z6.enum(["single", "double"]).optional(),
18558
+ semicolons: z6.boolean().optional(),
18559
+ trailingCommas: z6.enum(["none", "es5", "all"]).optional(),
18560
+ maxLineLength: z6.number().optional()
18561
+ });
18562
+ var ProjectStructure = z6.object({
18563
+ type: z6.enum(["flat", "src-based", "monorepo", "packages"]).optional(),
18564
+ srcDir: z6.string().optional(),
18565
+ testDir: z6.string().optional(),
18566
+ docsDir: z6.string().optional(),
18567
+ configDir: z6.string().optional(),
18568
+ hasWorkspaces: z6.boolean().default(false),
18569
+ workspaces: z6.array(z6.string()).optional()
18570
+ });
18571
+ var CIConfig = z6.object({
18572
+ provider: z6.enum(["github-actions", "gitlab-ci", "circleci", "jenkins", "travis", "azure-pipelines"]).optional(),
18573
+ hasCI: z6.boolean().default(false),
18574
+ hasCD: z6.boolean().default(false),
18575
+ configFile: z6.string().optional()
18576
+ });
18577
+ var EnvConfig = z6.object({
18578
+ hasEnvFile: z6.boolean().default(false),
18579
+ hasEnvExample: z6.boolean().default(false),
18580
+ envVariables: z6.array(z6.string()).optional()
18581
+ });
18582
+ var DockerConfig = z6.object({
18583
+ hasDockerfile: z6.boolean().default(false),
18584
+ hasCompose: z6.boolean().default(false),
18585
+ baseImage: z6.string().optional()
18586
+ });
18587
+ var PrimerAnalysis = z6.object({
18588
+ project: z6.object({
18589
+ name: z6.string(),
18590
+ description: z6.string().optional(),
18591
+ version: z6.string().optional(),
18592
+ type: z6.string().optional(),
18593
+ license: z6.string().optional(),
18594
+ repository: z6.string().optional()
18595
+ }),
18596
+ languages: z6.array(Detection).default([]),
18597
+ packageManagers: z6.array(PackageManager).default([]),
18598
+ stack: ProjectStack,
18599
+ patterns: ProjectPatterns.optional(),
18600
+ structure: ProjectStructure.optional(),
18601
+ conventions: CodeConvention.optional(),
18602
+ ci: CIConfig.optional(),
18603
+ env: EnvConfig.optional(),
18604
+ docker: DockerConfig.optional(),
18605
+ buildCommands: z6.object({
18606
+ install: z6.string().optional(),
18607
+ build: z6.string().optional(),
18608
+ test: z6.string().optional(),
18609
+ lint: z6.string().optional(),
18610
+ format: z6.string().optional(),
18611
+ dev: z6.string().optional(),
18612
+ start: z6.string().optional()
18613
+ }).optional(),
18614
+ importantFiles: z6.array(z6.string()).default([]),
18615
+ codebaseSize: z6.object({
18616
+ files: z6.number().optional(),
18617
+ lines: z6.number().optional(),
18618
+ directories: z6.number().optional()
18619
+ }).optional()
18620
+ });
18621
+ var AGENT_INSTRUCTION_TEMPLATES = {
18622
+ "claude-code": {
18623
+ agent: "claude-code",
18624
+ filename: "CLAUDE.md",
18625
+ format: "markdown",
18626
+ sectionOrder: ["overview", "stack", "commands", "conventions", "structure", "guidelines"]
18627
+ },
18628
+ "cursor": {
18629
+ agent: "cursor",
18630
+ filename: ".cursorrules",
18631
+ format: "markdown",
18632
+ sectionOrder: ["overview", "stack", "conventions", "guidelines"]
18633
+ },
18634
+ "github-copilot": {
18635
+ agent: "github-copilot",
18636
+ filename: ".github/copilot-instructions.md",
18637
+ format: "markdown",
18638
+ sectionOrder: ["overview", "stack", "commands", "conventions", "structure", "guidelines"]
18639
+ },
18640
+ "codex": {
18641
+ agent: "codex",
18642
+ filename: "AGENTS.md",
18643
+ format: "markdown",
18644
+ sectionOrder: ["overview", "stack", "commands", "conventions", "structure", "guidelines"]
18645
+ },
18646
+ "gemini-cli": {
18647
+ agent: "gemini-cli",
18648
+ filename: "GEMINI.md",
18649
+ format: "markdown",
18650
+ sectionOrder: ["overview", "stack", "commands", "conventions", "structure", "guidelines"]
18651
+ },
18652
+ "windsurf": {
18653
+ agent: "windsurf",
18654
+ filename: ".windsurfrules",
18655
+ format: "markdown",
18656
+ sectionOrder: ["overview", "stack", "conventions", "guidelines"]
18657
+ },
18658
+ "opencode": {
18659
+ agent: "opencode",
18660
+ filename: "AGENTS.md",
18661
+ format: "markdown",
18662
+ sectionOrder: ["overview", "stack", "commands", "conventions", "structure", "guidelines"]
18663
+ },
18664
+ "trae": {
18665
+ agent: "trae",
18666
+ filename: ".trae/rules/project_rules.md",
18667
+ format: "markdown",
18668
+ sectionOrder: ["overview", "stack", "commands", "conventions", "guidelines"]
18669
+ }
18670
+ };
18671
+
18672
+ // src/primer/analyzer.ts
18673
+ import { existsSync as existsSync35, readFileSync as readFileSync27, readdirSync as readdirSync10 } from "fs";
18674
+ import { join as join36, basename as basename13, relative as relative4, sep as sep2 } from "path";
18675
+ var PACKAGE_MANAGER_FILES = {
18676
+ "package-lock.json": "npm",
18677
+ "pnpm-lock.yaml": "pnpm",
18678
+ "yarn.lock": "yarn",
18679
+ "bun.lockb": "bun",
18680
+ "requirements.txt": "pip",
18681
+ "Pipfile.lock": "pip",
18682
+ "poetry.lock": "poetry",
18683
+ "uv.lock": "uv",
18684
+ "Cargo.lock": "cargo",
18685
+ "go.sum": "go",
18686
+ "pom.xml": "maven",
18687
+ "build.gradle": "gradle",
18688
+ "build.gradle.kts": "gradle",
18689
+ "composer.lock": "composer",
18690
+ "Gemfile.lock": "bundler",
18691
+ "Podfile.lock": "cocoapods",
18692
+ "Package.resolved": "swift-package-manager",
18693
+ "packages.lock.json": "nuget"
18694
+ };
18695
+ var CI_CONFIG_FILES = {
18696
+ ".github/workflows": "github-actions",
18697
+ ".gitlab-ci.yml": "gitlab-ci",
18698
+ ".circleci/config.yml": "circleci",
18699
+ "Jenkinsfile": "jenkins",
18700
+ ".travis.yml": "travis",
18701
+ "azure-pipelines.yml": "azure-pipelines"
18702
+ };
18703
+ var IMPORTANT_CONFIG_FILES = [
18704
+ "package.json",
18705
+ "tsconfig.json",
18706
+ "pyproject.toml",
18707
+ "Cargo.toml",
18708
+ "go.mod",
18709
+ ".eslintrc.js",
18710
+ ".eslintrc.json",
18711
+ "eslint.config.js",
18712
+ ".prettierrc",
18713
+ "prettier.config.js",
18714
+ "biome.json",
18715
+ "tailwind.config.js",
18716
+ "tailwind.config.ts",
18717
+ "vite.config.ts",
18718
+ "next.config.js",
18719
+ "next.config.mjs",
18720
+ "webpack.config.js",
18721
+ "rollup.config.js",
18722
+ "turbo.json",
18723
+ "nx.json",
18724
+ "jest.config.js",
18725
+ "vitest.config.ts",
18726
+ "playwright.config.ts",
18727
+ ".env.example",
18728
+ "docker-compose.yml",
18729
+ "Dockerfile"
18730
+ ];
18731
+ var PrimerAnalyzer = class {
18732
+ projectPath;
18733
+ packageJson = null;
18734
+ files = /* @__PURE__ */ new Set();
18735
+ constructor(projectPath) {
18736
+ this.projectPath = projectPath;
18737
+ }
18738
+ analyze() {
18739
+ this.loadPackageJson();
18740
+ this.scanFiles();
18741
+ const detector = new ProjectDetector(this.projectPath);
18742
+ const stack = detector.analyze();
18743
+ const patterns = detector.detectPatterns();
18744
+ const analysis = {
18745
+ project: this.getProjectInfo(),
18746
+ languages: this.detectLanguages(),
18747
+ packageManagers: this.detectPackageManagers(),
18748
+ stack,
18749
+ patterns,
18750
+ structure: this.detectProjectStructure(),
18751
+ conventions: this.detectCodeConventions(),
18752
+ ci: this.detectCIConfig(),
18753
+ env: this.detectEnvConfig(),
18754
+ docker: this.detectDockerConfig(),
18755
+ buildCommands: this.extractBuildCommands(),
18756
+ importantFiles: this.findImportantFiles(),
18757
+ codebaseSize: this.estimateCodebaseSize()
18758
+ };
18759
+ return analysis;
18760
+ }
18761
+ loadPackageJson() {
18762
+ const packageJsonPath = join36(this.projectPath, "package.json");
18763
+ if (existsSync35(packageJsonPath)) {
18764
+ try {
18765
+ const content = readFileSync27(packageJsonPath, "utf-8");
18766
+ this.packageJson = JSON.parse(content);
18767
+ } catch {
18768
+ this.packageJson = null;
18769
+ }
18770
+ }
18771
+ }
18772
+ scanFiles(maxDepth = 3) {
18773
+ const scan = (dir, depth) => {
18774
+ if (depth > maxDepth) return;
18775
+ try {
18776
+ const entries = readdirSync10(dir, { withFileTypes: true });
18777
+ for (const entry of entries) {
18778
+ const fullPath = join36(dir, entry.name);
18779
+ const relativePath = relative4(this.projectPath, fullPath);
18780
+ if (entry.name.startsWith(".") && entry.name !== ".github" && entry.name !== ".env.example") {
18781
+ if (!entry.isDirectory()) {
18782
+ this.files.add(relativePath);
18783
+ }
18784
+ continue;
18785
+ }
18786
+ if (entry.name === "node_modules" || entry.name === "dist" || entry.name === "build" || entry.name === ".git") {
18787
+ continue;
18788
+ }
18789
+ this.files.add(relativePath);
18790
+ if (entry.isDirectory()) {
18791
+ scan(fullPath, depth + 1);
18792
+ }
18793
+ }
18794
+ } catch {
18795
+ }
18796
+ };
18797
+ scan(this.projectPath, 0);
18798
+ }
18799
+ getProjectInfo() {
18800
+ const info = {
18801
+ name: basename13(this.projectPath)
18802
+ };
18803
+ if (this.packageJson) {
18804
+ if (typeof this.packageJson.name === "string") {
18805
+ info.name = this.packageJson.name;
18806
+ }
18807
+ if (typeof this.packageJson.description === "string") {
18808
+ info.description = this.packageJson.description;
18809
+ }
18810
+ if (typeof this.packageJson.version === "string") {
18811
+ info.version = this.packageJson.version;
18812
+ }
18813
+ if (typeof this.packageJson.license === "string") {
18814
+ info.license = this.packageJson.license;
18815
+ }
18816
+ const repo = this.packageJson.repository;
18817
+ if (typeof repo === "string") {
18818
+ info.repository = repo;
18819
+ } else if (repo && typeof repo === "object" && "url" in repo) {
18820
+ info.repository = String(repo.url);
18821
+ }
18822
+ }
18823
+ const pyprojectPath = join36(this.projectPath, "pyproject.toml");
18824
+ if (!this.packageJson && existsSync35(pyprojectPath)) {
18825
+ try {
18826
+ const content = readFileSync27(pyprojectPath, "utf-8");
18827
+ const nameMatch = content.match(/name\s*=\s*["']([^"']+)["']/);
18828
+ const versionMatch = content.match(/version\s*=\s*["']([^"']+)["']/);
18829
+ const descMatch = content.match(/description\s*=\s*["']([^"']+)["']/);
18830
+ if (nameMatch) info.name = nameMatch[1];
18831
+ if (versionMatch) info.version = versionMatch[1];
18832
+ if (descMatch) info.description = descMatch[1];
18833
+ } catch {
18834
+ }
18835
+ }
18836
+ const cargoPath = join36(this.projectPath, "Cargo.toml");
18837
+ if (!this.packageJson && existsSync35(cargoPath)) {
18838
+ try {
18839
+ const content = readFileSync27(cargoPath, "utf-8");
18840
+ const nameMatch = content.match(/name\s*=\s*["']([^"']+)["']/);
18841
+ const versionMatch = content.match(/version\s*=\s*["']([^"']+)["']/);
18842
+ const descMatch = content.match(/description\s*=\s*["']([^"']+)["']/);
18843
+ if (nameMatch) info.name = nameMatch[1];
18844
+ if (versionMatch) info.version = versionMatch[1];
18845
+ if (descMatch) info.description = descMatch[1];
18846
+ } catch {
18847
+ }
18848
+ }
18849
+ const detector = new ProjectDetector(this.projectPath);
18850
+ info.type = detector.detectProjectType();
18851
+ return info;
18852
+ }
18853
+ detectLanguages() {
18854
+ const languages = [];
18855
+ if (this.hasFile("tsconfig.json")) {
18856
+ const version = this.getDepVersion("typescript");
18857
+ languages.push({
18858
+ name: "typescript",
18859
+ version,
18860
+ confidence: 100,
18861
+ source: "tsconfig.json"
18862
+ });
18863
+ }
18864
+ if (this.packageJson && !this.hasFile("tsconfig.json")) {
18865
+ languages.push({
18866
+ name: "javascript",
18867
+ confidence: 90,
18868
+ source: "package.json"
18869
+ });
18870
+ }
18871
+ if (this.hasFile("pyproject.toml") || this.hasFile("requirements.txt") || this.hasFile("setup.py")) {
18872
+ const source = this.hasFile("pyproject.toml") ? "pyproject.toml" : this.hasFile("requirements.txt") ? "requirements.txt" : "setup.py";
18873
+ languages.push({
18874
+ name: "python",
18875
+ confidence: 100,
18876
+ source
18877
+ });
18878
+ }
18879
+ if (this.hasFile("go.mod")) {
18880
+ languages.push({
18881
+ name: "go",
18882
+ confidence: 100,
18883
+ source: "go.mod"
18884
+ });
18885
+ }
18886
+ if (this.hasFile("Cargo.toml")) {
18887
+ languages.push({
18888
+ name: "rust",
18889
+ confidence: 100,
18890
+ source: "Cargo.toml"
18891
+ });
18892
+ }
18893
+ if (this.hasFile("pom.xml") || this.hasFile("build.gradle") || this.hasFile("build.gradle.kts")) {
18894
+ languages.push({
18895
+ name: "java",
18896
+ confidence: 100,
18897
+ source: "pom.xml"
18898
+ });
18899
+ }
18900
+ if (this.hasFile("Package.swift")) {
18901
+ languages.push({
18902
+ name: "swift",
18903
+ confidence: 100,
18904
+ source: "Package.swift"
18905
+ });
18906
+ }
18907
+ if (this.hasFile("Gemfile")) {
18908
+ languages.push({
18909
+ name: "ruby",
18910
+ confidence: 100,
18911
+ source: "Gemfile"
18912
+ });
18913
+ }
18914
+ if (this.hasFile("composer.json")) {
18915
+ languages.push({
18916
+ name: "php",
18917
+ confidence: 100,
18918
+ source: "composer.json"
18919
+ });
18920
+ }
18921
+ return languages;
18922
+ }
18923
+ detectPackageManagers() {
18924
+ const managers = /* @__PURE__ */ new Set();
18925
+ for (const [file, manager] of Object.entries(PACKAGE_MANAGER_FILES)) {
18926
+ if (this.hasFile(file)) {
18927
+ managers.add(manager);
18928
+ }
18929
+ }
18930
+ if (this.packageJson) {
18931
+ const packageManager = this.packageJson.packageManager;
18932
+ if (typeof packageManager === "string") {
18933
+ const match = packageManager.match(/^(npm|pnpm|yarn|bun)@/);
18934
+ if (match && ["npm", "pnpm", "yarn", "bun"].includes(match[1])) {
18935
+ managers.add(match[1]);
18936
+ }
18937
+ }
18938
+ }
18939
+ return Array.from(managers);
18940
+ }
18941
+ detectProjectStructure() {
18942
+ const structure = {
18943
+ hasWorkspaces: false
18944
+ };
18945
+ if (this.hasFile("packages") || this.hasFile("apps")) {
18946
+ structure.type = "monorepo";
18947
+ } else if (this.hasFile("src")) {
18948
+ structure.type = "src-based";
18949
+ structure.srcDir = "src";
18950
+ } else if (this.hasFile("lib")) {
18951
+ structure.type = "src-based";
18952
+ structure.srcDir = "lib";
18953
+ } else {
18954
+ structure.type = "flat";
18955
+ }
18956
+ if (this.hasFile("tests") || this.hasFile("test") || this.hasFile("__tests__")) {
18957
+ structure.testDir = this.hasFile("tests") ? "tests" : this.hasFile("test") ? "test" : "__tests__";
18958
+ }
18959
+ if (this.hasFile("docs") || this.hasFile("documentation")) {
18960
+ structure.docsDir = this.hasFile("docs") ? "docs" : "documentation";
18961
+ }
18962
+ if (this.packageJson) {
18963
+ const workspaces = this.packageJson.workspaces;
18964
+ if (Array.isArray(workspaces)) {
18965
+ structure.hasWorkspaces = true;
18966
+ structure.workspaces = workspaces.filter((w) => typeof w === "string");
18967
+ structure.type = "monorepo";
18968
+ } else if (workspaces && typeof workspaces === "object" && "packages" in workspaces) {
18969
+ structure.hasWorkspaces = true;
18970
+ structure.workspaces = workspaces.packages || [];
18971
+ structure.type = "monorepo";
18972
+ }
18973
+ }
18974
+ if (this.hasFile("pnpm-workspace.yaml")) {
18975
+ structure.hasWorkspaces = true;
18976
+ structure.type = "monorepo";
18977
+ }
18978
+ if (this.hasFile("turbo.json") || this.hasFile("nx.json")) {
18979
+ structure.type = "monorepo";
18980
+ }
18981
+ return structure;
18982
+ }
18983
+ detectCodeConventions() {
18984
+ const conventions = {};
18985
+ const prettierConfig = this.readConfigFile([
18986
+ ".prettierrc",
18987
+ ".prettierrc.json",
18988
+ "prettier.config.js"
18989
+ ]);
18990
+ const biomeConfig = this.readConfigFile(["biome.json"]);
18991
+ if (prettierConfig) {
18992
+ try {
18993
+ const config = typeof prettierConfig === "string" ? JSON.parse(prettierConfig) : prettierConfig;
18994
+ if ("semi" in config) conventions.semicolons = config.semi;
18995
+ if ("singleQuote" in config) conventions.quotes = config.singleQuote ? "single" : "double";
18996
+ if ("tabWidth" in config) {
18997
+ conventions.indentation = config.useTabs ? "tabs" : `spaces-${config.tabWidth}`;
18998
+ }
18999
+ if ("trailingComma" in config) conventions.trailingCommas = config.trailingComma;
19000
+ if ("printWidth" in config) conventions.maxLineLength = config.printWidth;
19001
+ } catch {
19002
+ }
19003
+ }
19004
+ if (biomeConfig) {
19005
+ try {
19006
+ const config = typeof biomeConfig === "string" ? JSON.parse(biomeConfig) : biomeConfig;
19007
+ const formatter = config.formatter || {};
19008
+ const js = config.javascript?.formatter || {};
19009
+ if (formatter.indentStyle) conventions.indentation = formatter.indentStyle === "tab" ? "tabs" : "spaces-2";
19010
+ if (formatter.lineWidth) conventions.maxLineLength = formatter.lineWidth;
19011
+ if (js.quoteStyle) conventions.quotes = js.quoteStyle;
19012
+ if (js.semicolons) conventions.semicolons = js.semicolons !== "asNeeded";
19013
+ if (js.trailingCommas) conventions.trailingCommas = js.trailingCommas;
19014
+ } catch {
19015
+ }
19016
+ }
19017
+ if (this.hasFile("tsconfig.json")) {
19018
+ try {
19019
+ const tsconfigPath = join36(this.projectPath, "tsconfig.json");
19020
+ const content = readFileSync27(tsconfigPath, "utf-8");
19021
+ const tsconfig = JSON.parse(content.replace(/\/\/.*$/gm, "").replace(/,\s*}/g, "}"));
19022
+ const paths = tsconfig.compilerOptions?.paths;
19023
+ if (paths && Object.keys(paths).some((k) => k.startsWith("@"))) {
19024
+ conventions.namingStyle = "camelCase";
19025
+ }
19026
+ } catch {
19027
+ }
19028
+ }
19029
+ return conventions;
19030
+ }
19031
+ detectCIConfig() {
19032
+ const ci = {
19033
+ hasCI: false,
19034
+ hasCD: false
19035
+ };
19036
+ for (const [file, provider] of Object.entries(CI_CONFIG_FILES)) {
19037
+ if (this.hasFile(file)) {
19038
+ ci.hasCI = true;
19039
+ ci.provider = provider;
19040
+ ci.configFile = file;
19041
+ break;
19042
+ }
19043
+ }
19044
+ if (this.hasFile(".github/workflows")) {
19045
+ ci.hasCI = true;
19046
+ ci.provider = "github-actions";
19047
+ ci.configFile = ".github/workflows";
19048
+ try {
19049
+ const workflowsDir = join36(this.projectPath, ".github/workflows");
19050
+ const workflows = readdirSync10(workflowsDir);
19051
+ const deployWorkflows = workflows.filter(
19052
+ (f) => f.includes("deploy") || f.includes("release") || f.includes("publish")
19053
+ );
19054
+ if (deployWorkflows.length > 0) {
19055
+ ci.hasCD = true;
19056
+ }
19057
+ } catch {
19058
+ }
19059
+ }
19060
+ return ci;
19061
+ }
19062
+ detectEnvConfig() {
19063
+ const env = {
19064
+ hasEnvFile: false,
19065
+ hasEnvExample: false
19066
+ };
19067
+ env.hasEnvFile = this.hasFile(".env");
19068
+ env.hasEnvExample = this.hasFile(".env.example") || this.hasFile(".env.template") || this.hasFile(".env.sample");
19069
+ if (env.hasEnvExample) {
19070
+ const envExamplePath = join36(
19071
+ this.projectPath,
19072
+ this.hasFile(".env.example") ? ".env.example" : this.hasFile(".env.template") ? ".env.template" : ".env.sample"
19073
+ );
19074
+ try {
19075
+ const content = readFileSync27(envExamplePath, "utf-8");
19076
+ const variables = content.split("\n").filter((line) => line.trim() && !line.startsWith("#")).map((line) => line.split("=")[0].trim()).filter((v) => v);
19077
+ env.envVariables = variables;
19078
+ } catch {
19079
+ }
19080
+ }
19081
+ return env;
19082
+ }
19083
+ detectDockerConfig() {
19084
+ const docker = {
19085
+ hasDockerfile: false,
19086
+ hasCompose: false
19087
+ };
19088
+ docker.hasDockerfile = this.hasFile("Dockerfile");
19089
+ docker.hasCompose = this.hasFile("docker-compose.yml") || this.hasFile("docker-compose.yaml") || this.hasFile("compose.yml");
19090
+ if (docker.hasDockerfile) {
19091
+ try {
19092
+ const dockerfilePath = join36(this.projectPath, "Dockerfile");
19093
+ const content = readFileSync27(dockerfilePath, "utf-8");
19094
+ const fromMatch = content.match(/^FROM\s+(\S+)/m);
19095
+ if (fromMatch) {
19096
+ docker.baseImage = fromMatch[1];
19097
+ }
19098
+ } catch {
19099
+ }
19100
+ }
19101
+ return docker;
19102
+ }
19103
+ extractBuildCommands() {
19104
+ const commands = {};
19105
+ if (this.packageJson && this.packageJson.scripts) {
19106
+ const scripts = this.packageJson.scripts;
19107
+ if (scripts.build) commands.build = this.getRunCommand("build");
19108
+ if (scripts.test) commands.test = this.getRunCommand("test");
19109
+ if (scripts.lint) commands.lint = this.getRunCommand("lint");
19110
+ if (scripts.format) commands.format = this.getRunCommand("format");
19111
+ if (scripts.dev) commands.dev = this.getRunCommand("dev");
19112
+ if (scripts.start) commands.start = this.getRunCommand("start");
19113
+ }
19114
+ const packageManagers = this.detectPackageManagers();
19115
+ if (!commands.install) {
19116
+ if (packageManagers.includes("pnpm")) {
19117
+ commands.install = "pnpm install";
19118
+ } else if (packageManagers.includes("yarn")) {
19119
+ commands.install = "yarn install";
19120
+ } else if (packageManagers.includes("bun")) {
19121
+ commands.install = "bun install";
19122
+ } else if (packageManagers.includes("npm")) {
19123
+ commands.install = "npm install";
19124
+ } else if (packageManagers.includes("pip") || packageManagers.includes("poetry") || packageManagers.includes("uv")) {
19125
+ if (packageManagers.includes("poetry")) {
19126
+ commands.install = "poetry install";
19127
+ } else if (packageManagers.includes("uv")) {
19128
+ commands.install = "uv sync";
19129
+ } else {
19130
+ commands.install = "pip install -r requirements.txt";
19131
+ }
19132
+ } else if (packageManagers.includes("cargo")) {
19133
+ commands.install = "cargo build";
19134
+ } else if (packageManagers.includes("go")) {
19135
+ commands.install = "go mod download";
19136
+ }
19137
+ }
19138
+ return commands;
19139
+ }
19140
+ findImportantFiles() {
19141
+ const important = [];
19142
+ for (const file of IMPORTANT_CONFIG_FILES) {
19143
+ if (this.hasFile(file)) {
19144
+ important.push(file);
19145
+ }
19146
+ }
19147
+ if (this.hasFile("README.md")) {
19148
+ important.push("README.md");
19149
+ }
19150
+ if (this.hasFile("CONTRIBUTING.md")) {
19151
+ important.push("CONTRIBUTING.md");
19152
+ }
19153
+ if (this.hasFile("LICENSE") || this.hasFile("LICENSE.md")) {
19154
+ important.push(this.hasFile("LICENSE") ? "LICENSE" : "LICENSE.md");
19155
+ }
19156
+ return important;
19157
+ }
19158
+ estimateCodebaseSize() {
19159
+ let files = 0;
19160
+ let directories = 0;
19161
+ for (const file of this.files) {
19162
+ if (file.includes(sep2)) {
19163
+ directories++;
19164
+ }
19165
+ files++;
19166
+ }
19167
+ return {
19168
+ files,
19169
+ directories: Math.floor(directories / 3)
19170
+ };
19171
+ }
19172
+ hasFile(name) {
19173
+ if (name.includes("*")) {
19174
+ const regex = new RegExp(
19175
+ name.replace(/[.+?^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*")
19176
+ );
19177
+ for (const file of this.files) {
19178
+ if (regex.test(file)) return true;
19179
+ }
19180
+ return false;
19181
+ }
19182
+ return this.files.has(name) || existsSync35(join36(this.projectPath, name));
19183
+ }
19184
+ getDepVersion(dep) {
19185
+ if (!this.packageJson) return void 0;
19186
+ const deps = this.packageJson.dependencies;
19187
+ const devDeps = this.packageJson.devDependencies;
19188
+ const version = deps?.[dep] || devDeps?.[dep];
19189
+ return version?.replace(/^[\^~>=<]+/, "");
19190
+ }
19191
+ getRunCommand(script) {
19192
+ const packageManagers = this.detectPackageManagers();
19193
+ if (packageManagers.includes("pnpm")) {
19194
+ return `pnpm ${script}`;
19195
+ } else if (packageManagers.includes("yarn")) {
19196
+ return `yarn ${script}`;
19197
+ } else if (packageManagers.includes("bun")) {
19198
+ return `bun run ${script}`;
19199
+ }
19200
+ return `npm run ${script}`;
19201
+ }
19202
+ readConfigFile(files) {
19203
+ for (const file of files) {
19204
+ const filePath = join36(this.projectPath, file);
19205
+ if (existsSync35(filePath)) {
19206
+ try {
19207
+ const content = readFileSync27(filePath, "utf-8");
19208
+ if (file.endsWith(".json")) {
19209
+ return JSON.parse(content);
19210
+ }
19211
+ return content;
19212
+ } catch {
19213
+ }
19214
+ }
19215
+ }
19216
+ return null;
19217
+ }
19218
+ };
19219
+ function analyzePrimer(projectPath) {
19220
+ const analyzer = new PrimerAnalyzer(projectPath);
19221
+ return analyzer.analyze();
19222
+ }
19223
+
19224
+ // src/primer/generator.ts
19225
+ import { existsSync as existsSync36, mkdirSync as mkdirSync19, writeFileSync as writeFileSync19 } from "fs";
19226
+ import { join as join37, dirname as dirname13 } from "path";
19227
+ var ALL_AGENTS = Object.keys(AGENT_CONFIG);
19228
+ var markdownRenderer = {
19229
+ h1: (text) => `# ${text}`,
19230
+ h2: (text) => `## ${text}`,
19231
+ h3: (text) => `### ${text}`,
19232
+ bold: (text) => `**${text}**`,
19233
+ code: (text) => `\`${text}\``,
19234
+ codeBlock: (code, lang = "") => `\`\`\`${lang}
19235
+ ${code}
19236
+ \`\`\``,
19237
+ list: (items) => items.map((item) => `- ${item}`).join("\n"),
19238
+ keyValue: (key, value) => `**${key}:** ${value}`,
19239
+ paragraph: (text) => text,
19240
+ separator: () => "",
19241
+ wrap: (content) => content
19242
+ };
19243
+ var mdcRenderer = {
19244
+ h1: (text) => `# ${text}`,
19245
+ h2: (text) => `## ${text}`,
19246
+ h3: (text) => `### ${text}`,
19247
+ bold: (text) => `**${text}**`,
19248
+ code: (text) => `\`${text}\``,
19249
+ codeBlock: (code, lang = "") => `\`\`\`${lang}
19250
+ ${code}
19251
+ \`\`\``,
19252
+ list: (items) => items.map((item) => `- ${item}`).join("\n"),
19253
+ keyValue: (key, value) => `**${key}:** ${value}`,
19254
+ paragraph: (text) => text,
19255
+ separator: () => "",
19256
+ wrap: (content, metadata) => {
19257
+ if (metadata && Object.keys(metadata).length > 0) {
19258
+ const yaml = Object.entries(metadata).map(([k, v]) => `${k}: ${JSON.stringify(v)}`).join("\n");
19259
+ return `---
19260
+ ${yaml}
19261
+ ---
19262
+
19263
+ ${content}`;
19264
+ }
19265
+ return content;
19266
+ }
19267
+ };
19268
+ var jsonRenderer = {
19269
+ h1: (text) => text,
19270
+ h2: (text) => text,
19271
+ h3: (text) => text,
19272
+ bold: (text) => text,
19273
+ code: (text) => text,
19274
+ codeBlock: (code) => code,
19275
+ list: (items) => items.join(", "),
19276
+ keyValue: (key, value) => `${key}: ${value}`,
19277
+ paragraph: (text) => text,
19278
+ separator: () => "",
19279
+ wrap: (content, metadata) => {
19280
+ try {
19281
+ const data = { ...metadata, content };
19282
+ return JSON.stringify(data, null, 2);
19283
+ } catch {
19284
+ return content;
19285
+ }
19286
+ }
19287
+ };
19288
+ var xmlRenderer = {
19289
+ h1: (text) => `<h1>${escapeXml2(text)}</h1>`,
19290
+ h2: (text) => `<h2>${escapeXml2(text)}</h2>`,
19291
+ h3: (text) => `<h3>${escapeXml2(text)}</h3>`,
19292
+ bold: (text) => `<strong>${escapeXml2(text)}</strong>`,
19293
+ code: (text) => `<code>${escapeXml2(text)}</code>`,
19294
+ codeBlock: (code, lang = "") => `<pre${lang ? ` lang="${lang}"` : ""}><code>${escapeXml2(code)}</code></pre>`,
19295
+ list: (items) => `<ul>
19296
+ ${items.map((item) => ` <li>${escapeXml2(item)}</li>`).join("\n")}
19297
+ </ul>`,
19298
+ keyValue: (key, value) => `<dt>${escapeXml2(key)}</dt><dd>${escapeXml2(value)}</dd>`,
19299
+ paragraph: (text) => `<p>${escapeXml2(text)}</p>`,
19300
+ separator: () => "",
19301
+ wrap: (content, metadata) => {
19302
+ const attrs = metadata ? Object.entries(metadata).map(([k, v]) => `${k}="${escapeXml2(String(v))}"`).join(" ") : "";
19303
+ return `<?xml version="1.0" encoding="UTF-8"?>
19304
+ <instructions${attrs ? " " + attrs : ""}>
19305
+ ${content}
19306
+ </instructions>`;
19307
+ }
19308
+ };
19309
+ function escapeXml2(text) {
19310
+ return text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&apos;");
19311
+ }
19312
+ function getRenderer(format) {
19313
+ switch (format) {
19314
+ case "mdc":
19315
+ return mdcRenderer;
19316
+ case "json":
19317
+ return jsonRenderer;
19318
+ case "xml":
19319
+ return xmlRenderer;
19320
+ default:
19321
+ return markdownRenderer;
19322
+ }
19323
+ }
19324
+ var PrimerGenerator = class {
19325
+ projectPath;
19326
+ options;
19327
+ analysis = null;
19328
+ constructor(projectPath, options = {}) {
19329
+ this.projectPath = projectPath;
19330
+ this.options = options;
19331
+ }
19332
+ generate() {
19333
+ const warnings = [];
19334
+ const errors = [];
19335
+ const generated = [];
19336
+ const seenPaths = /* @__PURE__ */ new Map();
19337
+ this.analysis = analyzePrimer(this.projectPath);
19338
+ if (this.options.analyzeOnly) {
19339
+ return {
19340
+ success: true,
19341
+ analysis: this.analysis,
19342
+ generated: [],
19343
+ warnings,
19344
+ errors
19345
+ };
19346
+ }
19347
+ const targetAgents = this.getTargetAgents();
19348
+ for (const agent of targetAgents) {
19349
+ try {
19350
+ const instruction = this.generateForAgent(agent);
19351
+ if (instruction) {
19352
+ const existingAgent = seenPaths.get(instruction.filepath);
19353
+ if (existingAgent) {
19354
+ warnings.push(
19355
+ `Skipping ${agent}: output path "${instruction.filename}" already used by ${existingAgent}`
19356
+ );
19357
+ continue;
19358
+ }
19359
+ seenPaths.set(instruction.filepath, agent);
19360
+ if (!this.options.dryRun) {
19361
+ this.writeInstruction(instruction);
19362
+ }
19363
+ generated.push(instruction);
19364
+ }
19365
+ } catch (error) {
19366
+ const message = error instanceof Error ? error.message : String(error);
19367
+ errors.push(`Failed to generate for ${agent}: ${message}`);
19368
+ }
19369
+ }
19370
+ return {
19371
+ success: errors.length === 0,
19372
+ analysis: this.analysis,
19373
+ generated,
19374
+ warnings,
19375
+ errors
19376
+ };
19377
+ }
19378
+ getTargetAgents() {
19379
+ if (this.options.allAgents) {
19380
+ return ALL_AGENTS;
19381
+ }
19382
+ if (this.options.agents && this.options.agents.length > 0) {
19383
+ return this.options.agents;
19384
+ }
19385
+ return this.detectInstalledAgents();
19386
+ }
19387
+ detectInstalledAgents() {
19388
+ const detected = [];
19389
+ for (const [agent, config] of Object.entries(AGENT_CONFIG)) {
19390
+ const configPath = join37(this.projectPath, config.configFile);
19391
+ const skillsPath = join37(this.projectPath, config.skillsDir);
19392
+ if (existsSync36(configPath) || existsSync36(skillsPath)) {
19393
+ detected.push(agent);
19394
+ }
19395
+ if (config.altSkillsDirs) {
19396
+ for (const altDir of config.altSkillsDirs) {
19397
+ if (existsSync36(join37(this.projectPath, altDir))) {
19398
+ if (!detected.includes(agent)) {
19399
+ detected.push(agent);
19400
+ }
19401
+ break;
19402
+ }
19403
+ }
19404
+ }
19405
+ }
19406
+ if (detected.length === 0) {
19407
+ detected.push("claude-code", "cursor", "github-copilot");
19408
+ }
19409
+ return detected;
19410
+ }
19411
+ generateForAgent(agent) {
19412
+ if (!this.analysis) return null;
19413
+ const config = AGENT_CONFIG[agent];
19414
+ const template = AGENT_INSTRUCTION_TEMPLATES[agent] || this.getDefaultTemplate(agent, config);
19415
+ const content = this.generateContent(template);
19416
+ const outputDir = this.options.outputDir || this.projectPath;
19417
+ const filepath = join37(outputDir, template.filename);
19418
+ return {
19419
+ agent,
19420
+ filename: template.filename,
19421
+ filepath,
19422
+ content,
19423
+ format: template.format
19424
+ };
19425
+ }
19426
+ getDefaultTemplate(agent, config) {
19427
+ const formatMap = {
19428
+ ".md": "markdown",
19429
+ ".json": "json",
19430
+ ".mdc": "mdc",
19431
+ ".xml": "xml"
19432
+ };
19433
+ const ext = config.configFile.includes(".") ? "." + config.configFile.split(".").pop() : ".md";
19434
+ const format = formatMap[ext] || "markdown";
19435
+ return {
19436
+ agent,
19437
+ filename: config.configFile,
19438
+ format,
19439
+ sectionOrder: ["overview", "stack", "commands", "conventions", "structure", "guidelines"]
19440
+ };
19441
+ }
19442
+ generateContent(template) {
19443
+ if (!this.analysis) return "";
19444
+ const format = template.format;
19445
+ const renderer = getRenderer(format);
19446
+ if (format === "json") {
19447
+ return this.generateJsonContent(template);
19448
+ }
19449
+ const sections = [];
19450
+ for (const section of template.sectionOrder) {
19451
+ const content = this.generateSection(section, template, renderer);
19452
+ if (content) {
19453
+ sections.push(content);
19454
+ }
19455
+ }
19456
+ let result = sections.join("\n\n");
19457
+ if (template.header) {
19458
+ result = template.header + "\n\n" + result;
19459
+ }
19460
+ if (template.footer) {
19461
+ result = result + "\n\n" + template.footer;
19462
+ }
19463
+ if (this.options.customInstructions) {
19464
+ result += "\n\n" + renderer.h2("Custom Instructions") + "\n\n" + this.options.customInstructions;
19465
+ }
19466
+ const metadata = format === "mdc" ? {
19467
+ title: this.analysis.project.name,
19468
+ type: this.analysis.project.type,
19469
+ generated: (/* @__PURE__ */ new Date()).toISOString()
19470
+ } : void 0;
19471
+ return renderer.wrap(result, metadata);
19472
+ }
19473
+ generateJsonContent(template) {
19474
+ if (!this.analysis) return "{}";
19475
+ const data = {
19476
+ project: this.analysis.project,
19477
+ languages: this.analysis.languages.map((l) => l.name),
19478
+ packageManagers: this.analysis.packageManagers,
19479
+ stack: {
19480
+ frameworks: this.analysis.stack.frameworks.map((f) => ({ name: f.name, version: f.version })),
19481
+ libraries: this.analysis.stack.libraries.map((l) => ({ name: l.name, version: l.version })),
19482
+ styling: this.analysis.stack.styling.map((s) => s.name),
19483
+ testing: this.analysis.stack.testing.map((t) => t.name),
19484
+ databases: this.analysis.stack.databases.map((d) => d.name)
19485
+ },
19486
+ commands: this.analysis.buildCommands,
19487
+ conventions: this.analysis.conventions,
19488
+ structure: this.analysis.structure,
19489
+ importantFiles: this.analysis.importantFiles,
19490
+ generated: {
19491
+ agent: template.agent,
19492
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
19493
+ }
19494
+ };
19495
+ if (this.options.customInstructions) {
19496
+ data.customInstructions = this.options.customInstructions;
19497
+ }
19498
+ return JSON.stringify(data, null, 2);
19499
+ }
19500
+ generateSection(section, template, renderer) {
19501
+ if (!this.analysis) return "";
19502
+ switch (section) {
19503
+ case "overview":
19504
+ return this.generateOverviewSection(renderer);
19505
+ case "stack":
19506
+ return this.generateStackSection(renderer);
19507
+ case "commands":
19508
+ return this.generateCommandsSection(renderer);
19509
+ case "conventions":
19510
+ return this.generateConventionsSection(renderer);
19511
+ case "structure":
19512
+ return this.generateStructureSection(renderer);
19513
+ case "guidelines":
19514
+ return this.generateGuidelinesSection(template.agent, renderer);
19515
+ default:
19516
+ return "";
19517
+ }
19518
+ }
19519
+ generateOverviewSection(renderer) {
19520
+ if (!this.analysis) return "";
19521
+ const { project, languages } = this.analysis;
19522
+ const lines = [];
19523
+ lines.push(renderer.h1(project.name));
19524
+ lines.push("");
19525
+ if (project.description) {
19526
+ lines.push(renderer.paragraph(project.description));
19527
+ lines.push("");
19528
+ }
19529
+ if (project.type) {
19530
+ lines.push(renderer.keyValue("Project Type", this.formatProjectType(project.type)));
19531
+ }
19532
+ if (languages.length > 0) {
19533
+ const langNames = languages.map((l) => this.capitalize(l.name)).join(", ");
19534
+ lines.push(renderer.keyValue("Languages", langNames));
19535
+ }
19536
+ if (project.version) {
19537
+ lines.push(renderer.keyValue("Version", project.version));
19538
+ }
19539
+ return lines.join("\n");
19540
+ }
19541
+ generateStackSection(renderer) {
19542
+ if (!this.analysis) return "";
19543
+ const { stack, packageManagers } = this.analysis;
19544
+ const lines = [];
19545
+ lines.push(renderer.h2("Technology Stack"));
19546
+ lines.push("");
19547
+ if (stack.frameworks.length > 0) {
19548
+ lines.push(renderer.h3("Frameworks"));
19549
+ const items = stack.frameworks.map((fw) => {
19550
+ const version = fw.version ? ` (${fw.version})` : "";
19551
+ return `${this.capitalize(fw.name)}${version}`;
19552
+ });
19553
+ lines.push(renderer.list(items));
19554
+ lines.push("");
19555
+ }
19556
+ if (stack.libraries.length > 0) {
19557
+ lines.push(renderer.h3("Libraries"));
19558
+ const items = stack.libraries.map((lib) => {
19559
+ const version = lib.version ? ` (${lib.version})` : "";
19560
+ return `${this.capitalize(lib.name)}${version}`;
19561
+ });
19562
+ lines.push(renderer.list(items));
19563
+ lines.push("");
19564
+ }
19565
+ if (stack.styling.length > 0) {
19566
+ lines.push(renderer.h3("Styling"));
19567
+ lines.push(renderer.list(stack.styling.map((s) => this.capitalize(s.name))));
19568
+ lines.push("");
19569
+ }
19570
+ if (stack.testing.length > 0) {
19571
+ lines.push(renderer.h3("Testing"));
19572
+ lines.push(renderer.list(stack.testing.map((t) => this.capitalize(t.name))));
19573
+ lines.push("");
19574
+ }
19575
+ if (stack.databases.length > 0) {
19576
+ lines.push(renderer.h3("Databases"));
19577
+ lines.push(renderer.list(stack.databases.map((d) => this.capitalize(d.name))));
19578
+ lines.push("");
19579
+ }
19580
+ if (packageManagers.length > 0) {
19581
+ lines.push(renderer.h3("Package Manager"));
19582
+ lines.push(renderer.list([packageManagers.map((pm) => this.capitalize(pm)).join(", ")]));
19583
+ lines.push("");
19584
+ }
19585
+ return lines.join("\n");
19586
+ }
19587
+ generateCommandsSection(renderer) {
19588
+ if (!this.analysis || !this.analysis.buildCommands) return "";
19589
+ const { buildCommands } = this.analysis;
19590
+ const lines = [];
19591
+ const commands = [];
19592
+ lines.push(renderer.h2("Development Commands"));
19593
+ lines.push("");
19594
+ if (buildCommands.install) {
19595
+ commands.push(`# Install dependencies`);
19596
+ commands.push(buildCommands.install);
19597
+ commands.push("");
19598
+ }
19599
+ if (buildCommands.dev) {
19600
+ commands.push(`# Start development server`);
19601
+ commands.push(buildCommands.dev);
19602
+ commands.push("");
19603
+ }
19604
+ if (buildCommands.build) {
19605
+ commands.push(`# Build for production`);
19606
+ commands.push(buildCommands.build);
19607
+ commands.push("");
19608
+ }
19609
+ if (buildCommands.test) {
19610
+ commands.push(`# Run tests`);
19611
+ commands.push(buildCommands.test);
19612
+ commands.push("");
19613
+ }
19614
+ if (buildCommands.lint) {
19615
+ commands.push(`# Run linter`);
19616
+ commands.push(buildCommands.lint);
19617
+ commands.push("");
19618
+ }
19619
+ if (buildCommands.format) {
19620
+ commands.push(`# Format code`);
19621
+ commands.push(buildCommands.format);
19622
+ }
19623
+ lines.push(renderer.codeBlock(commands.join("\n"), "bash"));
19624
+ return lines.join("\n");
19625
+ }
19626
+ generateConventionsSection(renderer) {
19627
+ if (!this.analysis) return "";
19628
+ const { conventions, patterns } = this.analysis;
19629
+ const lines = [];
19630
+ lines.push(renderer.h2("Code Conventions"));
19631
+ lines.push("");
19632
+ if (conventions) {
19633
+ const items = [];
19634
+ if (conventions.indentation) {
19635
+ items.push(`${renderer.bold("Indentation:")} ${conventions.indentation}`);
19636
+ }
19637
+ if (conventions.quotes) {
19638
+ items.push(`${renderer.bold("Quotes:")} ${conventions.quotes}`);
19639
+ }
19640
+ if (conventions.semicolons !== void 0) {
19641
+ items.push(`${renderer.bold("Semicolons:")} ${conventions.semicolons ? "required" : "omitted"}`);
19642
+ }
19643
+ if (conventions.trailingCommas) {
19644
+ items.push(`${renderer.bold("Trailing Commas:")} ${conventions.trailingCommas}`);
19645
+ }
19646
+ if (conventions.maxLineLength) {
19647
+ items.push(`${renderer.bold("Max Line Length:")} ${conventions.maxLineLength}`);
19648
+ }
19649
+ if (items.length > 0) {
19650
+ lines.push(renderer.list(items));
19651
+ }
19652
+ }
19653
+ if (patterns) {
19654
+ lines.push("");
19655
+ lines.push(renderer.h3("Patterns"));
19656
+ const items = [];
19657
+ if (patterns.components) {
19658
+ items.push(`${renderer.bold("Components:")} ${patterns.components}`);
19659
+ }
19660
+ if (patterns.stateManagement) {
19661
+ items.push(`${renderer.bold("State Management:")} ${patterns.stateManagement}`);
19662
+ }
19663
+ if (patterns.apiStyle) {
19664
+ items.push(`${renderer.bold("API Style:")} ${patterns.apiStyle}`);
19665
+ }
19666
+ if (patterns.styling) {
19667
+ items.push(`${renderer.bold("Styling:")} ${patterns.styling}`);
19668
+ }
19669
+ if (patterns.testing) {
19670
+ items.push(`${renderer.bold("Testing:")} ${patterns.testing}`);
19671
+ }
19672
+ if (patterns.linting) {
19673
+ items.push(`${renderer.bold("Linting:")} ${patterns.linting}`);
19674
+ }
19675
+ if (patterns.formatting) {
19676
+ items.push(`${renderer.bold("Formatting:")} ${patterns.formatting}`);
19677
+ }
19678
+ if (items.length > 0) {
19679
+ lines.push(renderer.list(items));
19680
+ }
19681
+ }
19682
+ return lines.join("\n");
19683
+ }
19684
+ generateStructureSection(renderer) {
19685
+ if (!this.analysis) return "";
19686
+ const { structure, importantFiles } = this.analysis;
19687
+ const lines = [];
19688
+ lines.push(renderer.h2("Project Structure"));
19689
+ lines.push("");
19690
+ if (structure) {
19691
+ if (structure.type) {
19692
+ lines.push(renderer.keyValue("Structure Type", structure.type));
19693
+ }
19694
+ if (structure.srcDir) {
19695
+ lines.push(renderer.keyValue("Source Directory", renderer.code(`${structure.srcDir}/`)));
19696
+ }
19697
+ if (structure.testDir) {
19698
+ lines.push(renderer.keyValue("Test Directory", renderer.code(`${structure.testDir}/`)));
19699
+ }
19700
+ if (structure.hasWorkspaces && structure.workspaces) {
19701
+ lines.push(renderer.keyValue("Workspaces", structure.workspaces.join(", ")));
19702
+ }
19703
+ lines.push("");
19704
+ }
19705
+ if (importantFiles.length > 0) {
19706
+ lines.push(renderer.h3("Important Files"));
19707
+ lines.push(renderer.list(importantFiles.slice(0, 15).map((f) => renderer.code(f))));
19708
+ }
19709
+ return lines.join("\n");
19710
+ }
19711
+ generateGuidelinesSection(_agent, renderer) {
19712
+ if (!this.analysis) return "";
19713
+ const { stack, patterns } = this.analysis;
19714
+ const lines = [];
19715
+ lines.push(renderer.h2("Development Guidelines"));
19716
+ lines.push("");
19717
+ const hasReact = stack.frameworks.some((f) => f.name === "react" || f.name === "nextjs");
19718
+ const hasVue = stack.frameworks.some((f) => f.name === "vue" || f.name === "nuxt");
19719
+ const hasTypeScript = this.analysis.languages.some((l) => l.name === "typescript");
19720
+ const hasTailwind = stack.styling.some((s) => s.name === "tailwindcss");
19721
+ const hasPrisma = stack.databases.some((d) => d.name === "prisma");
19722
+ const hasZod = stack.libraries.some((l) => l.name === "zod");
19723
+ if (hasTypeScript) {
19724
+ lines.push(renderer.h3("TypeScript"));
19725
+ lines.push(renderer.list([
19726
+ "Use strict TypeScript with proper type annotations",
19727
+ "Prefer `interface` for object types, `type` for unions/intersections",
19728
+ "Avoid `any` - use `unknown` when type is uncertain"
19729
+ ]));
19730
+ lines.push("");
19731
+ }
19732
+ if (hasReact) {
19733
+ lines.push(renderer.h3("React"));
19734
+ const reactItems = [
19735
+ "Use functional components with hooks",
19736
+ "Prefer composition over inheritance",
19737
+ "Keep components small and focused"
19738
+ ];
19739
+ if (patterns?.stateManagement) {
19740
+ reactItems.push(`Use ${patterns.stateManagement} for state management`);
19741
+ }
19742
+ lines.push(renderer.list(reactItems));
19743
+ lines.push("");
19744
+ }
19745
+ if (hasVue) {
19746
+ lines.push(renderer.h3("Vue"));
19747
+ lines.push(renderer.list([
19748
+ "Use Composition API with `<script setup>`",
19749
+ "Keep components small and focused"
19750
+ ]));
19751
+ lines.push("");
19752
+ }
19753
+ if (hasTailwind) {
19754
+ lines.push(renderer.h3("Styling"));
19755
+ lines.push(renderer.list([
19756
+ "Use Tailwind CSS utility classes",
19757
+ "Follow mobile-first responsive design",
19758
+ "Extract repeated patterns to components"
19759
+ ]));
19760
+ lines.push("");
19761
+ }
19762
+ if (hasPrisma) {
19763
+ lines.push(renderer.h3("Database"));
19764
+ lines.push(renderer.list([
19765
+ "Use Prisma for database operations",
19766
+ "Keep database queries in dedicated service files",
19767
+ "Use transactions for related operations"
19768
+ ]));
19769
+ lines.push("");
19770
+ }
19771
+ if (hasZod) {
19772
+ lines.push(renderer.h3("Validation"));
19773
+ lines.push(renderer.list([
19774
+ "Use Zod for runtime validation",
19775
+ "Define schemas alongside types"
19776
+ ]));
19777
+ lines.push("");
19778
+ }
19779
+ lines.push(renderer.h3("General"));
19780
+ lines.push(renderer.list([
19781
+ "Follow existing code patterns and conventions",
19782
+ "Write clear, self-documenting code",
19783
+ "Keep functions small and focused",
19784
+ "Add tests for new functionality"
19785
+ ]));
19786
+ return lines.join("\n");
19787
+ }
19788
+ writeInstruction(instruction) {
19789
+ const dir = dirname13(instruction.filepath);
19790
+ if (!existsSync36(dir)) {
19791
+ mkdirSync19(dir, { recursive: true });
19792
+ }
19793
+ writeFileSync19(instruction.filepath, instruction.content, "utf-8");
19794
+ }
19795
+ formatProjectType(type) {
19796
+ const typeMap = {
19797
+ "web-app": "Web Application",
19798
+ "api": "API / Backend",
19799
+ "cli": "CLI Tool",
19800
+ "library": "Library / Package",
19801
+ "mobile": "Mobile Application",
19802
+ "desktop": "Desktop Application",
19803
+ "unknown": "Project"
19804
+ };
19805
+ return typeMap[type] || type;
19806
+ }
19807
+ capitalize(str) {
19808
+ return str.charAt(0).toUpperCase() + str.slice(1);
19809
+ }
19810
+ };
19811
+ function generatePrimer(projectPath, options = {}) {
19812
+ const generator = new PrimerGenerator(projectPath, options);
19813
+ return generator.generate();
19814
+ }
19815
+ function generatePrimerForAgent(projectPath, agent, options = {}) {
19816
+ return generatePrimer(projectPath, { ...options, agents: [agent] });
19817
+ }
19818
+ function analyzeForPrimer(projectPath) {
19819
+ const generator = new PrimerGenerator(projectPath, { analyzeOnly: true });
19820
+ const result = generator.generate();
19821
+ return result.analysis;
19822
+ }
18519
19823
  export {
18520
19824
  AGENT_CLI_CONFIGS,
18521
19825
  AGENT_CONFIG,
18522
19826
  AGENT_DISCOVERY_PATHS,
18523
19827
  AGENT_FORMAT_MAP,
19828
+ AGENT_INSTRUCTION_TEMPLATES,
18524
19829
  AGENT_SKILL_FORMATS,
18525
19830
  AIManager,
18526
19831
  AISearch,
@@ -18584,6 +19889,8 @@ export {
18584
19889
  PlanValidator,
18585
19890
  PluginLoader,
18586
19891
  PluginManager,
19892
+ PrimerAnalyzer,
19893
+ PrimerGenerator,
18587
19894
  ProjectDetector,
18588
19895
  RecommendationEngine,
18589
19896
  RuleBasedCompressor,
@@ -18613,6 +19920,8 @@ export {
18613
19920
  WorkflowOrchestrator,
18614
19921
  addToManifest,
18615
19922
  agentExists,
19923
+ analyzeForPrimer,
19924
+ analyzePrimer,
18616
19925
  analyzeProject,
18617
19926
  benchmarkSkill,
18618
19927
  buildSkillIndex,
@@ -18685,6 +19994,8 @@ export {
18685
19994
  fromCanonicalAgent,
18686
19995
  generateComparisonNotes,
18687
19996
  generateManifestFromInstalled,
19997
+ generatePrimer,
19998
+ generatePrimerForAgent,
18688
19999
  generateRecommendations,
18689
20000
  generateSkillsConfig,
18690
20001
  getAgentCLIConfig,