lynxprompt 2.1.42 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1401,9 +1401,9 @@ var SKILL_DIRECTORIES = [
1401
1401
  ".opencode/skills"
1402
1402
  ];
1403
1403
  function skillFolder(bp) {
1404
- const lines = (bp.content ?? "").split("\n").map((l) => l.trimEnd());
1405
- const end = lines[0] === "---" ? lines.indexOf("---", 1) : -1;
1406
- const nameLine = end > 0 ? lines.slice(1, end).find((l) => l.startsWith("name:")) : void 0;
1404
+ const lines2 = (bp.content ?? "").split("\n").map((l) => l.trimEnd());
1405
+ const end = lines2[0] === "---" ? lines2.indexOf("---", 1) : -1;
1406
+ const nameLine = end > 0 ? lines2.slice(1, end).find((l) => l.startsWith("name:")) : void 0;
1407
1407
  const name = nameLine?.slice("name:".length).trim().replace(/^["']|["']$/g, "");
1408
1408
  const slug = (name || bp.name || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").split("-").filter(Boolean).join("-");
1409
1409
  return slug || "skill";
@@ -1506,8 +1506,8 @@ function adaptRulesContent(content, fromPlatform, toPlatform, description) {
1506
1506
  const target = PLATFORM_FRONTMATTER[toPlatform];
1507
1507
  if (fromPlatform === toPlatform && (frontmatter || !target)) return content;
1508
1508
  if (frontmatter && target && PLATFORM_FRONTMATTER[fromPlatform] === target) return content;
1509
- const lines = frontmatterLines(toPlatform, description);
1510
- return lines.length ? `${lines.join("\n")}
1509
+ const lines2 = frontmatterLines(toPlatform, description);
1510
+ return lines2.length ? `${lines2.join("\n")}
1511
1511
  ${body}` : body;
1512
1512
  }
1513
1513
 
@@ -1520,21 +1520,21 @@ function syncInstructions(opts) {
1520
1520
  const bpId = toBlueprintApiId(opts.blueprintId);
1521
1521
  const file = opts.fileName;
1522
1522
  const appUrl = opts.appUrl.replace(/\/+$/, "");
1523
- const lines = [
1523
+ const lines2 = [
1524
1524
  "LynxPrompt Cloud Sync",
1525
1525
  `Blueprint ID: ${bpId}`,
1526
1526
  "This file is synced with LynxPrompt.",
1527
1527
  ""
1528
1528
  ];
1529
1529
  if (opts.preferCliSync) {
1530
- lines.push(
1530
+ lines2.push(
1531
1531
  "Using the LynxPrompt CLI (recommended, no token in this file):",
1532
1532
  " npm install -g lynxprompt"
1533
1533
  );
1534
1534
  if (appUrl !== CLI_DEFAULT_API_URL) {
1535
- lines.push(` export LYNXPROMPT_API_URL=${appUrl}`);
1535
+ lines2.push(` export LYNXPROMPT_API_URL=${appUrl}`);
1536
1536
  }
1537
- lines.push(
1537
+ lines2.push(
1538
1538
  " lynxp login",
1539
1539
  ` lynxp link ${file} ${bpId} # once: track this file without overwriting it`,
1540
1540
  ` lynxp push ${file} # upload local changes`,
@@ -1544,7 +1544,7 @@ function syncInstructions(opts) {
1544
1544
  } else {
1545
1545
  const token = opts.tokenEnvVar || "LYNXPROMPT_API_TOKEN";
1546
1546
  const url = `${appUrl}/api/v1/blueprints/${bpId}`;
1547
- lines.push(
1547
+ lines2.push(
1548
1548
  `Using curl, with the API token in $${token} (never put the token in this file):`,
1549
1549
  ` export ${token}="your_token_here"`,
1550
1550
  "",
@@ -1555,17 +1555,17 @@ function syncInstructions(opts) {
1555
1555
  ` curl -sf "${url}" -H "Authorization: Bearer $${token}" | jq -er '.blueprint.content' > ${file}.new && mv ${file}.new ${file}`
1556
1556
  );
1557
1557
  }
1558
- lines.push("", `Generate an API token at: ${appUrl}/settings`, `Docs: ${appUrl}/docs/api`);
1559
- return lines;
1558
+ lines2.push("", `Generate an API token at: ${appUrl}/settings`, `Docs: ${appUrl}/docs/api`);
1559
+ return lines2;
1560
1560
  }
1561
1561
  function addApiSyncHeader(content, opts) {
1562
1562
  const ext = opts.fileName.toLowerCase().split(".").pop() || "";
1563
1563
  if (ext === "json") return content;
1564
- const lines = syncInstructions(opts);
1564
+ const lines2 = syncInstructions(opts);
1565
1565
  if (ext === "yaml" || ext === "yml" || ext === "toml") {
1566
- return lines.map((l) => l ? `# ${l}` : "#").join("\n") + "\n\n" + content;
1566
+ return lines2.map((l) => l ? `# ${l}` : "#").join("\n") + "\n\n" + content;
1567
1567
  }
1568
- const block = ["<!--", ...lines, "-->", ""].join("\n");
1568
+ const block = ["<!--", ...lines2, "-->", ""].join("\n");
1569
1569
  const frontmatter = content.match(/^---\r?\n[\s\S]*?\r?\n---\r?\n/);
1570
1570
  if (frontmatter) {
1571
1571
  return frontmatter[0] + "\n" + block + "\n" + content.slice(frontmatter[0].length);
@@ -2126,21 +2126,21 @@ var MONOREPO_TOOLS = {
2126
2126
  pnpm_workspaces: "pnpm Workspaces"
2127
2127
  };
2128
2128
  function toolingLines(config2) {
2129
- const lines = [];
2130
- if (config2.packageManager) lines.push(`- **Package manager**: ${label(PACKAGE_MANAGERS, config2.packageManager)}. Use it for every install and script.`);
2131
- if (config2.jsRuntime) lines.push(`- **Runtime**: ${label(JS_RUNTIMES, config2.jsRuntime)}`);
2132
- if (config2.monorepoTool) lines.push(`- **Monorepo tool**: ${label(MONOREPO_TOOLS, config2.monorepoTool)}`);
2133
- if (config2.orm) lines.push(`- **ORM / database toolkit**: ${config2.orm}`);
2134
- return lines;
2129
+ const lines2 = [];
2130
+ if (config2.packageManager) lines2.push(`- **Package manager**: ${label(PACKAGE_MANAGERS, config2.packageManager)}. Use it for every install and script.`);
2131
+ if (config2.jsRuntime) lines2.push(`- **Runtime**: ${label(JS_RUNTIMES, config2.jsRuntime)}`);
2132
+ if (config2.monorepoTool) lines2.push(`- **Monorepo tool**: ${label(MONOREPO_TOOLS, config2.monorepoTool)}`);
2133
+ if (config2.orm) lines2.push(`- **ORM / database toolkit**: ${config2.orm}`);
2134
+ return lines2;
2135
2135
  }
2136
2136
  function extraCommandLines(config2) {
2137
2137
  const commands = config2.commands || {};
2138
- const lines = [];
2139
- if (commands.typecheck) lines.push(`- **Type check**: \`${commands.typecheck}\``);
2140
- if (commands.format) lines.push(`- **Format**: \`${commands.format}\``);
2141
- if (commands.preCommit) lines.push(`- **Pre-commit hooks**: \`${commands.preCommit}\``);
2142
- if (commands.clean) lines.push(`- **Clean**: \`${commands.clean}\``);
2143
- return lines;
2138
+ const lines2 = [];
2139
+ if (commands.typecheck) lines2.push(`- **Type check**: \`${commands.typecheck}\``);
2140
+ if (commands.format) lines2.push(`- **Format**: \`${commands.format}\``);
2141
+ if (commands.preCommit) lines2.push(`- **Pre-commit hooks**: \`${commands.preCommit}\``);
2142
+ if (commands.clean) lines2.push(`- **Clean**: \`${commands.clean}\``);
2143
+ return lines2;
2144
2144
  }
2145
2145
  var IMPORT_ORDERS = {
2146
2146
  grouped: "group imports: external packages, then internal modules, then relative paths",
@@ -2159,14 +2159,14 @@ var DOC_STYLES = {
2159
2159
  var DEFAULT_MAX_FILE_LENGTH = 300;
2160
2160
  function extraCodeStyleLines(config2) {
2161
2161
  const style = config2.codeStyle || {};
2162
- const lines = [];
2162
+ const lines2 = [];
2163
2163
  if (style.maxFileLength && style.maxFileLength !== DEFAULT_MAX_FILE_LENGTH) {
2164
- lines.push(`- **File length**: keep files under ${style.maxFileLength} lines; split larger ones`);
2164
+ lines2.push(`- **File length**: keep files under ${style.maxFileLength} lines; split larger ones`);
2165
2165
  }
2166
- if (style.importOrder) lines.push(`- **Imports**: ${label(IMPORT_ORDERS, style.importOrder)}`);
2167
- if (style.commentLanguage) lines.push(`- **Comment language**: write code comments in ${style.commentLanguage.replace(/_/g, " ")}`);
2168
- if (style.docStyle) lines.push(`- **Documentation comments**: ${label(DOC_STYLES, style.docStyle)}`);
2169
- return lines;
2166
+ if (style.importOrder) lines2.push(`- **Imports**: ${label(IMPORT_ORDERS, style.importOrder)}`);
2167
+ if (style.commentLanguage) lines2.push(`- **Comment language**: write code comments in ${style.commentLanguage.replace(/_/g, " ")}`);
2168
+ if (style.docStyle) lines2.push(`- **Documentation comments**: ${label(DOC_STYLES, style.docStyle)}`);
2169
+ return lines2;
2170
2170
  }
2171
2171
  var MOCK_STRATEGIES = {
2172
2172
  minimal: "mock only external dependencies",
@@ -2179,11 +2179,11 @@ function hasExtraTesting(config2) {
2179
2179
  }
2180
2180
  function extraTestingLines(config2) {
2181
2181
  const testing = config2.testingStrategy || {};
2182
- const lines = [];
2183
- if (testing.tddPreference) lines.push("- **Test-driven development**: write a failing test first, then the code that makes it pass");
2184
- if (testing.snapshotTesting) lines.push("- **Snapshot tests**: use snapshot tests for stable output such as rendered components");
2185
- if (testing.mockStrategy) lines.push(`- **Mocking**: ${label(MOCK_STRATEGIES, testing.mockStrategy)}`);
2186
- return lines;
2182
+ const lines2 = [];
2183
+ if (testing.tddPreference) lines2.push("- **Test-driven development**: write a failing test first, then the code that makes it pass");
2184
+ if (testing.snapshotTesting) lines2.push("- **Snapshot tests**: use snapshot tests for stable output such as rendered components");
2185
+ if (testing.mockStrategy) lines2.push(`- **Mocking**: ${label(MOCK_STRATEGIES, testing.mockStrategy)}`);
2186
+ return lines2;
2187
2187
  }
2188
2188
  var BRANCH_STRATEGIES = {
2189
2189
  none: "no branches: commit directly to the default branch",
@@ -2211,19 +2211,19 @@ var CHANGELOG_TOOLS = {
2211
2211
  other: "kept with the project's own tooling"
2212
2212
  };
2213
2213
  function gitWorkflowLines(config2) {
2214
- const lines = [];
2214
+ const lines2 = [];
2215
2215
  const branch = config2.defaultBranch || "main";
2216
- if (config2.branchStrategy) lines.push(`- **Branching**: ${label(BRANCH_STRATEGIES, config2.branchStrategy)}`);
2217
- if (config2.defaultBranch) lines.push(`- **Default branch**: \`${branch}\``);
2216
+ if (config2.branchStrategy) lines2.push(`- **Branching**: ${label(BRANCH_STRATEGIES, config2.branchStrategy)}`);
2217
+ if (config2.defaultBranch) lines2.push(`- **Default branch**: \`${branch}\``);
2218
2218
  if (config2.branchStrategy !== "none") {
2219
- lines.push(
2219
+ lines2.push(
2220
2220
  config2.allowDirectCommits ? `- Direct commits to \`${branch}\` are fine for small fixes (typos, docs); everything else goes through a branch` : `- Never commit directly to \`${branch}\`; work on a branch and open a pull request`
2221
2221
  );
2222
2222
  }
2223
- if (config2.commitSigning) lines.push("- Sign every commit (GPG or SSH)");
2224
- if (config2.versionTagFormat) lines.push(`- **Version tags**: ${label(VERSION_TAG_FORMATS, config2.versionTagFormat)}`);
2225
- if (config2.changelogTool) lines.push(`- **Changelog**: ${label(CHANGELOG_TOOLS, config2.changelogTool)}`);
2226
- return lines;
2223
+ if (config2.commitSigning) lines2.push("- Sign every commit (GPG or SSH)");
2224
+ if (config2.versionTagFormat) lines2.push(`- **Version tags**: ${label(VERSION_TAG_FORMATS, config2.versionTagFormat)}`);
2225
+ if (config2.changelogTool) lines2.push(`- **Changelog**: ${label(CHANGELOG_TOOLS, config2.changelogTool)}`);
2226
+ return lines2;
2227
2227
  }
2228
2228
  function dockerImageLines(config2) {
2229
2229
  if (!config2.buildContainer) return [];
@@ -2245,12 +2245,12 @@ var VERBOSITY = {
2245
2245
  detailed: "**Explanations**: detailed, walking through the reasoning"
2246
2246
  };
2247
2247
  function aiPreferenceLines(config2) {
2248
- const lines = [];
2249
- if (config2.planModeFrequency) lines.push(`- ${label(PLAN_MODES, config2.planModeFrequency)}`);
2250
- if (config2.explanationVerbosity) lines.push(`- ${label(VERBOSITY, config2.explanationVerbosity)}`);
2251
- if (config2.accessibilityFocus) lines.push("- **Accessibility**: follow WCAG; use semantic markup, labels, keyboard access and enough contrast");
2252
- if (config2.performanceFocus) lines.push("- **Performance**: keep an eye on load time, memory and needless work; measure before optimising");
2253
- return lines;
2248
+ const lines2 = [];
2249
+ if (config2.planModeFrequency) lines2.push(`- ${label(PLAN_MODES, config2.planModeFrequency)}`);
2250
+ if (config2.explanationVerbosity) lines2.push(`- ${label(VERBOSITY, config2.explanationVerbosity)}`);
2251
+ if (config2.accessibilityFocus) lines2.push("- **Accessibility**: follow WCAG; use semantic markup, labels, keyboard access and enough contrast");
2252
+ if (config2.performanceFocus) lines2.push("- **Performance**: keep an eye on load time, memory and needless work; measure before optimising");
2253
+ return lines2;
2254
2254
  }
2255
2255
  function mcpServerSection(config2, heading) {
2256
2256
  const servers = (config2.mcpServers || "").split(",").map((s) => s.trim()).filter(Boolean);
@@ -2272,18 +2272,18 @@ var DEPLOYMENT_METHODS = {
2272
2272
  };
2273
2273
  function infrastructureSection(config2, heading) {
2274
2274
  if (!config2.serverAccess && !config2.manualDeployment) return [];
2275
- const lines = [heading, ""];
2275
+ const lines2 = [heading, ""];
2276
2276
  if (config2.serverAccess) {
2277
2277
  const keyInfo = config2.sshKeyPath ? `SSH key: \`${config2.sshKeyPath}\`` : "SSH key in default location (~/.ssh/)";
2278
- lines.push(`- **Server access**: via SSH. ${keyInfo}`);
2278
+ lines2.push(`- **Server access**: via SSH. ${keyInfo}`);
2279
2279
  }
2280
2280
  if (config2.manualDeployment) {
2281
- lines.push(
2281
+ lines2.push(
2282
2282
  config2.deploymentMethod ? `- **Deployment**: ${label(DEPLOYMENT_METHODS, config2.deploymentMethod)}` : "- **Deployment**: manual, not through CI/CD"
2283
2283
  );
2284
2284
  }
2285
- lines.push("");
2286
- return lines;
2285
+ lines2.push("");
2286
+ return lines2;
2287
2287
  }
2288
2288
  var AUTH_PROVIDER_LABELS = {
2289
2289
  email_password: "Email/Password",
@@ -2421,24 +2421,24 @@ function rulesDescription(config2) {
2421
2421
  return `AI rules for ${name || "this project"}`;
2422
2422
  }
2423
2423
  function generateCursorRules(config2, user, brand) {
2424
- const lines = [];
2424
+ const lines2 = [];
2425
2425
  const bp = config2.blueprintMode;
2426
- lines.push(...frontmatterLines("cursor", rulesDescription(config2)));
2427
- lines.push(`# ${bpVar(bp, "PROJECT_NAME", config2.projectName || "Project")} - AI Rules`);
2428
- lines.push("");
2426
+ lines2.push(...frontmatterLines("cursor", rulesDescription(config2)));
2427
+ lines2.push(`# ${bpVar(bp, "PROJECT_NAME", config2.projectName || "Project")} - AI Rules`);
2428
+ lines2.push("");
2429
2429
  if (config2.useGitWorktrees) {
2430
- lines.push("## Before Starting Any Coding Task");
2431
- lines.push("");
2432
- lines.push("1. Check existing worktrees with `git worktree list` and create a new one for this task if needed");
2433
- lines.push("2. Use the naming convention: `git worktree add -b ai/[task-description] ../[repo-name]-ai-[task-description]`");
2434
- lines.push("3. Navigate to the worktree directory before making any changes");
2435
- lines.push("4. Commit changes when the task is finished. Merge to main, and clean the worktree.");
2436
- lines.push("");
2437
- }
2438
- lines.push("## Project Overview");
2439
- lines.push("");
2440
- lines.push(`**Description**: ${bpVar(bp, "PROJECT_DESCRIPTION", config2.projectDescription || "A software project.")}`);
2441
- lines.push("");
2430
+ lines2.push("## Before Starting Any Coding Task");
2431
+ lines2.push("");
2432
+ lines2.push("1. Check existing worktrees with `git worktree list` and create a new one for this task if needed");
2433
+ lines2.push("2. Use the naming convention: `git worktree add -b ai/[task-description] ../[repo-name]-ai-[task-description]`");
2434
+ lines2.push("3. Navigate to the worktree directory before making any changes");
2435
+ lines2.push("4. Commit changes when the task is finished. Merge to main, and clean the worktree.");
2436
+ lines2.push("");
2437
+ }
2438
+ lines2.push("## Project Overview");
2439
+ lines2.push("");
2440
+ lines2.push(`**Description**: ${bpVar(bp, "PROJECT_DESCRIPTION", config2.projectDescription || "A software project.")}`);
2441
+ lines2.push("");
2442
2442
  if (config2.architecturePattern) {
2443
2443
  const archLabels = {
2444
2444
  monolith: "Monolith - single deployable unit",
@@ -2454,20 +2454,20 @@ function generateCursorRules(config2, user, brand) {
2454
2454
  other: config2.architecturePatternOther || "Custom architecture"
2455
2455
  };
2456
2456
  const archValue = archLabels[config2.architecturePattern] || optionLabel(ARCHITECTURE_PATTERNS, config2.architecturePattern);
2457
- lines.push(`**Architecture Pattern**: ${bpVar(bp, "ARCHITECTURE_PATTERN", archValue)}`);
2457
+ lines2.push(`**Architecture Pattern**: ${bpVar(bp, "ARCHITECTURE_PATTERN", archValue)}`);
2458
2458
  }
2459
2459
  if (config2.isPublic !== void 0) {
2460
- lines.push(`**Visibility**: ${config2.isPublic ? "Public repository" : "Private repository"}`);
2460
+ lines2.push(`**Visibility**: ${config2.isPublic ? "Public repository" : "Private repository"}`);
2461
2461
  }
2462
2462
  if (config2.devOS) {
2463
- lines.push(`**Development OS**: ${formatDevOSDisplay(config2)}`);
2463
+ lines2.push(`**Development OS**: ${formatDevOSDisplay(config2)}`);
2464
2464
  }
2465
- lines.push("");
2465
+ lines2.push("");
2466
2466
  const hasRepoInfo = config2.repoUrl || config2.repoHosts?.length || config2.repoHost;
2467
2467
  if (hasRepoInfo) {
2468
- lines.push("### Repository");
2468
+ lines2.push("### Repository");
2469
2469
  if (config2.repoUrl) {
2470
- lines.push(`- **URL**: ${bpVar(bp, "REPO_URL", config2.repoUrl)}`);
2470
+ lines2.push(`- **URL**: ${bpVar(bp, "REPO_URL", config2.repoUrl)}`);
2471
2471
  }
2472
2472
  if (config2.repoHosts?.length || config2.repoHost) {
2473
2473
  const hostNames = {
@@ -2487,108 +2487,108 @@ function generateCursorRules(config2, user, brand) {
2487
2487
  };
2488
2488
  const hosts = config2.repoHosts?.length ? config2.repoHosts : [config2.repoHost];
2489
2489
  const hostLabels = hosts.map((h) => hostNames[h] || optionLabel(REPO_HOSTS, h)).join(", ");
2490
- lines.push(`- **Platform${hosts.length > 1 ? "s" : ""}**: ${bpVar(bp, "REPO_HOST", hostLabels)}`);
2490
+ lines2.push(`- **Platform${hosts.length > 1 ? "s" : ""}**: ${bpVar(bp, "REPO_HOST", hostLabels)}`);
2491
2491
  if (hosts.length > 1 && config2.multiRepoReason) {
2492
- lines.push(`- **Why multiple platforms**: ${config2.multiRepoReason}`);
2492
+ lines2.push(`- **Why multiple platforms**: ${config2.multiRepoReason}`);
2493
2493
  }
2494
2494
  }
2495
- lines.push("");
2495
+ lines2.push("");
2496
2496
  }
2497
2497
  if (config2.devOS) {
2498
2498
  const osList = resolveDevOS(config2);
2499
- lines.push("### Development Environment");
2499
+ lines2.push("### Development Environment");
2500
2500
  if (isMultiPlatformOS(config2) || osList.length > 1) {
2501
- lines.push("- Use cross-platform commands that work on Windows, macOS, and Linux");
2502
- lines.push("- Prefer npm scripts or Makefile targets over platform-specific commands");
2501
+ lines2.push("- Use cross-platform commands that work on Windows, macOS, and Linux");
2502
+ lines2.push("- Prefer npm scripts or Makefile targets over platform-specific commands");
2503
2503
  } else if (osList.includes("windows")) {
2504
- lines.push("- Use PowerShell or CMD compatible commands");
2505
- lines.push("- Use backslashes for paths, or forward slashes for cross-platform compatibility");
2504
+ lines2.push("- Use PowerShell or CMD compatible commands");
2505
+ lines2.push("- Use backslashes for paths, or forward slashes for cross-platform compatibility");
2506
2506
  } else if (osList.includes("wsl")) {
2507
- lines.push("- Prefer Linux commands (bash/zsh)");
2508
- lines.push("- Be aware of Windows/Linux path translations when needed");
2507
+ lines2.push("- Prefer Linux commands (bash/zsh)");
2508
+ lines2.push("- Be aware of Windows/Linux path translations when needed");
2509
2509
  } else if (osList.includes("linux")) {
2510
- lines.push("- Use standard Unix/Linux commands (bash, zsh)");
2510
+ lines2.push("- Use standard Unix/Linux commands (bash, zsh)");
2511
2511
  } else if (osList.includes("macos")) {
2512
- lines.push("- Use standard Unix commands, macOS-specific tools are acceptable");
2512
+ lines2.push("- Use standard Unix commands, macOS-specific tools are acceptable");
2513
2513
  }
2514
- lines.push("");
2514
+ lines2.push("");
2515
2515
  }
2516
2516
  if (config2.exampleRepoUrl || config2.documentationUrl) {
2517
- lines.push("### Reference Materials");
2517
+ lines2.push("### Reference Materials");
2518
2518
  if (config2.exampleRepoUrl) {
2519
- lines.push(`- **Example Repository**: ${bpVar(bp, "EXAMPLE_REPO_URL", config2.exampleRepoUrl)}`);
2520
- lines.push(" Use this as a reference for coding patterns, conventions, and architecture decisions.");
2519
+ lines2.push(`- **Example Repository**: ${bpVar(bp, "EXAMPLE_REPO_URL", config2.exampleRepoUrl)}`);
2520
+ lines2.push(" Use this as a reference for coding patterns, conventions, and architecture decisions.");
2521
2521
  }
2522
2522
  if (config2.documentationUrl) {
2523
- lines.push(`- **External Documentation**: ${bpVar(bp, "DOCUMENTATION_URL", config2.documentationUrl)}`);
2524
- lines.push(" Refer to this for additional project context, architecture decisions, and team guidelines.");
2523
+ lines2.push(`- **External Documentation**: ${bpVar(bp, "DOCUMENTATION_URL", config2.documentationUrl)}`);
2524
+ lines2.push(" Refer to this for additional project context, architecture decisions, and team guidelines.");
2525
2525
  }
2526
- lines.push("");
2526
+ lines2.push("");
2527
2527
  }
2528
2528
  const tooling = toolingLines(config2);
2529
2529
  if (config2.languages.length > 0 || config2.frameworks.length > 0 || config2.databases && config2.databases.length > 0 || config2.letAiDecide || tooling.length > 0) {
2530
- lines.push("## Technology Stack");
2531
- lines.push("");
2532
- lines.push("This project uses the following technologies. Please ensure all code follows the conventions and best practices for these:");
2533
- lines.push("");
2530
+ lines2.push("## Technology Stack");
2531
+ lines2.push("");
2532
+ lines2.push("This project uses the following technologies. Please ensure all code follows the conventions and best practices for these:");
2533
+ lines2.push("");
2534
2534
  if (config2.languages.length > 0) {
2535
2535
  const langs = config2.languages.map(stackLabel);
2536
- lines.push(`**Programming Languages**: ${bpVarArray(bp, "LANGUAGES", langs)}`);
2536
+ lines2.push(`**Programming Languages**: ${bpVarArray(bp, "LANGUAGES", langs)}`);
2537
2537
  }
2538
2538
  if (config2.frameworks.length > 0) {
2539
2539
  const fws = config2.frameworks.map(stackLabel);
2540
- lines.push(`**Frameworks & Libraries**: ${bpVarArray(bp, "FRAMEWORKS", fws)}`);
2540
+ lines2.push(`**Frameworks & Libraries**: ${bpVarArray(bp, "FRAMEWORKS", fws)}`);
2541
2541
  }
2542
2542
  if (config2.databases && config2.databases.length > 0) {
2543
2543
  const dbs = config2.databases.map(stackLabel);
2544
- lines.push(`**Database${config2.databases.length > 1 ? "s" : ""}**: ${bpVarArray(bp, "DATABASES", dbs)}`);
2544
+ lines2.push(`**Database${config2.databases.length > 1 ? "s" : ""}**: ${bpVarArray(bp, "DATABASES", dbs)}`);
2545
2545
  }
2546
2546
  if (tooling.length > 0) {
2547
- lines.push("");
2548
- lines.push(...tooling);
2547
+ lines2.push("");
2548
+ lines2.push(...tooling);
2549
2549
  }
2550
2550
  if (config2.letAiDecide) {
2551
- lines.push("");
2551
+ lines2.push("");
2552
2552
  if (config2.languages.length > 0 || config2.frameworks.length > 0) {
2553
- lines.push("**AI Flexibility**: For technologies not listed above, you may suggest and use what's best suited for the project based on codebase analysis.");
2553
+ lines2.push("**AI Flexibility**: For technologies not listed above, you may suggest and use what's best suited for the project based on codebase analysis.");
2554
2554
  } else {
2555
- lines.push("**AI Flexibility**: Analyze the codebase to determine appropriate languages and frameworks. You have full flexibility to choose what works best.");
2555
+ lines2.push("**AI Flexibility**: Analyze the codebase to determine appropriate languages and frameworks. You have full flexibility to choose what works best.");
2556
2556
  }
2557
2557
  }
2558
- lines.push("");
2558
+ lines2.push("");
2559
2559
  }
2560
- lines.push("## Code Style & Conventions");
2561
- lines.push("");
2562
- lines.push("Follow these coding style guidelines when writing or modifying code:");
2563
- lines.push("");
2560
+ lines2.push("## Code Style & Conventions");
2561
+ lines2.push("");
2562
+ lines2.push("Follow these coding style guidelines when writing or modifying code:");
2563
+ lines2.push("");
2564
2564
  if (config2.includePersonalData !== false && (user.skillLevel || user.persona)) {
2565
- lines.push("### Developer Profile");
2565
+ lines2.push("### Developer Profile");
2566
2566
  if (user.skillLevel) {
2567
2567
  const authorName = user.displayName || user.name || "Developer";
2568
- lines.push(`- **Author**: ${bpVar(bp, "AUTHOR_NAME", authorName)}`);
2568
+ lines2.push(`- **Author**: ${bpVar(bp, "AUTHOR_NAME", authorName)}`);
2569
2569
  }
2570
2570
  if (user.persona) {
2571
- lines.push(`- **Developer Background**: ${user.persona.replace(/_/g, " ")} \u2014 adapt responses to this domain expertise`);
2571
+ lines2.push(`- **Developer Background**: ${user.persona.replace(/_/g, " ")} \u2014 adapt responses to this domain expertise`);
2572
2572
  }
2573
- if (!user.skillLevel) lines.push("");
2573
+ if (!user.skillLevel) lines2.push("");
2574
2574
  }
2575
2575
  if (config2.includePersonalData !== false && user.skillLevel) {
2576
- lines.push(`- **Experience Level**: ${user.skillLevel.charAt(0).toUpperCase() + user.skillLevel.slice(1)}`);
2577
- lines.push("");
2578
- lines.push("### Communication Style");
2576
+ lines2.push(`- **Experience Level**: ${user.skillLevel.charAt(0).toUpperCase() + user.skillLevel.slice(1)}`);
2577
+ lines2.push("");
2578
+ lines2.push("### Communication Style");
2579
2579
  if (user.skillLevel === "novice" || user.skillLevel === "beginner") {
2580
- lines.push("- Be verbose with explanations and add helpful comments");
2581
- lines.push("- Explain concepts and reasoning as you implement them");
2582
- lines.push("- Ask clarifying questions when requirements are unclear");
2580
+ lines2.push("- Be verbose with explanations and add helpful comments");
2581
+ lines2.push("- Explain concepts and reasoning as you implement them");
2582
+ lines2.push("- Ask clarifying questions when requirements are unclear");
2583
2583
  } else if (user.skillLevel === "intermediate") {
2584
- lines.push("- Provide balanced explanations, not too verbose");
2585
- lines.push("- Focus on important decisions, trade-offs, and non-obvious choices");
2584
+ lines2.push("- Provide balanced explanations, not too verbose");
2585
+ lines2.push("- Focus on important decisions, trade-offs, and non-obvious choices");
2586
2586
  } else {
2587
- lines.push("- Be concise and direct in communications");
2588
- lines.push("- Assume expertise - minimal hand-holding needed");
2589
- lines.push("- Focus on implementation details, skip explanations of basics");
2587
+ lines2.push("- Be concise and direct in communications");
2588
+ lines2.push("- Assume expertise - minimal hand-holding needed");
2589
+ lines2.push("- Focus on implementation details, skip explanations of basics");
2590
2590
  }
2591
- lines.push("");
2591
+ lines2.push("");
2592
2592
  }
2593
2593
  if (config2.codeStyle?.naming) {
2594
2594
  const namingDescriptions = {
@@ -2599,9 +2599,9 @@ function generateCursorRules(config2, user, brand) {
2599
2599
  "kebab-case": "Use kebab-case for file names and URLs (e.g., my-component, user-profile)"
2600
2600
  };
2601
2601
  const namingValue = namingDescriptions[config2.codeStyle.naming] || config2.codeStyle.naming;
2602
- lines.push("### Naming Conventions");
2603
- lines.push(`**Style**: ${bpVar(bp, "NAMING_CONVENTION", namingValue)}`);
2604
- lines.push("");
2602
+ lines2.push("### Naming Conventions");
2603
+ lines2.push(`**Style**: ${bpVar(bp, "NAMING_CONVENTION", namingValue)}`);
2604
+ lines2.push("");
2605
2605
  }
2606
2606
  if (config2.codeStyle?.errorHandling) {
2607
2607
  const errorDescriptions = {
@@ -2614,46 +2614,46 @@ function generateCursorRules(config2, user, brand) {
2614
2614
  other: config2.codeStyle.errorHandlingOther || "Follow the project's custom error handling approach"
2615
2615
  };
2616
2616
  const errorValue = errorDescriptions[config2.codeStyle.errorHandling] || optionLabel(ERROR_HANDLING_PATTERNS, config2.codeStyle.errorHandling);
2617
- lines.push("### Error Handling");
2618
- lines.push(`**Approach**: ${bpVar(bp, "ERROR_HANDLING", errorValue)}`);
2619
- lines.push("");
2617
+ lines2.push("### Error Handling");
2618
+ lines2.push(`**Approach**: ${bpVar(bp, "ERROR_HANDLING", errorValue)}`);
2619
+ lines2.push("");
2620
2620
  }
2621
2621
  if (config2.codeStyle?.loggingConventions) {
2622
- lines.push("### Logging Conventions");
2623
- lines.push(`**Guidelines**: ${bpVar(bp, "LOGGING_CONVENTIONS", optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions))}`);
2624
- lines.push("");
2622
+ lines2.push("### Logging Conventions");
2623
+ lines2.push(`**Guidelines**: ${bpVar(bp, "LOGGING_CONVENTIONS", optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions))}`);
2624
+ lines2.push("");
2625
2625
  }
2626
2626
  const styleExtras = extraCodeStyleLines(config2);
2627
2627
  if (styleExtras.length > 0) {
2628
- lines.push("### Formatting & Documentation");
2629
- lines.push(...styleExtras);
2630
- lines.push("");
2628
+ lines2.push("### Formatting & Documentation");
2629
+ lines2.push(...styleExtras);
2630
+ lines2.push("");
2631
2631
  }
2632
2632
  if (config2.codeStyle?.notes) {
2633
- lines.push("### Additional Style Notes");
2634
- lines.push(bpVar(bp, "CODE_STYLE_NOTES", config2.codeStyle.notes));
2635
- lines.push("");
2633
+ lines2.push("### Additional Style Notes");
2634
+ lines2.push(bpVar(bp, "CODE_STYLE_NOTES", config2.codeStyle.notes));
2635
+ lines2.push("");
2636
2636
  }
2637
2637
  const aiPrefs = aiPreferenceLines(config2);
2638
2638
  if (config2.aiBehaviorRules.length > 0 || aiPrefs.length > 0) {
2639
- lines.push("## AI Behavior Guidelines");
2640
- lines.push("");
2641
- lines.push("When assisting with this project, follow these specific rules:");
2642
- lines.push("");
2639
+ lines2.push("## AI Behavior Guidelines");
2640
+ lines2.push("");
2641
+ lines2.push("When assisting with this project, follow these specific rules:");
2642
+ lines2.push("");
2643
2643
  config2.aiBehaviorRules.forEach((rule) => {
2644
2644
  const ruleText = getRuleDescription(rule);
2645
- if (ruleText) lines.push(`- ${ruleText}`);
2645
+ if (ruleText) lines2.push(`- ${ruleText}`);
2646
2646
  });
2647
- lines.push(...aiPrefs);
2647
+ lines2.push(...aiPrefs);
2648
2648
  if (config2.attemptWorkarounds === true) {
2649
- lines.push("- When stuck, **attempt creative workarounds** before asking for help");
2649
+ lines2.push("- When stuck, **attempt creative workarounds** before asking for help");
2650
2650
  } else if (config2.attemptWorkarounds === false) {
2651
- lines.push("- When stuck, **stop and ask** rather than attempting workarounds");
2651
+ lines2.push("- When stuck, **stop and ask** rather than attempting workarounds");
2652
2652
  }
2653
- lines.push("");
2653
+ lines2.push("");
2654
2654
  }
2655
- lines.push(...mcpServerSection(config2, "## MCP Servers"));
2656
- lines.push(...infrastructureSection(config2, "## Infrastructure"));
2655
+ lines2.push(...mcpServerSection(config2, "## MCP Servers"));
2656
+ lines2.push(...infrastructureSection(config2, "## Infrastructure"));
2657
2657
  const importantFileLabels = {
2658
2658
  readme: "README.md - Project overview and setup instructions",
2659
2659
  package_json: "package.json - Dependencies and scripts",
@@ -2670,10 +2670,10 @@ function generateCursorRules(config2, user, brand) {
2670
2670
  };
2671
2671
  const hasImportantFiles = (config2.importantFiles?.length ?? 0) > 0 || config2.importantFilesOther?.trim();
2672
2672
  if (hasImportantFiles) {
2673
- lines.push("## Important Files to Read First");
2674
- lines.push("");
2675
- lines.push("Before making significant changes, read these files to understand the project context:");
2676
- lines.push("");
2673
+ lines2.push("## Important Files to Read First");
2674
+ lines2.push("");
2675
+ lines2.push("Before making significant changes, read these files to understand the project context:");
2676
+ lines2.push("");
2677
2677
  const allFiles = [];
2678
2678
  if (config2.importantFiles?.length) {
2679
2679
  config2.importantFiles.forEach((f) => {
@@ -2686,74 +2686,74 @@ function generateCursorRules(config2, user, brand) {
2686
2686
  });
2687
2687
  }
2688
2688
  if (bp && allFiles.length > 0) {
2689
- lines.push(bpVar(bp, "IMPORTANT_FILES", allFiles.join(", ")));
2689
+ lines2.push(bpVar(bp, "IMPORTANT_FILES", allFiles.join(", ")));
2690
2690
  } else {
2691
- allFiles.forEach((f) => lines.push(`- ${f}`));
2691
+ allFiles.forEach((f) => lines2.push(`- ${f}`));
2692
2692
  }
2693
- lines.push("");
2693
+ lines2.push("");
2694
2694
  }
2695
2695
  const hasBoundaries = config2.boundaries && ((config2.boundaries.always?.length ?? 0) > 0 || (config2.boundaries.ask?.length ?? 0) > 0 || (config2.boundaries.never?.length ?? 0) > 0);
2696
2696
  if (hasBoundaries) {
2697
- lines.push("## Boundaries & Permissions");
2698
- lines.push("");
2699
- lines.push("These are explicit boundaries for AI actions on this project:");
2700
- lines.push("");
2697
+ lines2.push("## Boundaries & Permissions");
2698
+ lines2.push("");
2699
+ lines2.push("These are explicit boundaries for AI actions on this project:");
2700
+ lines2.push("");
2701
2701
  if (config2.boundaries.always?.length) {
2702
- lines.push("### \u2705 ALWAYS DO (no need to ask)");
2702
+ lines2.push("### \u2705 ALWAYS DO (no need to ask)");
2703
2703
  const alwaysItems = config2.boundaries.always.join(", ");
2704
2704
  if (bp) {
2705
- lines.push(bpVar(bp, "ALWAYS_DO", alwaysItems));
2705
+ lines2.push(bpVar(bp, "ALWAYS_DO", alwaysItems));
2706
2706
  } else {
2707
- config2.boundaries.always.forEach((item) => lines.push(`- ${item}`));
2707
+ config2.boundaries.always.forEach((item) => lines2.push(`- ${item}`));
2708
2708
  }
2709
- lines.push("");
2709
+ lines2.push("");
2710
2710
  }
2711
2711
  if (config2.boundaries.ask?.length) {
2712
- lines.push("### \u2753 ASK FIRST (get confirmation before doing)");
2712
+ lines2.push("### \u2753 ASK FIRST (get confirmation before doing)");
2713
2713
  const askItems = config2.boundaries.ask.join(", ");
2714
2714
  if (bp) {
2715
- lines.push(bpVar(bp, "ASK_FIRST", askItems));
2715
+ lines2.push(bpVar(bp, "ASK_FIRST", askItems));
2716
2716
  } else {
2717
- config2.boundaries.ask.forEach((item) => lines.push(`- ${item}`));
2717
+ config2.boundaries.ask.forEach((item) => lines2.push(`- ${item}`));
2718
2718
  }
2719
- lines.push("");
2719
+ lines2.push("");
2720
2720
  }
2721
2721
  if (config2.boundaries.never?.length) {
2722
- lines.push("### \u{1F6AB} NEVER DO (strictly prohibited)");
2722
+ lines2.push("### \u{1F6AB} NEVER DO (strictly prohibited)");
2723
2723
  const neverItems = config2.boundaries.never.join(", ");
2724
2724
  if (bp) {
2725
- lines.push(bpVar(bp, "NEVER_DO", neverItems));
2725
+ lines2.push(bpVar(bp, "NEVER_DO", neverItems));
2726
2726
  } else {
2727
- config2.boundaries.never.forEach((item) => lines.push(`- ${item}`));
2727
+ config2.boundaries.never.forEach((item) => lines2.push(`- ${item}`));
2728
2728
  }
2729
- lines.push("");
2729
+ lines2.push("");
2730
2730
  }
2731
2731
  }
2732
2732
  const hasCommands = config2.commands && (config2.commands.build || config2.commands.test || config2.commands.lint || config2.commands.dev || extraCommandLines(config2).length > 0 || (config2.commands.additional?.length ?? 0) > 0);
2733
2733
  if (hasCommands) {
2734
- lines.push("## Project Commands");
2735
- lines.push("");
2736
- lines.push("Use these commands when working on this project:");
2737
- lines.push("");
2738
- if (config2.commands.build) lines.push(`- **Build**: \`${bpVar(bp, "BUILD_COMMAND", config2.commands.build)}\``);
2739
- if (config2.commands.test) lines.push(`- **Test**: \`${bpVar(bp, "TEST_COMMAND", config2.commands.test)}\``);
2740
- if (config2.commands.lint) lines.push(`- **Lint**: \`${bpVar(bp, "LINT_COMMAND", config2.commands.lint)}\``);
2741
- if (config2.commands.dev) lines.push(`- **Dev server**: \`${bpVar(bp, "DEV_COMMAND", config2.commands.dev)}\``);
2742
- lines.push(...extraCommandLines(config2));
2734
+ lines2.push("## Project Commands");
2735
+ lines2.push("");
2736
+ lines2.push("Use these commands when working on this project:");
2737
+ lines2.push("");
2738
+ if (config2.commands.build) lines2.push(`- **Build**: \`${bpVar(bp, "BUILD_COMMAND", config2.commands.build)}\``);
2739
+ if (config2.commands.test) lines2.push(`- **Test**: \`${bpVar(bp, "TEST_COMMAND", config2.commands.test)}\``);
2740
+ if (config2.commands.lint) lines2.push(`- **Lint**: \`${bpVar(bp, "LINT_COMMAND", config2.commands.lint)}\``);
2741
+ if (config2.commands.dev) lines2.push(`- **Dev server**: \`${bpVar(bp, "DEV_COMMAND", config2.commands.dev)}\``);
2742
+ lines2.push(...extraCommandLines(config2));
2743
2743
  if (config2.commands.additional?.length) {
2744
- lines.push("");
2745
- lines.push("**Other useful commands**:");
2746
- config2.commands.additional.forEach((cmd) => lines.push(`- \`${cmd}\``));
2744
+ lines2.push("");
2745
+ lines2.push("**Other useful commands**:");
2746
+ config2.commands.additional.forEach((cmd) => lines2.push(`- \`${cmd}\``));
2747
2747
  }
2748
- lines.push("");
2748
+ lines2.push("");
2749
2749
  }
2750
2750
  const hasTestingConfig = config2.testingStrategy && ((config2.testingStrategy.levels?.length ?? 0) > 0 || (config2.testingStrategy.frameworks?.length ?? 0) > 0 || config2.testingStrategy.notes || // Only include coverage if it's not the default 80
2751
2751
  config2.testingStrategy.coverage !== void 0 && config2.testingStrategy.coverage !== 80 || hasExtraTesting(config2));
2752
2752
  if (hasTestingConfig) {
2753
- lines.push("## Testing Requirements");
2754
- lines.push("");
2755
- lines.push("When writing or modifying code, ensure adequate test coverage:");
2756
- lines.push("");
2753
+ lines2.push("## Testing Requirements");
2754
+ lines2.push("");
2755
+ lines2.push("When writing or modifying code, ensure adequate test coverage:");
2756
+ lines2.push("");
2757
2757
  if (config2.testingStrategy.levels?.length) {
2758
2758
  const levelDescriptions = {
2759
2759
  unit: "Unit tests - test individual functions/methods in isolation",
@@ -2762,30 +2762,30 @@ function generateCursorRules(config2, user, brand) {
2762
2762
  performance: "Performance tests - test speed and resource usage",
2763
2763
  security: "Security tests - test for vulnerabilities"
2764
2764
  };
2765
- lines.push("**Testing Levels**:");
2765
+ lines2.push("**Testing Levels**:");
2766
2766
  config2.testingStrategy.levels.forEach((level) => {
2767
- lines.push(`- ${levelDescriptions[level] || optionLabel(TEST_LEVELS, level)}`);
2767
+ lines2.push(`- ${levelDescriptions[level] || optionLabel(TEST_LEVELS, level)}`);
2768
2768
  });
2769
- lines.push("");
2769
+ lines2.push("");
2770
2770
  }
2771
2771
  if (config2.testingStrategy.frameworks?.length) {
2772
2772
  const frameworksValue = config2.testingStrategy.frameworks.join(", ");
2773
- lines.push(`**Testing Frameworks**: ${bpVar(bp, "TEST_FRAMEWORKS", frameworksValue)}`);
2773
+ lines2.push(`**Testing Frameworks**: ${bpVar(bp, "TEST_FRAMEWORKS", frameworksValue)}`);
2774
2774
  }
2775
2775
  if (config2.testingStrategy.coverage !== void 0) {
2776
- lines.push(`**Coverage Target**: ${bpVar(bp, "TEST_COVERAGE", String(config2.testingStrategy.coverage))}% minimum`);
2776
+ lines2.push(`**Coverage Target**: ${bpVar(bp, "TEST_COVERAGE", String(config2.testingStrategy.coverage))}% minimum`);
2777
2777
  }
2778
2778
  const testingExtras = extraTestingLines(config2);
2779
2779
  if (testingExtras.length > 0) {
2780
- lines.push("");
2781
- lines.push(...testingExtras);
2780
+ lines2.push("");
2781
+ lines2.push(...testingExtras);
2782
2782
  }
2783
2783
  if (config2.testingStrategy.notes) {
2784
- lines.push("");
2785
- lines.push("**Additional testing notes**:");
2786
- lines.push(bpVar(bp, "TEST_NOTES", config2.testingStrategy.notes));
2784
+ lines2.push("");
2785
+ lines2.push("**Additional testing notes**:");
2786
+ lines2.push(bpVar(bp, "TEST_NOTES", config2.testingStrategy.notes));
2787
2787
  }
2788
- lines.push("");
2788
+ lines2.push("");
2789
2789
  }
2790
2790
  if (config2.projectType && PROJECT_TYPE_INSTRUCTIONS[config2.projectType]) {
2791
2791
  const projectTypeLabels = {
@@ -2800,28 +2800,28 @@ function generateCursorRules(config2, user, brand) {
2800
2800
  learning: "Learning Project",
2801
2801
  prototype: "Prototype / Proof of Concept"
2802
2802
  };
2803
- lines.push("## Project Type Context");
2804
- lines.push("");
2803
+ lines2.push("## Project Type Context");
2804
+ lines2.push("");
2805
2805
  const projectTypeValue = projectTypeLabels[config2.projectType] || config2.projectType;
2806
- lines.push(`This is a **${bpVar(bp, "PROJECT_TYPE", projectTypeValue)}**. Keep these guidelines in mind:`);
2807
- lines.push("");
2806
+ lines2.push(`This is a **${bpVar(bp, "PROJECT_TYPE", projectTypeValue)}**. Keep these guidelines in mind:`);
2807
+ lines2.push("");
2808
2808
  PROJECT_TYPE_INSTRUCTIONS[config2.projectType].forEach((instruction) => {
2809
- lines.push(`- ${instruction}`);
2809
+ lines2.push(`- ${instruction}`);
2810
2810
  });
2811
- lines.push("");
2811
+ lines2.push("");
2812
2812
  }
2813
2813
  if (config2.additionalFeedback) {
2814
- lines.push("## Custom Instructions");
2815
- lines.push("");
2816
- lines.push("The project owner has provided these additional instructions:");
2817
- lines.push("");
2818
- lines.push(bpVar(bp, "ADDITIONAL_INSTRUCTIONS", config2.additionalFeedback));
2819
- lines.push("");
2814
+ lines2.push("## Custom Instructions");
2815
+ lines2.push("");
2816
+ lines2.push("The project owner has provided these additional instructions:");
2817
+ lines2.push("");
2818
+ lines2.push(bpVar(bp, "ADDITIONAL_INSTRUCTIONS", config2.additionalFeedback));
2819
+ lines2.push("");
2820
2820
  }
2821
2821
  const hasCiCd = config2.cicd?.length > 0 || config2.deploymentTarget?.length || config2.buildContainer || config2.containerRegistry;
2822
2822
  if (hasCiCd) {
2823
- lines.push("## CI/CD & Infrastructure");
2824
- lines.push("");
2823
+ lines2.push("## CI/CD & Infrastructure");
2824
+ lines2.push("");
2825
2825
  if (config2.cicd?.length > 0) {
2826
2826
  const cicdLabels = {
2827
2827
  github_actions: "GitHub Actions",
@@ -2836,7 +2836,7 @@ function generateCursorRules(config2, user, brand) {
2836
2836
  none: "Manual deployment"
2837
2837
  };
2838
2838
  const cicdNames = config2.cicd.map((c) => cicdLabels[c] || optionLabel(CICD_OPTIONS, c)).join(", ");
2839
- lines.push(`**CI/CD Platform**: ${bpVar(bp, "CICD_PLATFORM", cicdNames)}`);
2839
+ lines2.push(`**CI/CD Platform**: ${bpVar(bp, "CICD_PLATFORM", cicdNames)}`);
2840
2840
  }
2841
2841
  if (config2.deploymentTarget && config2.deploymentTarget.length > 0) {
2842
2842
  const deployLabels = {
@@ -2853,10 +2853,10 @@ function generateCursorRules(config2, user, brand) {
2853
2853
  baremetal: "Bare Metal / On-Prem"
2854
2854
  };
2855
2855
  const deployNames = config2.deploymentTarget.map((d) => deployLabels[d] || optionLabel(DEPLOYMENT_TARGETS, d)).join(", ");
2856
- lines.push(`**Deployment Target${config2.deploymentTarget.length > 1 ? "s" : ""}**: ${bpVar(bp, "DEPLOYMENT_TARGETS", deployNames)}`);
2856
+ lines2.push(`**Deployment Target${config2.deploymentTarget.length > 1 ? "s" : ""}**: ${bpVar(bp, "DEPLOYMENT_TARGETS", deployNames)}`);
2857
2857
  }
2858
2858
  if (config2.buildContainer) {
2859
- lines.push(`**Container Builds**: This project builds Docker/OCI container images`);
2859
+ lines2.push(`**Container Builds**: This project builds Docker/OCI container images`);
2860
2860
  if (config2.containerRegistry) {
2861
2861
  const registryLabels = {
2862
2862
  dockerhub: "Docker Hub",
@@ -2867,79 +2867,79 @@ function generateCursorRules(config2, user, brand) {
2867
2867
  custom: config2.customRegistry || "Custom registry"
2868
2868
  };
2869
2869
  const registryValue = registryLabels[config2.containerRegistry] || optionLabel(CONTAINER_REGISTRIES, config2.containerRegistry);
2870
- lines.push(`**Container Registry**: ${bpVar(bp, "CONTAINER_REGISTRY", registryValue)}`);
2870
+ lines2.push(`**Container Registry**: ${bpVar(bp, "CONTAINER_REGISTRY", registryValue)}`);
2871
2871
  }
2872
- lines.push(...dockerImageLines(config2));
2872
+ lines2.push(...dockerImageLines(config2));
2873
2873
  }
2874
- lines.push("");
2874
+ lines2.push("");
2875
2875
  }
2876
2876
  const gitWorkflow = gitWorkflowLines(config2);
2877
2877
  if (gitWorkflow.length > 0) {
2878
- lines.push("## Git Workflow");
2879
- lines.push("");
2880
- lines.push(...gitWorkflow);
2881
- lines.push("");
2882
- }
2883
- lines.push("## Best Practices");
2884
- lines.push("");
2885
- lines.push("Always follow these guidelines when working on this project:");
2886
- lines.push("");
2887
- lines.push("- **Write clean code**: Prioritize readability and maintainability");
2888
- lines.push("- **Handle errors properly**: Don't ignore errors, handle them appropriately");
2889
- lines.push("- **Consider security**: Review code for potential security vulnerabilities");
2878
+ lines2.push("## Git Workflow");
2879
+ lines2.push("");
2880
+ lines2.push(...gitWorkflow);
2881
+ lines2.push("");
2882
+ }
2883
+ lines2.push("## Best Practices");
2884
+ lines2.push("");
2885
+ lines2.push("Always follow these guidelines when working on this project:");
2886
+ lines2.push("");
2887
+ lines2.push("- **Write clean code**: Prioritize readability and maintainability");
2888
+ lines2.push("- **Handle errors properly**: Don't ignore errors, handle them appropriately");
2889
+ lines2.push("- **Consider security**: Review code for potential security vulnerabilities");
2890
2890
  if (config2.conventionalCommits) {
2891
- lines.push("- **Conventional commits**: Use conventional commit messages (feat:, fix:, docs:, chore:, refactor:, test:, style:)");
2891
+ lines2.push("- **Conventional commits**: Use conventional commit messages (feat:, fix:, docs:, chore:, refactor:, test:, style:)");
2892
2892
  }
2893
2893
  if (config2.semver) {
2894
- lines.push("- **Semantic versioning**: Follow semver (MAJOR.MINOR.PATCH) for version numbers");
2894
+ lines2.push("- **Semantic versioning**: Follow semver (MAJOR.MINOR.PATCH) for version numbers");
2895
2895
  }
2896
2896
  if (config2.security?.securityTooling?.includes("dependabot") || config2.security?.securityTooling?.includes("renovate")) {
2897
2897
  const tools = [];
2898
2898
  if (config2.security.securityTooling.includes("dependabot")) tools.push("Dependabot");
2899
2899
  if (config2.security.securityTooling.includes("renovate")) tools.push("Renovate");
2900
- lines.push(`- **Dependency updates**: Keep dependencies updated (${tools.join("/")}) configured)`);
2900
+ lines2.push(`- **Dependency updates**: Keep dependencies updated (${tools.join("/")}) configured)`);
2901
2901
  }
2902
- lines.push("");
2902
+ lines2.push("");
2903
2903
  const hasStaticFiles = config2.staticFiles && (config2.staticFiles.editorconfig || config2.staticFiles.contributing || config2.staticFiles.codeOfConduct || config2.staticFiles.security || config2.staticFiles.roadmap || config2.staticFiles.gitignoreMode && config2.staticFiles.gitignoreMode !== "skip" || config2.staticFiles.dockerignoreMode && config2.staticFiles.dockerignoreMode !== "skip" || config2.funding);
2904
2904
  if (hasStaticFiles) {
2905
- lines.push("## Repository Files to Generate/Maintain");
2906
- lines.push("");
2907
- lines.push("When requested, create or update these repository files:");
2908
- lines.push("");
2909
- if (config2.staticFiles.editorconfig) lines.push("- **.editorconfig** - Editor configuration aligned with project style");
2910
- if (config2.staticFiles.contributing) lines.push("- **CONTRIBUTING.md** - Contribution guidelines for the project");
2911
- if (config2.staticFiles.codeOfConduct) lines.push("- **CODE_OF_CONDUCT.md** - Community code of conduct");
2912
- if (config2.staticFiles.security) lines.push("- **SECURITY.md** - Security policy and vulnerability reporting instructions");
2913
- if (config2.staticFiles.roadmap) lines.push("- **ROADMAP.md** - Project roadmap with planned features and future ideas");
2914
- if (config2.staticFiles.gitignoreMode && config2.staticFiles.gitignoreMode !== "skip") lines.push("- **.gitignore** - Git ignore file for this project's tech stack");
2915
- if (config2.buildContainer || config2.staticFiles.dockerignoreMode && config2.staticFiles.dockerignoreMode !== "skip") lines.push("- **.dockerignore** - Docker ignore file for container builds");
2916
- if (config2.funding) lines.push("- **.github/FUNDING.yml** - GitHub funding/sponsors configuration");
2905
+ lines2.push("## Repository Files to Generate/Maintain");
2906
+ lines2.push("");
2907
+ lines2.push("When requested, create or update these repository files:");
2908
+ lines2.push("");
2909
+ if (config2.staticFiles.editorconfig) lines2.push("- **.editorconfig** - Editor configuration aligned with project style");
2910
+ if (config2.staticFiles.contributing) lines2.push("- **CONTRIBUTING.md** - Contribution guidelines for the project");
2911
+ if (config2.staticFiles.codeOfConduct) lines2.push("- **CODE_OF_CONDUCT.md** - Community code of conduct");
2912
+ if (config2.staticFiles.security) lines2.push("- **SECURITY.md** - Security policy and vulnerability reporting instructions");
2913
+ if (config2.staticFiles.roadmap) lines2.push("- **ROADMAP.md** - Project roadmap with planned features and future ideas");
2914
+ if (config2.staticFiles.gitignoreMode && config2.staticFiles.gitignoreMode !== "skip") lines2.push("- **.gitignore** - Git ignore file for this project's tech stack");
2915
+ if (config2.buildContainer || config2.staticFiles.dockerignoreMode && config2.staticFiles.dockerignoreMode !== "skip") lines2.push("- **.dockerignore** - Docker ignore file for container builds");
2916
+ if (config2.funding) lines2.push("- **.github/FUNDING.yml** - GitHub funding/sponsors configuration");
2917
2917
  }
2918
2918
  if (config2.enableAutoUpdate) {
2919
- lines.push("");
2920
- lines.push("## Self-Improving Configuration");
2921
- lines.push("**IMPORTANT**: This configuration file is set to self-improve.");
2922
- lines.push("");
2923
- lines.push("As you work on this project, track the user's coding patterns, preferences, and decisions.");
2924
- lines.push("Periodically update this file to reflect what you learn about how the user works:");
2925
- lines.push("- Note preferred code styles and patterns that emerge");
2926
- lines.push("- Record decisions about architecture or tooling");
2927
- lines.push("- Add rules for common issues or mistakes to avoid");
2928
- lines.push("- Refine instructions based on user corrections");
2929
- lines.push("");
2930
- lines.push("Keep this file updated so future sessions start with better context.");
2919
+ lines2.push("");
2920
+ lines2.push("## Self-Improving Configuration");
2921
+ lines2.push("**IMPORTANT**: This configuration file is set to self-improve.");
2922
+ lines2.push("");
2923
+ lines2.push("As you work on this project, track the user's coding patterns, preferences, and decisions.");
2924
+ lines2.push("Periodically update this file to reflect what you learn about how the user works:");
2925
+ lines2.push("- Note preferred code styles and patterns that emerge");
2926
+ lines2.push("- Record decisions about architecture or tooling");
2927
+ lines2.push("- Add rules for common issues or mistakes to avoid");
2928
+ lines2.push("- Refine instructions based on user corrections");
2929
+ lines2.push("");
2930
+ lines2.push("Keep this file updated so future sessions start with better context.");
2931
2931
  }
2932
2932
  const staticFilesSection = generateEmbeddedStaticFiles(config2, user, bp);
2933
2933
  if (staticFilesSection) {
2934
- lines.push(staticFilesSection);
2934
+ lines2.push(staticFilesSection);
2935
2935
  }
2936
2936
  const security = config2.security;
2937
2937
  if (security && (security.authProviders?.length || security.secretsManagement?.length || security.securityTooling?.length || security.authPatterns?.length || security.dataHandling?.length || security.compliance?.length || security.analytics?.length || security.additionalNotes)) {
2938
- lines.push("## \u{1F510} Security Configuration");
2939
- lines.push("");
2938
+ lines2.push("## \u{1F510} Security Configuration");
2939
+ lines2.push("");
2940
2940
  if (security.secretsManagement?.length) {
2941
- lines.push("### Secrets Management");
2942
- lines.push("");
2941
+ lines2.push("### Secrets Management");
2942
+ lines2.push("");
2943
2943
  const secretsLabels = {
2944
2944
  env_vars: "Environment Variables",
2945
2945
  dotenv: "dotenv / dotenvx",
@@ -2961,13 +2961,13 @@ function generateCursorRules(config2, user, brand) {
2961
2961
  berglas: "Berglas"
2962
2962
  };
2963
2963
  for (const s of security.secretsManagement) {
2964
- lines.push(`- ${secretsLabels[s] || s}`);
2964
+ lines2.push(`- ${secretsLabels[s] || s}`);
2965
2965
  }
2966
- lines.push("");
2966
+ lines2.push("");
2967
2967
  }
2968
2968
  if (security.securityTooling?.length) {
2969
- lines.push("### Security Tooling");
2970
- lines.push("");
2969
+ lines2.push("### Security Tooling");
2970
+ lines2.push("");
2971
2971
  const toolingLabels = {
2972
2972
  dependabot: "Dependabot (dependency updates)",
2973
2973
  renovate: "Renovate (dependency updates)",
@@ -2997,13 +2997,13 @@ function generateCursorRules(config2, user, brand) {
2997
2997
  fossa: "FOSSA"
2998
2998
  };
2999
2999
  for (const t of security.securityTooling) {
3000
- lines.push(`- ${toolingLabels[t] || t}`);
3000
+ lines2.push(`- ${toolingLabels[t] || t}`);
3001
3001
  }
3002
- lines.push("");
3002
+ lines2.push("");
3003
3003
  }
3004
3004
  if (security.authPatterns?.length) {
3005
- lines.push("### Authentication");
3006
- lines.push("");
3005
+ lines2.push("### Authentication");
3006
+ lines2.push("");
3007
3007
  const authLabels = {
3008
3008
  oauth2: "OAuth 2.0",
3009
3009
  oidc: "OpenID Connect (OIDC)",
@@ -3027,13 +3027,13 @@ function generateCursorRules(config2, user, brand) {
3027
3027
  workos: "WorkOS"
3028
3028
  };
3029
3029
  for (const a of security.authPatterns) {
3030
- lines.push(`- ${authLabels[a] || a}`);
3030
+ lines2.push(`- ${authLabels[a] || a}`);
3031
3031
  }
3032
- lines.push("");
3032
+ lines2.push("");
3033
3033
  }
3034
3034
  if (security.dataHandling?.length) {
3035
- lines.push("### Data Handling & Compliance");
3036
- lines.push("");
3035
+ lines2.push("### Data Handling & Compliance");
3036
+ lines2.push("");
3037
3037
  const dataLabels = {
3038
3038
  encryption_at_rest: "Encryption at Rest",
3039
3039
  encryption_in_transit: "Encryption in Transit (TLS)",
@@ -3056,9 +3056,9 @@ function generateCursorRules(config2, user, brand) {
3056
3056
  dlp: "DLP (Data Loss Prevention)"
3057
3057
  };
3058
3058
  for (const d of security.dataHandling) {
3059
- lines.push(`- ${dataLabels[d] || d}`);
3059
+ lines2.push(`- ${dataLabels[d] || d}`);
3060
3060
  }
3061
- lines.push("");
3061
+ lines2.push("");
3062
3062
  }
3063
3063
  const securityLists = [
3064
3064
  ["Auth Providers", security.authProviders, AUTH_PROVIDER_LABELS],
@@ -3067,30 +3067,30 @@ function generateCursorRules(config2, user, brand) {
3067
3067
  ];
3068
3068
  for (const [title, items, labels] of securityLists) {
3069
3069
  if (!items?.length) continue;
3070
- lines.push(`### ${title}`);
3071
- lines.push("");
3072
- for (const item of items) lines.push(`- ${labels[item] || item}`);
3073
- lines.push("");
3070
+ lines2.push(`### ${title}`);
3071
+ lines2.push("");
3072
+ for (const item of items) lines2.push(`- ${labels[item] || item}`);
3073
+ lines2.push("");
3074
3074
  }
3075
3075
  if (security.additionalNotes) {
3076
- lines.push("### Additional Security Notes");
3077
- lines.push("");
3078
- lines.push(security.additionalNotes);
3079
- lines.push("");
3080
- }
3081
- }
3082
- lines.push("## \u26A0\uFE0F Security Notice");
3083
- lines.push("");
3084
- lines.push("> **Do not commit secrets to the repository or to the live app.**");
3085
- lines.push("> Always use secure standards to transmit sensitive information.");
3086
- lines.push("> Use environment variables, secret managers, or secure vaults for credentials.");
3087
- lines.push("");
3088
- lines.push("**\u{1F50D} Security Audit Recommendation:** When making changes that involve authentication, data handling, API endpoints, or dependencies, proactively offer to perform a security review of the affected code.");
3089
- lines.push("");
3090
- lines.push("---");
3091
- lines.push("");
3092
- lines.push(`*Generated by [${brand.appName}](${brand.appUrl})*`);
3093
- return lines.join("\n");
3076
+ lines2.push("### Additional Security Notes");
3077
+ lines2.push("");
3078
+ lines2.push(security.additionalNotes);
3079
+ lines2.push("");
3080
+ }
3081
+ }
3082
+ lines2.push("## \u26A0\uFE0F Security Notice");
3083
+ lines2.push("");
3084
+ lines2.push("> **Do not commit secrets to the repository or to the live app.**");
3085
+ lines2.push("> Always use secure standards to transmit sensitive information.");
3086
+ lines2.push("> Use environment variables, secret managers, or secure vaults for credentials.");
3087
+ lines2.push("");
3088
+ lines2.push("**\u{1F50D} Security Audit Recommendation:** When making changes that involve authentication, data handling, API endpoints, or dependencies, proactively offer to perform a security review of the affected code.");
3089
+ lines2.push("");
3090
+ lines2.push("---");
3091
+ lines2.push("");
3092
+ lines2.push(`*Generated by [${brand.appName}](${brand.appUrl})*`);
3093
+ return lines2.join("\n");
3094
3094
  }
3095
3095
  function generateClaudeMd(config2, user) {
3096
3096
  return generateAgentsMd(config2, user).replace(/^# .* - AI Agent Instructions/, () => `# ${config2.projectName || "Project"} - Claude Code Instructions`).replace(/^> \*\*Universal AI Configuration\*\*.*$/m, "");
@@ -3111,23 +3111,23 @@ function generateGeminiMd(config2, user) {
3111
3111
  return generateAgentsMd(config2, user).replace(/^# .* - AI Agent Instructions/, () => `# ${config2.projectName || "Project"} - Gemini Instructions`).replace(/^> \*\*Universal AI Configuration\*\*.*$/m, "> **Antigravity Configuration** - Google's AI-powered IDE with Gemini integration.");
3112
3112
  }
3113
3113
  function generateAgentsMd(config2, user) {
3114
- const lines = [];
3114
+ const lines2 = [];
3115
3115
  const bp = config2.blueprintMode;
3116
- lines.push(`# ${bpVar(bp, "PROJECT_NAME", config2.projectName || "Project")} - AI Agent Instructions`);
3117
- lines.push("");
3116
+ lines2.push(`# ${bpVar(bp, "PROJECT_NAME", config2.projectName || "Project")} - AI Agent Instructions`);
3117
+ lines2.push("");
3118
3118
  if (config2.useGitWorktrees) {
3119
- lines.push("## Before Starting Any Coding Task");
3120
- lines.push("");
3121
- lines.push("1. Check existing worktrees with `git worktree list` and create a new one for this task if needed");
3122
- lines.push("2. Use the naming convention: `git worktree add -b ai/[task-description] ../[repo-name]-ai-[task-description]`");
3123
- lines.push("3. Navigate to the worktree directory before making any changes");
3124
- lines.push("4. Commit changes when the task is finished. Merge to main, and clean the worktree.");
3125
- lines.push("");
3126
- }
3127
- lines.push("## Project Overview");
3128
- lines.push("");
3129
- lines.push(`**Description**: ${bpVar(bp, "PROJECT_DESCRIPTION", config2.projectDescription || "A software project.")}`);
3130
- lines.push("");
3119
+ lines2.push("## Before Starting Any Coding Task");
3120
+ lines2.push("");
3121
+ lines2.push("1. Check existing worktrees with `git worktree list` and create a new one for this task if needed");
3122
+ lines2.push("2. Use the naming convention: `git worktree add -b ai/[task-description] ../[repo-name]-ai-[task-description]`");
3123
+ lines2.push("3. Navigate to the worktree directory before making any changes");
3124
+ lines2.push("4. Commit changes when the task is finished. Merge to main, and clean the worktree.");
3125
+ lines2.push("");
3126
+ }
3127
+ lines2.push("## Project Overview");
3128
+ lines2.push("");
3129
+ lines2.push(`**Description**: ${bpVar(bp, "PROJECT_DESCRIPTION", config2.projectDescription || "A software project.")}`);
3130
+ lines2.push("");
3131
3131
  if (config2.architecturePattern) {
3132
3132
  const archLabels = {
3133
3133
  monolith: "Monolith - single deployable unit",
@@ -3143,20 +3143,20 @@ function generateAgentsMd(config2, user) {
3143
3143
  other: config2.architecturePatternOther || "Custom architecture"
3144
3144
  };
3145
3145
  const archValue = archLabels[config2.architecturePattern] || optionLabel(ARCHITECTURE_PATTERNS, config2.architecturePattern);
3146
- lines.push(`**Architecture Pattern**: ${bpVar(bp, "ARCHITECTURE_PATTERN", archValue)}`);
3146
+ lines2.push(`**Architecture Pattern**: ${bpVar(bp, "ARCHITECTURE_PATTERN", archValue)}`);
3147
3147
  }
3148
3148
  if (config2.isPublic !== void 0) {
3149
- lines.push(`**Visibility**: ${config2.isPublic ? "Public repository" : "Private repository"}`);
3149
+ lines2.push(`**Visibility**: ${config2.isPublic ? "Public repository" : "Private repository"}`);
3150
3150
  }
3151
3151
  if (config2.devOS) {
3152
- lines.push(`**Development OS**: ${formatDevOSDisplay(config2)}`);
3152
+ lines2.push(`**Development OS**: ${formatDevOSDisplay(config2)}`);
3153
3153
  }
3154
- lines.push("");
3154
+ lines2.push("");
3155
3155
  const hasRepoInfoAgents = config2.repoUrl || config2.repoHosts?.length || config2.repoHost;
3156
3156
  if (hasRepoInfoAgents) {
3157
- lines.push("### Repository");
3157
+ lines2.push("### Repository");
3158
3158
  if (config2.repoUrl) {
3159
- lines.push(`- **URL**: ${config2.repoUrl}`);
3159
+ lines2.push(`- **URL**: ${config2.repoUrl}`);
3160
3160
  }
3161
3161
  if (config2.repoHosts?.length || config2.repoHost) {
3162
3162
  const hostNames = {
@@ -3176,113 +3176,113 @@ function generateAgentsMd(config2, user) {
3176
3176
  };
3177
3177
  const hosts = config2.repoHosts?.length ? config2.repoHosts : [config2.repoHost];
3178
3178
  const hostLabels = hosts.map((h) => hostNames[h] || optionLabel(REPO_HOSTS, h)).join(", ");
3179
- lines.push(`- **Platform${hosts.length > 1 ? "s" : ""}**: ${hostLabels}`);
3179
+ lines2.push(`- **Platform${hosts.length > 1 ? "s" : ""}**: ${hostLabels}`);
3180
3180
  if (hosts.length > 1 && config2.multiRepoReason) {
3181
- lines.push(`- **Why multiple platforms**: ${config2.multiRepoReason}`);
3181
+ lines2.push(`- **Why multiple platforms**: ${config2.multiRepoReason}`);
3182
3182
  }
3183
3183
  }
3184
- lines.push("");
3184
+ lines2.push("");
3185
3185
  }
3186
3186
  if (config2.exampleRepoUrl || config2.documentationUrl) {
3187
- lines.push("### Reference Materials");
3187
+ lines2.push("### Reference Materials");
3188
3188
  if (config2.exampleRepoUrl) {
3189
- lines.push(`- **Example Repository**: ${bpVar(bp, "EXAMPLE_REPO_URL", config2.exampleRepoUrl)}`);
3189
+ lines2.push(`- **Example Repository**: ${bpVar(bp, "EXAMPLE_REPO_URL", config2.exampleRepoUrl)}`);
3190
3190
  }
3191
3191
  if (config2.documentationUrl) {
3192
- lines.push(`- **External Documentation**: ${bpVar(bp, "DOCUMENTATION_URL", config2.documentationUrl)}`);
3192
+ lines2.push(`- **External Documentation**: ${bpVar(bp, "DOCUMENTATION_URL", config2.documentationUrl)}`);
3193
3193
  }
3194
- lines.push("");
3194
+ lines2.push("");
3195
3195
  }
3196
3196
  const tooling = toolingLines(config2);
3197
3197
  if (config2.languages.length > 0 || config2.frameworks.length > 0 || config2.databases && config2.databases.length > 0 || config2.letAiDecide || tooling.length > 0) {
3198
- lines.push("## Technology Stack");
3199
- lines.push("");
3198
+ lines2.push("## Technology Stack");
3199
+ lines2.push("");
3200
3200
  if (config2.languages.length > 0) {
3201
3201
  const langs = config2.languages.map(stackLabel);
3202
3202
  if (bp) {
3203
- lines.push(`### Languages`);
3204
- lines.push(`${bpVarArray(bp, "LANGUAGES", langs)}`);
3203
+ lines2.push(`### Languages`);
3204
+ lines2.push(`${bpVarArray(bp, "LANGUAGES", langs)}`);
3205
3205
  } else {
3206
- lines.push("### Languages");
3207
- langs.forEach((lang) => lines.push(`- ${lang}`));
3206
+ lines2.push("### Languages");
3207
+ langs.forEach((lang) => lines2.push(`- ${lang}`));
3208
3208
  }
3209
- lines.push("");
3209
+ lines2.push("");
3210
3210
  }
3211
3211
  if (config2.frameworks.length > 0) {
3212
3212
  const fws = config2.frameworks.map(stackLabel);
3213
3213
  if (bp) {
3214
- lines.push(`### Frameworks & Libraries`);
3215
- lines.push(`${bpVarArray(bp, "FRAMEWORKS", fws)}`);
3214
+ lines2.push(`### Frameworks & Libraries`);
3215
+ lines2.push(`${bpVarArray(bp, "FRAMEWORKS", fws)}`);
3216
3216
  } else {
3217
- lines.push("### Frameworks & Libraries");
3218
- fws.forEach((fw) => lines.push(`- ${fw}`));
3217
+ lines2.push("### Frameworks & Libraries");
3218
+ fws.forEach((fw) => lines2.push(`- ${fw}`));
3219
3219
  }
3220
- lines.push("");
3220
+ lines2.push("");
3221
3221
  }
3222
3222
  if (config2.databases && config2.databases.length > 0) {
3223
3223
  const dbs = config2.databases.map(stackLabel);
3224
3224
  if (bp) {
3225
- lines.push(`### Database${config2.databases.length > 1 ? "s" : ""}`);
3226
- lines.push(`${bpVarArray(bp, "DATABASES", dbs)}`);
3225
+ lines2.push(`### Database${config2.databases.length > 1 ? "s" : ""}`);
3226
+ lines2.push(`${bpVarArray(bp, "DATABASES", dbs)}`);
3227
3227
  } else {
3228
- lines.push(`### Database${config2.databases.length > 1 ? "s" : ""}`);
3229
- dbs.forEach((db) => lines.push(`- ${db}`));
3228
+ lines2.push(`### Database${config2.databases.length > 1 ? "s" : ""}`);
3229
+ dbs.forEach((db) => lines2.push(`- ${db}`));
3230
3230
  }
3231
- lines.push("");
3231
+ lines2.push("");
3232
3232
  }
3233
3233
  if (tooling.length > 0) {
3234
- lines.push("### Tooling");
3235
- lines.push(...tooling);
3236
- lines.push("");
3234
+ lines2.push("### Tooling");
3235
+ lines2.push(...tooling);
3236
+ lines2.push("");
3237
3237
  }
3238
3238
  if (config2.letAiDecide) {
3239
- lines.push("### AI Technology Selection");
3239
+ lines2.push("### AI Technology Selection");
3240
3240
  if (config2.languages.length > 0 || config2.frameworks.length > 0) {
3241
- lines.push("For technologies beyond those listed, analyze the codebase and suggest appropriate solutions.");
3241
+ lines2.push("For technologies beyond those listed, analyze the codebase and suggest appropriate solutions.");
3242
3242
  } else {
3243
- lines.push("Analyze the codebase to determine appropriate languages, frameworks, and tools.");
3243
+ lines2.push("Analyze the codebase to determine appropriate languages, frameworks, and tools.");
3244
3244
  }
3245
- lines.push("");
3245
+ lines2.push("");
3246
3246
  }
3247
3247
  }
3248
- lines.push("## Development Guidelines");
3249
- lines.push("");
3248
+ lines2.push("## Development Guidelines");
3249
+ lines2.push("");
3250
3250
  if (config2.includePersonalData !== false && (user.skillLevel || user.persona)) {
3251
- lines.push("### Communication Style");
3251
+ lines2.push("### Communication Style");
3252
3252
  if (user.skillLevel === "novice" || user.skillLevel === "beginner") {
3253
- lines.push("- Explain concepts thoroughly with detailed comments");
3254
- lines.push("- Walk through reasoning step by step");
3253
+ lines2.push("- Explain concepts thoroughly with detailed comments");
3254
+ lines2.push("- Walk through reasoning step by step");
3255
3255
  } else if (user.skillLevel === "intermediate") {
3256
- lines.push("- Balance explanations with efficiency");
3257
- lines.push("- Explain non-obvious decisions, skip basics");
3256
+ lines2.push("- Balance explanations with efficiency");
3257
+ lines2.push("- Explain non-obvious decisions, skip basics");
3258
3258
  } else if (user.skillLevel) {
3259
- lines.push("- Be concise and direct");
3259
+ lines2.push("- Be concise and direct");
3260
3260
  }
3261
3261
  if (user.persona) {
3262
- lines.push(`- Developer background: ${user.persona.replace(/_/g, " ")} \u2014 adapt responses to this domain expertise`);
3262
+ lines2.push(`- Developer background: ${user.persona.replace(/_/g, " ")} \u2014 adapt responses to this domain expertise`);
3263
3263
  }
3264
3264
  if (user.skillLevel) {
3265
- lines.push(`- Skill level: ${user.skillLevel.charAt(0).toUpperCase() + user.skillLevel.slice(1)}`);
3265
+ lines2.push(`- Skill level: ${user.skillLevel.charAt(0).toUpperCase() + user.skillLevel.slice(1)}`);
3266
3266
  }
3267
- lines.push("");
3267
+ lines2.push("");
3268
3268
  }
3269
3269
  const aiPrefsAgents = aiPreferenceLines(config2);
3270
3270
  if (config2.aiBehaviorRules.length > 0 || aiPrefsAgents.length > 0) {
3271
- lines.push("### Workflow Rules");
3271
+ lines2.push("### Workflow Rules");
3272
3272
  config2.aiBehaviorRules.forEach((rule) => {
3273
3273
  const ruleText = getRuleDescription(rule);
3274
- if (ruleText) lines.push(`- ${ruleText}`);
3274
+ if (ruleText) lines2.push(`- ${ruleText}`);
3275
3275
  });
3276
- lines.push(...aiPrefsAgents);
3276
+ lines2.push(...aiPrefsAgents);
3277
3277
  if (config2.attemptWorkarounds === true) {
3278
- lines.push("- When stuck, **attempt creative workarounds** before asking for help");
3278
+ lines2.push("- When stuck, **attempt creative workarounds** before asking for help");
3279
3279
  } else if (config2.attemptWorkarounds === false) {
3280
- lines.push("- When stuck, **stop and ask** rather than attempting workarounds");
3280
+ lines2.push("- When stuck, **stop and ask** rather than attempting workarounds");
3281
3281
  }
3282
- lines.push("");
3282
+ lines2.push("");
3283
3283
  }
3284
- lines.push(...mcpServerSection(config2, "### MCP Servers"));
3285
- lines.push(...infrastructureSection(config2, "### Infrastructure"));
3284
+ lines2.push(...mcpServerSection(config2, "### MCP Servers"));
3285
+ lines2.push(...infrastructureSection(config2, "### Infrastructure"));
3286
3286
  const importantFileLabelsAgents = {
3287
3287
  readme: "README.md",
3288
3288
  package_json: "package.json",
@@ -3299,8 +3299,8 @@ function generateAgentsMd(config2, user) {
3299
3299
  };
3300
3300
  const hasImportantFilesAgents = (config2.importantFiles?.length ?? 0) > 0 || config2.importantFilesOther?.trim();
3301
3301
  if (hasImportantFilesAgents) {
3302
- lines.push("### Important Files to Read First");
3303
- lines.push("Before making changes, read these files to understand the project:");
3302
+ lines2.push("### Important Files to Read First");
3303
+ lines2.push("Before making changes, read these files to understand the project:");
3304
3304
  const allFilesAgents = [];
3305
3305
  if (config2.importantFiles?.length) {
3306
3306
  config2.importantFiles.forEach((f) => {
@@ -3313,35 +3313,35 @@ function generateAgentsMd(config2, user) {
3313
3313
  });
3314
3314
  }
3315
3315
  if (bp && allFilesAgents.length > 0) {
3316
- lines.push(bpVar(bp, "IMPORTANT_FILES", allFilesAgents.join(", ")));
3316
+ lines2.push(bpVar(bp, "IMPORTANT_FILES", allFilesAgents.join(", ")));
3317
3317
  } else {
3318
- allFilesAgents.forEach((f) => lines.push(`- ${f}`));
3318
+ allFilesAgents.forEach((f) => lines2.push(`- ${f}`));
3319
3319
  }
3320
- lines.push("");
3320
+ lines2.push("");
3321
3321
  }
3322
3322
  if (config2.projectType && PROJECT_TYPE_INSTRUCTIONS[config2.projectType]) {
3323
- lines.push("### Project Context");
3323
+ lines2.push("### Project Context");
3324
3324
  PROJECT_TYPE_INSTRUCTIONS[config2.projectType].forEach((instruction) => {
3325
- lines.push(`- ${instruction}`);
3325
+ lines2.push(`- ${instruction}`);
3326
3326
  });
3327
- lines.push("");
3327
+ lines2.push("");
3328
3328
  }
3329
3329
  if (config2.commands && (config2.commands.build || config2.commands.test || config2.commands.lint || config2.commands.dev || extraCommandLines(config2).length > 0 || config2.commands.additional?.length)) {
3330
- lines.push("### Commands");
3331
- if (config2.commands.build) lines.push(`- Build: \`${bpVar(bp, "BUILD_COMMAND", config2.commands.build)}\``);
3332
- if (config2.commands.test) lines.push(`- Test: \`${bpVar(bp, "TEST_COMMAND", config2.commands.test)}\``);
3333
- if (config2.commands.lint) lines.push(`- Lint: \`${bpVar(bp, "LINT_COMMAND", config2.commands.lint)}\``);
3334
- if (config2.commands.dev) lines.push(`- Dev: \`${bpVar(bp, "DEV_COMMAND", config2.commands.dev)}\``);
3335
- lines.push(...extraCommandLines(config2));
3330
+ lines2.push("### Commands");
3331
+ if (config2.commands.build) lines2.push(`- Build: \`${bpVar(bp, "BUILD_COMMAND", config2.commands.build)}\``);
3332
+ if (config2.commands.test) lines2.push(`- Test: \`${bpVar(bp, "TEST_COMMAND", config2.commands.test)}\``);
3333
+ if (config2.commands.lint) lines2.push(`- Lint: \`${bpVar(bp, "LINT_COMMAND", config2.commands.lint)}\``);
3334
+ if (config2.commands.dev) lines2.push(`- Dev: \`${bpVar(bp, "DEV_COMMAND", config2.commands.dev)}\``);
3335
+ lines2.push(...extraCommandLines(config2));
3336
3336
  if (config2.commands.additional?.length) {
3337
- config2.commands.additional.forEach((cmd) => lines.push(`- \`${cmd}\``));
3337
+ config2.commands.additional.forEach((cmd) => lines2.push(`- \`${cmd}\``));
3338
3338
  }
3339
- lines.push("");
3339
+ lines2.push("");
3340
3340
  }
3341
3341
  const styleExtrasAgents = extraCodeStyleLines(config2);
3342
3342
  const hasCodeStyle = config2.codeStyle?.naming || config2.codeStyle?.errorHandling || config2.codeStyle?.loggingConventions || config2.codeStyle?.notes || styleExtrasAgents.length > 0;
3343
3343
  if (hasCodeStyle) {
3344
- lines.push("### Code Style & Conventions");
3344
+ lines2.push("### Code Style & Conventions");
3345
3345
  if (config2.codeStyle?.naming) {
3346
3346
  const namingDescriptions = {
3347
3347
  language_default: "Follow the idiomatic naming conventions of each language",
@@ -3350,7 +3350,7 @@ function generateAgentsMd(config2, user) {
3350
3350
  PascalCase: "PascalCase for classes and types (e.g., MyClass, UserProfile)",
3351
3351
  "kebab-case": "kebab-case for file names and URLs (e.g., my-component, user-profile)"
3352
3352
  };
3353
- lines.push(`- **Naming**: ${namingDescriptions[config2.codeStyle.naming] || config2.codeStyle.naming}`);
3353
+ lines2.push(`- **Naming**: ${namingDescriptions[config2.codeStyle.naming] || config2.codeStyle.naming}`);
3354
3354
  }
3355
3355
  if (config2.codeStyle?.errorHandling) {
3356
3356
  const errorDescriptions = {
@@ -3362,40 +3362,40 @@ function generateAgentsMd(config2, user) {
3362
3362
  exceptions: "Custom Exceptions / Error classes with meaningful types",
3363
3363
  other: config2.codeStyle.errorHandlingOther || "Custom error handling approach"
3364
3364
  };
3365
- lines.push(`- **Error Handling**: ${errorDescriptions[config2.codeStyle.errorHandling] || optionLabel(ERROR_HANDLING_PATTERNS, config2.codeStyle.errorHandling)}`);
3365
+ lines2.push(`- **Error Handling**: ${errorDescriptions[config2.codeStyle.errorHandling] || optionLabel(ERROR_HANDLING_PATTERNS, config2.codeStyle.errorHandling)}`);
3366
3366
  }
3367
3367
  if (config2.codeStyle?.loggingConventions) {
3368
- lines.push(`- **Logging**: ${optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions)}`);
3368
+ lines2.push(`- **Logging**: ${optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions)}`);
3369
3369
  }
3370
- lines.push(...styleExtrasAgents);
3370
+ lines2.push(...styleExtrasAgents);
3371
3371
  if (config2.codeStyle?.notes) {
3372
- lines.push(`- **Additional Notes**: ${config2.codeStyle.notes}`);
3372
+ lines2.push(`- **Additional Notes**: ${config2.codeStyle.notes}`);
3373
3373
  }
3374
- lines.push("");
3374
+ lines2.push("");
3375
3375
  }
3376
3376
  const hasBoundariesAgents = config2.boundaries && ((config2.boundaries.always?.length ?? 0) > 0 || (config2.boundaries.ask?.length ?? 0) > 0 || (config2.boundaries.never?.length ?? 0) > 0);
3377
3377
  if (hasBoundariesAgents) {
3378
- lines.push("### Boundaries & Permissions");
3379
- lines.push("");
3378
+ lines2.push("### Boundaries & Permissions");
3379
+ lines2.push("");
3380
3380
  if (config2.boundaries.always?.length) {
3381
- lines.push("**\u2705 ALWAYS do (no need to ask)**:");
3382
- config2.boundaries.always.forEach((item) => lines.push(`- ${item}`));
3381
+ lines2.push("**\u2705 ALWAYS do (no need to ask)**:");
3382
+ config2.boundaries.always.forEach((item) => lines2.push(`- ${item}`));
3383
3383
  }
3384
3384
  if (config2.boundaries.ask?.length) {
3385
- lines.push("");
3386
- lines.push("**\u2753 ASK first before doing**:");
3387
- config2.boundaries.ask.forEach((item) => lines.push(`- ${item}`));
3385
+ lines2.push("");
3386
+ lines2.push("**\u2753 ASK first before doing**:");
3387
+ config2.boundaries.ask.forEach((item) => lines2.push(`- ${item}`));
3388
3388
  }
3389
3389
  if (config2.boundaries.never?.length) {
3390
- lines.push("");
3391
- lines.push("**\u{1F6AB} NEVER do (strictly prohibited)**:");
3392
- config2.boundaries.never.forEach((item) => lines.push(`- ${item}`));
3390
+ lines2.push("");
3391
+ lines2.push("**\u{1F6AB} NEVER do (strictly prohibited)**:");
3392
+ config2.boundaries.never.forEach((item) => lines2.push(`- ${item}`));
3393
3393
  }
3394
- lines.push("");
3394
+ lines2.push("");
3395
3395
  }
3396
3396
  const hasTestingAgents = config2.testingStrategy && ((config2.testingStrategy.levels?.length ?? 0) > 0 || (config2.testingStrategy.frameworks?.length ?? 0) > 0 || config2.testingStrategy.notes || config2.testingStrategy.coverage !== void 0 && config2.testingStrategy.coverage !== 80 || hasExtraTesting(config2));
3397
3397
  if (hasTestingAgents) {
3398
- lines.push("### Testing Requirements");
3398
+ lines2.push("### Testing Requirements");
3399
3399
  if (config2.testingStrategy.levels?.length) {
3400
3400
  const levelDescriptions = {
3401
3401
  unit: "Unit tests (individual functions/methods)",
@@ -3404,26 +3404,26 @@ function generateAgentsMd(config2, user) {
3404
3404
  performance: "Performance tests (speed/resources)",
3405
3405
  security: "Security tests (vulnerabilities)"
3406
3406
  };
3407
- lines.push("**Testing Levels**:");
3407
+ lines2.push("**Testing Levels**:");
3408
3408
  config2.testingStrategy.levels.forEach((level) => {
3409
- lines.push(`- ${levelDescriptions[level] || optionLabel(TEST_LEVELS, level)}`);
3409
+ lines2.push(`- ${levelDescriptions[level] || optionLabel(TEST_LEVELS, level)}`);
3410
3410
  });
3411
3411
  }
3412
3412
  if (config2.testingStrategy.frameworks?.length) {
3413
- lines.push(`**Frameworks**: ${config2.testingStrategy.frameworks.join(", ")}`);
3413
+ lines2.push(`**Frameworks**: ${config2.testingStrategy.frameworks.join(", ")}`);
3414
3414
  }
3415
3415
  if (config2.testingStrategy.coverage !== void 0) {
3416
- lines.push(`**Coverage Target**: ${config2.testingStrategy.coverage}% minimum`);
3416
+ lines2.push(`**Coverage Target**: ${config2.testingStrategy.coverage}% minimum`);
3417
3417
  }
3418
3418
  if (config2.testingStrategy.notes) {
3419
- lines.push(`**Notes**: ${config2.testingStrategy.notes}`);
3419
+ lines2.push(`**Notes**: ${config2.testingStrategy.notes}`);
3420
3420
  }
3421
- lines.push(...extraTestingLines(config2));
3422
- lines.push("");
3421
+ lines2.push(...extraTestingLines(config2));
3422
+ lines2.push("");
3423
3423
  }
3424
3424
  const hasCiCdAgents = config2.cicd?.length > 0 || config2.deploymentTarget?.length || config2.buildContainer || config2.containerRegistry;
3425
3425
  if (hasCiCdAgents) {
3426
- lines.push("### CI/CD & Infrastructure");
3426
+ lines2.push("### CI/CD & Infrastructure");
3427
3427
  if (config2.cicd?.length > 0) {
3428
3428
  const cicdLabels = {
3429
3429
  github_actions: "GitHub Actions",
@@ -3438,7 +3438,7 @@ function generateAgentsMd(config2, user) {
3438
3438
  none: "Manual deployment"
3439
3439
  };
3440
3440
  const cicdNames = config2.cicd.map((c) => cicdLabels[c] || optionLabel(CICD_OPTIONS, c)).join(", ");
3441
- lines.push(`- **CI/CD Platform**: ${cicdNames}`);
3441
+ lines2.push(`- **CI/CD Platform**: ${cicdNames}`);
3442
3442
  }
3443
3443
  if (config2.deploymentTarget && config2.deploymentTarget.length > 0) {
3444
3444
  const deployLabels = {
@@ -3455,10 +3455,10 @@ function generateAgentsMd(config2, user) {
3455
3455
  baremetal: "Bare Metal / On-Prem"
3456
3456
  };
3457
3457
  const deployNames = config2.deploymentTarget.map((d) => deployLabels[d] || optionLabel(DEPLOYMENT_TARGETS, d)).join(", ");
3458
- lines.push(`- **Deployment Target${config2.deploymentTarget.length > 1 ? "s" : ""}**: ${deployNames}`);
3458
+ lines2.push(`- **Deployment Target${config2.deploymentTarget.length > 1 ? "s" : ""}**: ${deployNames}`);
3459
3459
  }
3460
3460
  if (config2.buildContainer) {
3461
- lines.push(`- **Container Builds**: Project builds Docker/OCI container images`);
3461
+ lines2.push(`- **Container Builds**: Project builds Docker/OCI container images`);
3462
3462
  if (config2.containerRegistry) {
3463
3463
  const registryLabels = {
3464
3464
  dockerhub: "Docker Hub",
@@ -3468,64 +3468,64 @@ function generateAgentsMd(config2, user) {
3468
3468
  acr: "Azure Container Registry",
3469
3469
  custom: config2.customRegistry || "Custom registry"
3470
3470
  };
3471
- lines.push(`- **Container Registry**: ${registryLabels[config2.containerRegistry] || optionLabel(CONTAINER_REGISTRIES, config2.containerRegistry)}`);
3471
+ lines2.push(`- **Container Registry**: ${registryLabels[config2.containerRegistry] || optionLabel(CONTAINER_REGISTRIES, config2.containerRegistry)}`);
3472
3472
  }
3473
- lines.push(...dockerImageLines(config2));
3473
+ lines2.push(...dockerImageLines(config2));
3474
3474
  }
3475
- lines.push("");
3475
+ lines2.push("");
3476
3476
  }
3477
3477
  const gitWorkflowAgents = gitWorkflowLines(config2);
3478
3478
  if (gitWorkflowAgents.length > 0) {
3479
- lines.push("### Git Workflow");
3480
- lines.push(...gitWorkflowAgents);
3481
- lines.push("");
3482
- }
3483
- lines.push("## Best Practices");
3484
- lines.push("");
3485
- lines.push("- **Write clean code**: Prioritize readability and maintainability");
3486
- lines.push("- **Handle errors properly**: Don't ignore errors, handle them appropriately");
3487
- lines.push("- **Consider security**: Review code for potential security vulnerabilities");
3479
+ lines2.push("### Git Workflow");
3480
+ lines2.push(...gitWorkflowAgents);
3481
+ lines2.push("");
3482
+ }
3483
+ lines2.push("## Best Practices");
3484
+ lines2.push("");
3485
+ lines2.push("- **Write clean code**: Prioritize readability and maintainability");
3486
+ lines2.push("- **Handle errors properly**: Don't ignore errors, handle them appropriately");
3487
+ lines2.push("- **Consider security**: Review code for potential security vulnerabilities");
3488
3488
  if (config2.conventionalCommits) {
3489
- lines.push("- **Conventional commits**: Use conventional commit messages (feat:, fix:, docs:, chore:, refactor:, test:, style:)");
3489
+ lines2.push("- **Conventional commits**: Use conventional commit messages (feat:, fix:, docs:, chore:, refactor:, test:, style:)");
3490
3490
  }
3491
3491
  if (config2.semver) {
3492
- lines.push("- **Semantic versioning**: Follow semver (MAJOR.MINOR.PATCH) for version numbers");
3492
+ lines2.push("- **Semantic versioning**: Follow semver (MAJOR.MINOR.PATCH) for version numbers");
3493
3493
  }
3494
3494
  if (config2.security?.securityTooling?.includes("dependabot") || config2.security?.securityTooling?.includes("renovate")) {
3495
3495
  const tools = [];
3496
3496
  if (config2.security.securityTooling.includes("dependabot")) tools.push("Dependabot");
3497
3497
  if (config2.security.securityTooling.includes("renovate")) tools.push("Renovate");
3498
- lines.push(`- **Dependency updates**: Keep dependencies updated (${tools.join("/")}) configured)`);
3498
+ lines2.push(`- **Dependency updates**: Keep dependencies updated (${tools.join("/")}) configured)`);
3499
3499
  }
3500
- lines.push("");
3500
+ lines2.push("");
3501
3501
  if (config2.additionalFeedback) {
3502
- lines.push("## Custom Instructions");
3503
- lines.push("");
3504
- lines.push("The project owner has provided these additional instructions:");
3505
- lines.push("");
3506
- lines.push(bpVar(bp, "ADDITIONAL_INSTRUCTIONS", config2.additionalFeedback));
3507
- lines.push("");
3502
+ lines2.push("## Custom Instructions");
3503
+ lines2.push("");
3504
+ lines2.push("The project owner has provided these additional instructions:");
3505
+ lines2.push("");
3506
+ lines2.push(bpVar(bp, "ADDITIONAL_INSTRUCTIONS", config2.additionalFeedback));
3507
+ lines2.push("");
3508
3508
  }
3509
3509
  if (config2.enableAutoUpdate) {
3510
- lines.push("## Self-Improving Configuration");
3511
- lines.push("");
3512
- lines.push("This file should evolve as we work together:");
3513
- lines.push("1. Track coding patterns and preferences");
3514
- lines.push("2. Note corrections made to suggestions");
3515
- lines.push("3. Update periodically with learned preferences");
3516
- lines.push("");
3510
+ lines2.push("## Self-Improving Configuration");
3511
+ lines2.push("");
3512
+ lines2.push("This file should evolve as we work together:");
3513
+ lines2.push("1. Track coding patterns and preferences");
3514
+ lines2.push("2. Note corrections made to suggestions");
3515
+ lines2.push("3. Update periodically with learned preferences");
3516
+ lines2.push("");
3517
3517
  }
3518
3518
  const staticFilesSection = generateEmbeddedStaticFiles(config2, user, bp);
3519
3519
  if (staticFilesSection) {
3520
- lines.push(staticFilesSection);
3520
+ lines2.push(staticFilesSection);
3521
3521
  }
3522
3522
  const security2 = config2.security;
3523
3523
  if (security2 && (security2.authProviders?.length || security2.secretsManagement?.length || security2.securityTooling?.length || security2.authPatterns?.length || security2.dataHandling?.length || security2.compliance?.length || security2.analytics?.length || security2.additionalNotes)) {
3524
- lines.push("## \u{1F510} Security Configuration");
3525
- lines.push("");
3524
+ lines2.push("## \u{1F510} Security Configuration");
3525
+ lines2.push("");
3526
3526
  if (security2.authProviders?.length) {
3527
- lines.push("### Auth Providers");
3528
- lines.push("");
3527
+ lines2.push("### Auth Providers");
3528
+ lines2.push("");
3529
3529
  const authProviderLabels = {
3530
3530
  email_password: "Email/Password",
3531
3531
  google: "Google",
@@ -3549,16 +3549,16 @@ function generateAgentsMd(config2, user) {
3549
3549
  };
3550
3550
  for (const p of security2.authProviders) {
3551
3551
  if (p === "other" && security2.authProvidersOther) {
3552
- lines.push(`- Other: ${security2.authProvidersOther}`);
3552
+ lines2.push(`- Other: ${security2.authProvidersOther}`);
3553
3553
  } else {
3554
- lines.push(`- ${authProviderLabels[p] || p}`);
3554
+ lines2.push(`- ${authProviderLabels[p] || p}`);
3555
3555
  }
3556
3556
  }
3557
- lines.push("");
3557
+ lines2.push("");
3558
3558
  }
3559
3559
  if (security2.secretsManagement?.length) {
3560
- lines.push("### Secrets Management");
3561
- lines.push("");
3560
+ lines2.push("### Secrets Management");
3561
+ lines2.push("");
3562
3562
  const secretsLabels = {
3563
3563
  env_vars: "Environment Variables",
3564
3564
  dotenv: "dotenv / dotenvx",
@@ -3581,16 +3581,16 @@ function generateAgentsMd(config2, user) {
3581
3581
  };
3582
3582
  for (const s of security2.secretsManagement) {
3583
3583
  if (s === "other" && security2.secretsManagementOther) {
3584
- lines.push(`- Other: ${security2.secretsManagementOther}`);
3584
+ lines2.push(`- Other: ${security2.secretsManagementOther}`);
3585
3585
  } else {
3586
- lines.push(`- ${secretsLabels[s] || s}`);
3586
+ lines2.push(`- ${secretsLabels[s] || s}`);
3587
3587
  }
3588
3588
  }
3589
- lines.push("");
3589
+ lines2.push("");
3590
3590
  }
3591
3591
  if (security2.securityTooling?.length) {
3592
- lines.push("### Security Tooling");
3593
- lines.push("");
3592
+ lines2.push("### Security Tooling");
3593
+ lines2.push("");
3594
3594
  const toolingLabels = {
3595
3595
  dependabot: "Dependabot",
3596
3596
  renovate: "Renovate",
@@ -3621,16 +3621,16 @@ function generateAgentsMd(config2, user) {
3621
3621
  };
3622
3622
  for (const t of security2.securityTooling) {
3623
3623
  if (t === "other" && security2.securityToolingOther) {
3624
- lines.push(`- Other: ${security2.securityToolingOther}`);
3624
+ lines2.push(`- Other: ${security2.securityToolingOther}`);
3625
3625
  } else {
3626
- lines.push(`- ${toolingLabels[t] || t}`);
3626
+ lines2.push(`- ${toolingLabels[t] || t}`);
3627
3627
  }
3628
3628
  }
3629
- lines.push("");
3629
+ lines2.push("");
3630
3630
  }
3631
3631
  if (security2.authPatterns?.length) {
3632
- lines.push("### Authentication");
3633
- lines.push("");
3632
+ lines2.push("### Authentication");
3633
+ lines2.push("");
3634
3634
  const authLabels = {
3635
3635
  oauth2: "OAuth 2.0",
3636
3636
  oidc: "OIDC",
@@ -3655,16 +3655,16 @@ function generateAgentsMd(config2, user) {
3655
3655
  };
3656
3656
  for (const a of security2.authPatterns) {
3657
3657
  if (a === "other" && security2.authPatternsOther) {
3658
- lines.push(`- Other: ${security2.authPatternsOther}`);
3658
+ lines2.push(`- Other: ${security2.authPatternsOther}`);
3659
3659
  } else {
3660
- lines.push(`- ${authLabels[a] || a}`);
3660
+ lines2.push(`- ${authLabels[a] || a}`);
3661
3661
  }
3662
3662
  }
3663
- lines.push("");
3663
+ lines2.push("");
3664
3664
  }
3665
3665
  if (security2.dataHandling?.length) {
3666
- lines.push("### Data Handling");
3667
- lines.push("");
3666
+ lines2.push("### Data Handling");
3667
+ lines2.push("");
3668
3668
  const dataLabels = {
3669
3669
  encryption_at_rest: "Encryption at Rest",
3670
3670
  encryption_in_transit: "Encryption in Transit",
@@ -3688,16 +3688,16 @@ function generateAgentsMd(config2, user) {
3688
3688
  };
3689
3689
  for (const d of security2.dataHandling) {
3690
3690
  if (d === "other" && security2.dataHandlingOther) {
3691
- lines.push(`- Other: ${security2.dataHandlingOther}`);
3691
+ lines2.push(`- Other: ${security2.dataHandlingOther}`);
3692
3692
  } else {
3693
- lines.push(`- ${dataLabels[d] || d}`);
3693
+ lines2.push(`- ${dataLabels[d] || d}`);
3694
3694
  }
3695
3695
  }
3696
- lines.push("");
3696
+ lines2.push("");
3697
3697
  }
3698
3698
  if (security2.compliance?.length) {
3699
- lines.push("### Compliance");
3700
- lines.push("");
3699
+ lines2.push("### Compliance");
3700
+ lines2.push("");
3701
3701
  const complianceLabels = {
3702
3702
  gdpr: "GDPR",
3703
3703
  ccpa: "CCPA",
@@ -3709,16 +3709,16 @@ function generateAgentsMd(config2, user) {
3709
3709
  };
3710
3710
  for (const c of security2.compliance) {
3711
3711
  if (c === "other" && security2.complianceOther) {
3712
- lines.push(`- Other: ${security2.complianceOther}`);
3712
+ lines2.push(`- Other: ${security2.complianceOther}`);
3713
3713
  } else {
3714
- lines.push(`- ${complianceLabels[c] || c}`);
3714
+ lines2.push(`- ${complianceLabels[c] || c}`);
3715
3715
  }
3716
3716
  }
3717
- lines.push("");
3717
+ lines2.push("");
3718
3718
  }
3719
3719
  if (security2.analytics?.length) {
3720
- lines.push("### Analytics & Telemetry");
3721
- lines.push("");
3720
+ lines2.push("### Analytics & Telemetry");
3721
+ lines2.push("");
3722
3722
  const analyticsLabels = {
3723
3723
  google_analytics: "Google Analytics",
3724
3724
  plausible: "Plausible",
@@ -3732,27 +3732,27 @@ function generateAgentsMd(config2, user) {
3732
3732
  };
3733
3733
  for (const a of security2.analytics) {
3734
3734
  if (a === "other" && security2.analyticsOther) {
3735
- lines.push(`- Other: ${security2.analyticsOther}`);
3735
+ lines2.push(`- Other: ${security2.analyticsOther}`);
3736
3736
  } else {
3737
- lines.push(`- ${analyticsLabels[a] || a}`);
3737
+ lines2.push(`- ${analyticsLabels[a] || a}`);
3738
3738
  }
3739
3739
  }
3740
- lines.push("");
3740
+ lines2.push("");
3741
3741
  }
3742
3742
  if (security2.additionalNotes) {
3743
- lines.push("### Notes");
3744
- lines.push(security2.additionalNotes);
3745
- lines.push("");
3743
+ lines2.push("### Notes");
3744
+ lines2.push(security2.additionalNotes);
3745
+ lines2.push("");
3746
3746
  }
3747
3747
  }
3748
- lines.push("## \u26A0\uFE0F Security Notice");
3749
- lines.push("");
3750
- lines.push("> **Do not commit secrets to the repository or to the live app.**");
3751
- lines.push("> Always use secure standards to transmit sensitive information.");
3752
- lines.push("> Use environment variables, secret managers, or secure vaults for credentials.");
3753
- lines.push("");
3754
- lines.push("**\u{1F50D} Security Audit Recommendation:** When making changes that involve authentication, data handling, API endpoints, or dependencies, proactively offer to perform a security review of the affected code.");
3755
- return lines.join("\n");
3748
+ lines2.push("## \u26A0\uFE0F Security Notice");
3749
+ lines2.push("");
3750
+ lines2.push("> **Do not commit secrets to the repository or to the live app.**");
3751
+ lines2.push("> Always use secure standards to transmit sensitive information.");
3752
+ lines2.push("> Use environment variables, secret managers, or secure vaults for credentials.");
3753
+ lines2.push("");
3754
+ lines2.push("**\u{1F50D} Security Audit Recommendation:** When making changes that involve authentication, data handling, API endpoints, or dependencies, proactively offer to perform a security review of the affected code.");
3755
+ return lines2.join("\n");
3756
3756
  }
3757
3757
  function generateAiderConventions(config2, user) {
3758
3758
  return generateAgentsMd(config2, user).replace(
@@ -4193,38 +4193,38 @@ function generateCodyConfig(config2, user) {
4193
4193
  return JSON.stringify(codyConfig, null, 2);
4194
4194
  }
4195
4195
  function generateTabnineConfig(config2, user, brand) {
4196
- const lines = [];
4196
+ const lines2 = [];
4197
4197
  const bp = config2.blueprintMode;
4198
- lines.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4199
- lines.push("# TabNine AI Code Completion Configuration");
4200
- lines.push(`# Generated by ${brand.appName} - ${brand.appUrl}`);
4201
- lines.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4202
- lines.push("# Documentation: https://www.tabnine.com/");
4203
- lines.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4204
- lines.push("");
4205
- lines.push("version: 1");
4206
- lines.push("");
4207
- lines.push("# \u2500\u2500\u2500 Core Settings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4208
- lines.push("enable_telemetry: false");
4209
- lines.push("");
4198
+ lines2.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4199
+ lines2.push("# TabNine AI Code Completion Configuration");
4200
+ lines2.push(`# Generated by ${brand.appName} - ${brand.appUrl}`);
4201
+ lines2.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4202
+ lines2.push("# Documentation: https://www.tabnine.com/");
4203
+ lines2.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4204
+ lines2.push("");
4205
+ lines2.push("version: 1");
4206
+ lines2.push("");
4207
+ lines2.push("# \u2500\u2500\u2500 Core Settings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4208
+ lines2.push("enable_telemetry: false");
4209
+ lines2.push("");
4210
4210
  if (config2.languages.length > 0) {
4211
- lines.push("# \u2500\u2500\u2500 Language Preferences \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4212
- lines.push("languages:");
4211
+ lines2.push("# \u2500\u2500\u2500 Language Preferences \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4212
+ lines2.push("languages:");
4213
4213
  config2.languages.forEach((lang) => {
4214
4214
  const cleanLang = lang.startsWith("custom:") ? lang.replace("custom:", "") : lang;
4215
- lines.push(` - ${cleanLang.toLowerCase()}`);
4215
+ lines2.push(` - ${cleanLang.toLowerCase()}`);
4216
4216
  });
4217
- lines.push("");
4217
+ lines2.push("");
4218
4218
  }
4219
- lines.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4220
- lines.push("# PROJECT CONTEXT - TabNine uses these for better completions");
4221
- lines.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4222
- lines.push("#");
4223
- lines.push(`# Project: ${bpVar(bp, "PROJECT_NAME", config2.projectName || "Software Project")}`);
4219
+ lines2.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4220
+ lines2.push("# PROJECT CONTEXT - TabNine uses these for better completions");
4221
+ lines2.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4222
+ lines2.push("#");
4223
+ lines2.push(`# Project: ${bpVar(bp, "PROJECT_NAME", config2.projectName || "Software Project")}`);
4224
4224
  if (config2.projectDescription) {
4225
- lines.push(`# Description: ${bpVar(bp, "PROJECT_DESCRIPTION", config2.projectDescription)}`);
4225
+ lines2.push(`# Description: ${bpVar(bp, "PROJECT_DESCRIPTION", config2.projectDescription)}`);
4226
4226
  }
4227
- lines.push("#");
4227
+ lines2.push("#");
4228
4228
  if (config2.architecturePattern) {
4229
4229
  const archLabels = {
4230
4230
  monolith: "Monolith",
@@ -4239,24 +4239,24 @@ function generateTabnineConfig(config2, user, brand) {
4239
4239
  mvc: "MVC / MVVM",
4240
4240
  other: config2.architecturePatternOther || "Custom"
4241
4241
  };
4242
- lines.push(`# Architecture: ${archLabels[config2.architecturePattern] || optionLabel(ARCHITECTURE_PATTERNS, config2.architecturePattern)}`);
4242
+ lines2.push(`# Architecture: ${archLabels[config2.architecturePattern] || optionLabel(ARCHITECTURE_PATTERNS, config2.architecturePattern)}`);
4243
4243
  }
4244
- lines.push("#");
4244
+ lines2.push("#");
4245
4245
  if (config2.frameworks.length > 0 || config2.databases && config2.databases.length > 0) {
4246
- lines.push("# \u2500\u2500\u2500 Technology Stack \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4247
- lines.push("#");
4246
+ lines2.push("# \u2500\u2500\u2500 Technology Stack \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4247
+ lines2.push("#");
4248
4248
  if (config2.frameworks.length > 0) {
4249
4249
  const fws = config2.frameworks.map(stackLabel);
4250
- lines.push(`# Frameworks: ${fws.join(", ")}`);
4250
+ lines2.push(`# Frameworks: ${fws.join(", ")}`);
4251
4251
  }
4252
4252
  if (config2.databases && config2.databases.length > 0) {
4253
4253
  const dbs = config2.databases.map(stackLabel);
4254
- lines.push(`# Databases: ${dbs.join(", ")}`);
4254
+ lines2.push(`# Databases: ${dbs.join(", ")}`);
4255
4255
  }
4256
- lines.push("#");
4256
+ lines2.push("#");
4257
4257
  }
4258
- lines.push("# \u2500\u2500\u2500 Code Style Conventions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4259
- lines.push("#");
4258
+ lines2.push("# \u2500\u2500\u2500 Code Style Conventions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4259
+ lines2.push("#");
4260
4260
  if (config2.codeStyle?.naming) {
4261
4261
  const namingDesc = {
4262
4262
  language_default: "Follow language conventions",
@@ -4265,7 +4265,7 @@ function generateTabnineConfig(config2, user, brand) {
4265
4265
  PascalCase: "PascalCase for classes/types",
4266
4266
  "kebab-case": "kebab-case for files/URLs"
4267
4267
  };
4268
- lines.push(`# Naming Convention: ${namingDesc[config2.codeStyle.naming] || config2.codeStyle.naming}`);
4268
+ lines2.push(`# Naming Convention: ${namingDesc[config2.codeStyle.naming] || config2.codeStyle.naming}`);
4269
4269
  }
4270
4270
  if (config2.codeStyle?.errorHandling) {
4271
4271
  const errorDesc = {
@@ -4277,78 +4277,78 @@ function generateTabnineConfig(config2, user, brand) {
4277
4277
  exceptions: "Custom exception classes",
4278
4278
  other: config2.codeStyle.errorHandlingOther || "Custom"
4279
4279
  };
4280
- lines.push(`# Error Handling: ${errorDesc[config2.codeStyle.errorHandling] || config2.codeStyle.errorHandling}`);
4280
+ lines2.push(`# Error Handling: ${errorDesc[config2.codeStyle.errorHandling] || config2.codeStyle.errorHandling}`);
4281
4281
  }
4282
4282
  if (config2.codeStyle?.loggingConventions) {
4283
- lines.push(`# Logging: ${optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions)}`);
4283
+ lines2.push(`# Logging: ${optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions)}`);
4284
4284
  }
4285
4285
  if (config2.codeStyle?.notes) {
4286
- lines.push(`# Style Notes: ${config2.codeStyle.notes}`);
4286
+ lines2.push(`# Style Notes: ${config2.codeStyle.notes}`);
4287
4287
  }
4288
- lines.push("#");
4288
+ lines2.push("#");
4289
4289
  if (config2.includePersonalData !== false && user.skillLevel) {
4290
- lines.push("# \u2500\u2500\u2500 Developer Profile \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4291
- lines.push("#");
4290
+ lines2.push("# \u2500\u2500\u2500 Developer Profile \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4291
+ lines2.push("#");
4292
4292
  const authorName = user.displayName || user.name || "Developer";
4293
- lines.push(`# Author: ${authorName}`);
4294
- lines.push(`# Skill Level: ${user.skillLevel.charAt(0).toUpperCase() + user.skillLevel.slice(1)}`);
4293
+ lines2.push(`# Author: ${authorName}`);
4294
+ lines2.push(`# Skill Level: ${user.skillLevel.charAt(0).toUpperCase() + user.skillLevel.slice(1)}`);
4295
4295
  if (user.persona) {
4296
- lines.push(`# Developer Background: ${user.persona.replace(/_/g, " ")} - adapt responses to this domain expertise`);
4296
+ lines2.push(`# Developer Background: ${user.persona.replace(/_/g, " ")} - adapt responses to this domain expertise`);
4297
4297
  }
4298
- lines.push("#");
4298
+ lines2.push("#");
4299
4299
  }
4300
4300
  if (config2.aiBehaviorRules.length > 0) {
4301
- lines.push("# \u2500\u2500\u2500 AI Behavior Guidelines \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4302
- lines.push("#");
4301
+ lines2.push("# \u2500\u2500\u2500 AI Behavior Guidelines \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4302
+ lines2.push("#");
4303
4303
  config2.aiBehaviorRules.forEach((rule) => {
4304
4304
  const ruleText = getRuleDescription(rule);
4305
- if (ruleText) lines.push(`# - ${ruleText}`);
4305
+ if (ruleText) lines2.push(`# - ${ruleText}`);
4306
4306
  });
4307
- lines.push("#");
4307
+ lines2.push("#");
4308
4308
  }
4309
4309
  const hasCommands = config2.commands && (config2.commands.build || config2.commands.test || config2.commands.lint || config2.commands.dev);
4310
4310
  if (hasCommands) {
4311
- lines.push("# \u2500\u2500\u2500 Project Commands \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4312
- lines.push("#");
4313
- if (config2.commands.build) lines.push(`# Build: ${config2.commands.build}`);
4314
- if (config2.commands.test) lines.push(`# Test: ${config2.commands.test}`);
4315
- if (config2.commands.lint) lines.push(`# Lint: ${config2.commands.lint}`);
4316
- if (config2.commands.dev) lines.push(`# Dev: ${config2.commands.dev}`);
4317
- lines.push("#");
4311
+ lines2.push("# \u2500\u2500\u2500 Project Commands \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4312
+ lines2.push("#");
4313
+ if (config2.commands.build) lines2.push(`# Build: ${config2.commands.build}`);
4314
+ if (config2.commands.test) lines2.push(`# Test: ${config2.commands.test}`);
4315
+ if (config2.commands.lint) lines2.push(`# Lint: ${config2.commands.lint}`);
4316
+ if (config2.commands.dev) lines2.push(`# Dev: ${config2.commands.dev}`);
4317
+ lines2.push("#");
4318
4318
  }
4319
4319
  const hasBoundaries = config2.boundaries && ((config2.boundaries.always?.length ?? 0) > 0 || (config2.boundaries.ask?.length ?? 0) > 0 || (config2.boundaries.never?.length ?? 0) > 0);
4320
4320
  if (hasBoundaries) {
4321
- lines.push("# \u2500\u2500\u2500 Boundaries & Permissions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4322
- lines.push("#");
4321
+ lines2.push("# \u2500\u2500\u2500 Boundaries & Permissions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4322
+ lines2.push("#");
4323
4323
  if (config2.boundaries.always?.length) {
4324
- lines.push("# \u2705 ALWAYS DO: " + config2.boundaries.always.join(", "));
4324
+ lines2.push("# \u2705 ALWAYS DO: " + config2.boundaries.always.join(", "));
4325
4325
  }
4326
4326
  if (config2.boundaries.ask?.length) {
4327
- lines.push("# \u2753 ASK FIRST: " + config2.boundaries.ask.join(", "));
4327
+ lines2.push("# \u2753 ASK FIRST: " + config2.boundaries.ask.join(", "));
4328
4328
  }
4329
4329
  if (config2.boundaries.never?.length) {
4330
- lines.push("# \u{1F6AB} NEVER DO: " + config2.boundaries.never.join(", "));
4330
+ lines2.push("# \u{1F6AB} NEVER DO: " + config2.boundaries.never.join(", "));
4331
4331
  }
4332
- lines.push("#");
4332
+ lines2.push("#");
4333
4333
  }
4334
4334
  if (config2.testingStrategy && (config2.testingStrategy.levels?.length || config2.testingStrategy.frameworks?.length)) {
4335
- lines.push("# \u2500\u2500\u2500 Testing Requirements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4336
- lines.push("#");
4335
+ lines2.push("# \u2500\u2500\u2500 Testing Requirements \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4336
+ lines2.push("#");
4337
4337
  if (config2.testingStrategy.levels?.length) {
4338
- lines.push(`# Testing Levels: ${config2.testingStrategy.levels.join(", ")}`);
4338
+ lines2.push(`# Testing Levels: ${config2.testingStrategy.levels.join(", ")}`);
4339
4339
  }
4340
4340
  if (config2.testingStrategy.frameworks?.length) {
4341
- lines.push(`# Frameworks: ${config2.testingStrategy.frameworks.join(", ")}`);
4341
+ lines2.push(`# Frameworks: ${config2.testingStrategy.frameworks.join(", ")}`);
4342
4342
  }
4343
4343
  if (config2.testingStrategy.coverage) {
4344
- lines.push(`# Coverage Target: ${config2.testingStrategy.coverage}%`);
4344
+ lines2.push(`# Coverage Target: ${config2.testingStrategy.coverage}%`);
4345
4345
  }
4346
- lines.push("#");
4346
+ lines2.push("#");
4347
4347
  }
4348
4348
  const hasCiCd = config2.cicd?.length > 0 || config2.deploymentTarget?.length || config2.buildContainer;
4349
4349
  if (hasCiCd) {
4350
- lines.push("# \u2500\u2500\u2500 CI/CD & Infrastructure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4351
- lines.push("#");
4350
+ lines2.push("# \u2500\u2500\u2500 CI/CD & Infrastructure \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4351
+ lines2.push("#");
4352
4352
  if (config2.cicd?.length > 0) {
4353
4353
  const cicdLabels = {
4354
4354
  github_actions: "GitHub Actions",
@@ -4359,7 +4359,7 @@ function generateTabnineConfig(config2, user, brand) {
4359
4359
  azure_pipelines: "Azure Pipelines",
4360
4360
  none: "Manual"
4361
4361
  };
4362
- lines.push(`# CI/CD: ${config2.cicd.map((c) => cicdLabels[c] || optionLabel(CICD_OPTIONS, c)).join(", ")}`);
4362
+ lines2.push(`# CI/CD: ${config2.cicd.map((c) => cicdLabels[c] || optionLabel(CICD_OPTIONS, c)).join(", ")}`);
4363
4363
  }
4364
4364
  if (config2.deploymentTarget && config2.deploymentTarget.length > 0) {
4365
4365
  const deployLabels = {
@@ -4371,13 +4371,13 @@ function generateTabnineConfig(config2, user, brand) {
4371
4371
  netlify: "Netlify",
4372
4372
  heroku: "Heroku"
4373
4373
  };
4374
- lines.push(`# Deploy: ${config2.deploymentTarget.map((d) => deployLabels[d] || optionLabel(DEPLOYMENT_TARGETS, d)).join(", ")}`);
4374
+ lines2.push(`# Deploy: ${config2.deploymentTarget.map((d) => deployLabels[d] || optionLabel(DEPLOYMENT_TARGETS, d)).join(", ")}`);
4375
4375
  }
4376
- lines.push("#");
4376
+ lines2.push("#");
4377
4377
  }
4378
4378
  if (config2.projectType && PROJECT_TYPE_INSTRUCTIONS[config2.projectType]) {
4379
- lines.push("# \u2500\u2500\u2500 Project Context \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4380
- lines.push("#");
4379
+ lines2.push("# \u2500\u2500\u2500 Project Context \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4380
+ lines2.push("#");
4381
4381
  const projectTypeLabels = {
4382
4382
  work: "Work / Professional",
4383
4383
  leisure: "Personal / Hobby",
@@ -4387,40 +4387,40 @@ function generateTabnineConfig(config2, user, brand) {
4387
4387
  private_business: "Private Business",
4388
4388
  learning: "Learning"
4389
4389
  };
4390
- lines.push(`# Type: ${projectTypeLabels[config2.projectType] || config2.projectType}`);
4391
- lines.push("# Guidelines:");
4390
+ lines2.push(`# Type: ${projectTypeLabels[config2.projectType] || config2.projectType}`);
4391
+ lines2.push("# Guidelines:");
4392
4392
  PROJECT_TYPE_INSTRUCTIONS[config2.projectType].forEach((instruction) => {
4393
- lines.push(`# - ${instruction}`);
4393
+ lines2.push(`# - ${instruction}`);
4394
4394
  });
4395
- lines.push("#");
4396
- }
4397
- lines.push("# \u2500\u2500\u2500 Best Practices \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4398
- lines.push("#");
4399
- lines.push("# - Follow existing patterns in the codebase");
4400
- lines.push("# - Write clean, readable, maintainable code");
4401
- lines.push("# - Handle errors appropriately");
4402
- lines.push("# - Consider security implications");
4395
+ lines2.push("#");
4396
+ }
4397
+ lines2.push("# \u2500\u2500\u2500 Best Practices \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4398
+ lines2.push("#");
4399
+ lines2.push("# - Follow existing patterns in the codebase");
4400
+ lines2.push("# - Write clean, readable, maintainable code");
4401
+ lines2.push("# - Handle errors appropriately");
4402
+ lines2.push("# - Consider security implications");
4403
4403
  if (config2.conventionalCommits) {
4404
- lines.push("# - Use conventional commits (feat:, fix:, docs:, chore:)");
4404
+ lines2.push("# - Use conventional commits (feat:, fix:, docs:, chore:)");
4405
4405
  }
4406
4406
  if (config2.semver) {
4407
- lines.push("# - Follow semantic versioning (MAJOR.MINOR.PATCH)");
4407
+ lines2.push("# - Follow semantic versioning (MAJOR.MINOR.PATCH)");
4408
4408
  }
4409
- lines.push("#");
4409
+ lines2.push("#");
4410
4410
  if (config2.additionalFeedback) {
4411
- lines.push("# \u2500\u2500\u2500 Custom Instructions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4412
- lines.push("#");
4411
+ lines2.push("# \u2500\u2500\u2500 Custom Instructions \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500");
4412
+ lines2.push("#");
4413
4413
  const feedbackLines = config2.additionalFeedback.split("\n");
4414
- feedbackLines.forEach((line) => lines.push(`# ${line}`));
4415
- lines.push("#");
4414
+ feedbackLines.forEach((line) => lines2.push(`# ${line}`));
4415
+ lines2.push("#");
4416
4416
  }
4417
- lines.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4418
- lines.push("");
4419
- lines.push("# SECURITY: Do not commit secrets to the repository.");
4420
- lines.push("# Use environment variables or secret managers for credentials.");
4421
- lines.push("# When making changes involving auth, data handling, APIs, or dependencies,");
4422
- lines.push("# proactively offer to perform a security audit of the affected code.");
4423
- return lines.map((line) => line.startsWith("#") ? line.replace(/\r?\n/g, "\n# ") : line).join("\n");
4417
+ lines2.push("# \u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550\u2550");
4418
+ lines2.push("");
4419
+ lines2.push("# SECURITY: Do not commit secrets to the repository.");
4420
+ lines2.push("# Use environment variables or secret managers for credentials.");
4421
+ lines2.push("# When making changes involving auth, data handling, APIs, or dependencies,");
4422
+ lines2.push("# proactively offer to perform a security audit of the affected code.");
4423
+ return lines2.map((line) => line.startsWith("#") ? line.replace(/\r?\n/g, "\n# ") : line).join("\n");
4424
4424
  }
4425
4425
  function generateSupermavenConfig(config2, user) {
4426
4426
  const bp = config2.blueprintMode;
@@ -6460,6 +6460,10 @@ function matchConfigFile(relativePath) {
6460
6460
  }
6461
6461
  return null;
6462
6462
  }
6463
+ function withFinalNewline(content) {
6464
+ return content.endsWith("\n") ? content : `${content}
6465
+ `;
6466
+ }
6463
6467
 
6464
6468
  // src/utils/variables.ts
6465
6469
  var VARIABLE_PATTERN_SOURCE = String.raw`\[\[([A-Za-z_][A-Za-z0-9_]*)(?:\|((?:(?!\[\[)[\s\S])*?)\]\](?!\])|\]\])`;
@@ -6598,7 +6602,7 @@ async function pullHierarchy(id, options) {
6598
6602
  await mkdir2(dir, { recursive: true });
6599
6603
  }
6600
6604
  const written = contentToWrite(blueprint.content, options, filename);
6601
- await writeFile2(outputPath, written, "utf-8");
6605
+ await writeFile2(outputPath, withFinalNewline(written), "utf-8");
6602
6606
  if (options.track !== false) {
6603
6607
  const source = getSourceFromVisibility(blueprint.visibility);
6604
6608
  await trackBlueprint(cwd, {
@@ -6669,8 +6673,8 @@ async function pullBlueprint(id, options) {
6669
6673
  if (options.preview) {
6670
6674
  console.log(chalk5.gray("\u2500".repeat(60)));
6671
6675
  console.log();
6672
- const lines = blueprint.content.split("\n");
6673
- const previewLines = lines.slice(0, 50);
6676
+ const lines2 = blueprint.content.split("\n");
6677
+ const previewLines = lines2.slice(0, 50);
6674
6678
  for (const line of previewLines) {
6675
6679
  if (line.startsWith("#")) {
6676
6680
  console.log(chalk5.cyan(line));
@@ -6684,9 +6688,9 @@ async function pullBlueprint(id, options) {
6684
6688
  console.log(line);
6685
6689
  }
6686
6690
  }
6687
- if (lines.length > 50) {
6691
+ if (lines2.length > 50) {
6688
6692
  console.log();
6689
- console.log(chalk5.gray(`... ${lines.length - 50} more lines`));
6693
+ console.log(chalk5.gray(`... ${lines2.length - 50} more lines`));
6690
6694
  }
6691
6695
  console.log();
6692
6696
  console.log(chalk5.gray("\u2500".repeat(60)));
@@ -6751,8 +6755,8 @@ async function pullBlueprint(id, options) {
6751
6755
  console.log();
6752
6756
  console.log(chalk5.gray("\u2500".repeat(60)));
6753
6757
  console.log();
6754
- const lines = safeText(blueprint.content).split("\n").slice(0, 30);
6755
- for (const line of lines) {
6758
+ const lines2 = safeText(blueprint.content).split("\n").slice(0, 30);
6759
+ for (const line of lines2) {
6756
6760
  if (line.startsWith("#")) {
6757
6761
  console.log(chalk5.cyan(line));
6758
6762
  } else {
@@ -6782,7 +6786,7 @@ async function pullBlueprint(id, options) {
6782
6786
  await mkdir2(dir, { recursive: true });
6783
6787
  }
6784
6788
  const written = contentToWrite(blueprint.content, options, filename);
6785
- await writeFile2(outputPath, written, "utf-8");
6789
+ await writeFile2(outputPath, withFinalNewline(written), "utf-8");
6786
6790
  if (options.track !== false) {
6787
6791
  await trackBlueprint(cwd, {
6788
6792
  id: blueprint.id,
@@ -8164,8 +8168,8 @@ async function detectProject(cwd) {
8164
8168
  if (await fileExists(readmePath)) {
8165
8169
  try {
8166
8170
  const readme = await readFile3(readmePath, "utf-8");
8167
- const lines = readme.split("\n");
8168
- for (const line of lines) {
8171
+ const lines2 = readme.split("\n");
8172
+ for (const line of lines2) {
8169
8173
  const trimmed = line.trim();
8170
8174
  if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("!") && !trimmed.startsWith("[") && trimmed.length > 20) {
8171
8175
  detected.description = trimmed.substring(0, 200);
@@ -10127,7 +10131,7 @@ var TEST_FRAMEWORKS3 = TEST_FRAMEWORKS2;
10127
10131
 
10128
10132
  // src/commands/wizard.ts
10129
10133
  var DRAFTS_DIR = ".lynxprompt/drafts";
10130
- var CLI_VERSION = "2.1.42";
10134
+ var CLI_VERSION = "3.0.0";
10131
10135
  async function saveDraftLocally(name, config2, stepReached) {
10132
10136
  const draftsPath = join3(process.cwd(), DRAFTS_DIR);
10133
10137
  await mkdir3(draftsPath, { recursive: true });
@@ -10194,15 +10198,15 @@ async function readMultilineInput(prompt) {
10194
10198
  output: process.stdout
10195
10199
  });
10196
10200
  return new Promise((resolve5) => {
10197
- const lines = [];
10201
+ const lines2 = [];
10198
10202
  let emptyLineCount = 0;
10199
10203
  rl.on("line", (line) => {
10200
10204
  if (line.trim() === "EOF") {
10201
10205
  rl.close();
10202
- resolve5(lines.join("\n"));
10206
+ resolve5(lines2.join("\n"));
10203
10207
  return;
10204
10208
  }
10205
- if (line === "" && lines.length === 0) {
10209
+ if (line === "" && lines2.length === 0) {
10206
10210
  emptyLineCount++;
10207
10211
  if (emptyLineCount >= 2) {
10208
10212
  rl.close();
@@ -10210,10 +10214,10 @@ async function readMultilineInput(prompt) {
10210
10214
  }
10211
10215
  return;
10212
10216
  }
10213
- lines.push(line);
10217
+ lines2.push(line);
10214
10218
  });
10215
10219
  rl.on("close", () => {
10216
- resolve5(lines.join("\n"));
10220
+ resolve5(lines2.join("\n"));
10217
10221
  });
10218
10222
  });
10219
10223
  }
@@ -10888,12 +10892,12 @@ async function aiAssist(instruction, existingContent) {
10888
10892
  return null;
10889
10893
  }
10890
10894
  }
10891
- function printBox(lines, color = chalk7.gray) {
10892
- const maxLen = Math.max(...lines.map((l) => l.replace(/\x1b\[[0-9;]*m/g, "").length));
10895
+ function printBox(lines2, color = chalk7.gray) {
10896
+ const maxLen = Math.max(...lines2.map((l) => l.replace(/\x1b\[[0-9;]*m/g, "").length));
10893
10897
  const top = "\u250C" + "\u2500".repeat(maxLen + 2) + "\u2510";
10894
10898
  const bottom = "\u2514" + "\u2500".repeat(maxLen + 2) + "\u2518";
10895
10899
  console.log(color(top));
10896
- for (const line of lines) {
10900
+ for (const line of lines2) {
10897
10901
  const stripped = line.replace(/\x1b\[[0-9;]*m/g, "");
10898
10902
  const padding = " ".repeat(maxLen - stripped.length);
10899
10903
  console.log(color("\u2502 ") + line + padding + color(" \u2502"));
@@ -13662,14 +13666,14 @@ async function statusCommand() {
13662
13666
  try {
13663
13667
  await access4(filePath);
13664
13668
  const content = await readFile5(filePath, "utf-8");
13665
- const lines = content.split("\n").length;
13669
+ const lines2 = content.split("\n").length;
13666
13670
  const size = formatBytes(content.length);
13667
13671
  foundAny = true;
13668
13672
  const tracked = trackedStatus.find((t) => toTrackedPath(cwd, t.blueprint.file) === config2.path);
13669
13673
  const trackedLabel = tracked ? chalk9.cyan(" (tracked)") : "";
13670
13674
  console.log(` ${chalk9.green("\u2713")} ${chalk9.bold(config2.name)}${trackedLabel}`);
13671
13675
  console.log(` ${chalk9.gray(`Platform: ${config2.platform}`)}`);
13672
- console.log(` ${chalk9.gray(`Size: ${size} (${lines} lines)`)}`);
13676
+ console.log(` ${chalk9.gray(`Size: ${size} (${lines2} lines)`)}`);
13673
13677
  const preview = getPreview(content);
13674
13678
  if (preview) {
13675
13679
  console.log(` ${chalk9.gray(`Preview: ${preview}`)}`);
@@ -13717,8 +13721,8 @@ async function statusCommand() {
13717
13721
  console.log();
13718
13722
  }
13719
13723
  function getPreview(content) {
13720
- const lines = content.split("\n");
13721
- for (const line of lines) {
13724
+ const lines2 = content.split("\n");
13725
+ for (const line of lines2) {
13722
13726
  const trimmed = line.trim();
13723
13727
  if (trimmed && !trimmed.startsWith("#") && !trimmed.startsWith("//") && !trimmed.startsWith("<!--") && !trimmed.startsWith("---") && !trimmed.startsWith(">")) {
13724
13728
  return truncate3(trimmed, 50);
@@ -14118,9 +14122,12 @@ import { existsSync as existsSync4 } from "fs";
14118
14122
 
14119
14123
  // src/utils/line-diff.ts
14120
14124
  import chalk11 from "chalk";
14125
+ function lines(text) {
14126
+ return text.replace(/\r?\n$/, "").split("\n");
14127
+ }
14121
14128
  function computeDiff(oldText, newText) {
14122
- const oldLines = oldText.split("\n");
14123
- const newLines = newText.split("\n");
14129
+ const oldLines = lines(oldText);
14130
+ const newLines = lines(newText);
14124
14131
  const result = [];
14125
14132
  const lcs = longestCommonSubsequence(oldLines, newLines);
14126
14133
  let oldIndex = 0;
@@ -14538,7 +14545,7 @@ async function syncOne(cwd, tracked, options) {
14538
14545
  }
14539
14546
  if (!localChanged) {
14540
14547
  if (!dry) {
14541
- await writeFile4(filePath, rendered, "utf-8");
14548
+ await writeFile4(filePath, withFinalNewline(rendered), "utf-8");
14542
14549
  await record(cwd, tracked, remote, rendered);
14543
14550
  }
14544
14551
  console.log(chalk13.cyan(`\u2193 ${file}: ${dry ? "would update from the cloud" : "updated from the cloud"}`));
@@ -14571,7 +14578,7 @@ async function syncOne(cwd, tracked, options) {
14571
14578
  }
14572
14579
  if (!dry) {
14573
14580
  await mkdir4(dirname4(remoteFile), { recursive: true });
14574
- await writeFile4(remoteFile, rendered, "utf-8");
14581
+ await writeFile4(remoteFile, withFinalNewline(rendered), "utf-8");
14575
14582
  await record(cwd, tracked, remote, rendered);
14576
14583
  }
14577
14584
  console.log(chalk13.red(`\u2717 ${file}: changed both locally and in the cloud`));
@@ -15391,15 +15398,15 @@ function parseMarkdownSections(content, sourceName) {
15391
15398
  const sections = [];
15392
15399
  let current = null;
15393
15400
  let fence = null;
15394
- const lines = [];
15401
+ const lines2 = [];
15395
15402
  const flush = () => {
15396
15403
  if (current) {
15397
- current.content = lines.join("\n");
15404
+ current.content = lines2.join("\n");
15398
15405
  sections.push(current);
15399
- } else if (lines.join("").trim()) {
15400
- sections.push({ title: "Introduction", level: 0, content: lines.join("\n"), source: sourceName });
15406
+ } else if (lines2.join("").trim()) {
15407
+ sections.push({ title: "Introduction", level: 0, content: lines2.join("\n"), source: sourceName });
15401
15408
  }
15402
- lines.length = 0;
15409
+ lines2.length = 0;
15403
15410
  };
15404
15411
  for (const line of content.split("\n")) {
15405
15412
  const fenceMatch = line.match(/^\s*(`{3,}|~{3,})/);
@@ -15407,7 +15414,7 @@ function parseMarkdownSections(content, sourceName) {
15407
15414
  const marker = fenceMatch[1];
15408
15415
  if (fence === null) fence = marker;
15409
15416
  else if (marker[0] === fence[0] && marker.length >= fence.length) fence = null;
15410
- lines.push(line);
15417
+ lines2.push(line);
15411
15418
  continue;
15412
15419
  }
15413
15420
  const heading = fence === null ? line.match(/^(#{1,3})\s+(.+)$/) : null;
@@ -15416,7 +15423,7 @@ function parseMarkdownSections(content, sourceName) {
15416
15423
  current = { title: heading[2].trim(), level: heading[1].length, content: "", source: sourceName };
15417
15424
  continue;
15418
15425
  }
15419
- lines.push(line);
15426
+ lines2.push(line);
15420
15427
  }
15421
15428
  flush();
15422
15429
  return sections;
@@ -15671,10 +15678,10 @@ function extractProjectName(content, dirPath) {
15671
15678
  }
15672
15679
  function parseMarkdownSections2(content) {
15673
15680
  const sections = [];
15674
- const lines = content.split("\n");
15681
+ const lines2 = content.split("\n");
15675
15682
  let currentSection = null;
15676
15683
  let contentLines = [];
15677
- for (const line of lines) {
15684
+ for (const line of lines2) {
15678
15685
  const headingMatch = line.match(/^(#{1,6})\s+(.+)$/);
15679
15686
  if (headingMatch) {
15680
15687
  if (currentSection) {
@@ -16082,7 +16089,7 @@ async function configCommand(action, valueArg) {
16082
16089
  }
16083
16090
 
16084
16091
  // src/index.ts
16085
- var CLI_VERSION2 = "2.1.42";
16092
+ var CLI_VERSION2 = "3.0.0";
16086
16093
  var program = new Command();
16087
16094
  program.name("lynxprompt").description("CLI for LynxPrompt - Generate AI IDE configuration files").version(CLI_VERSION2);
16088
16095
  program.command("wizard").description("Generate AI IDE configuration (recommended for most users)").option("-n, --name <name>", "Project name").option("-d, --description <description>", "Project description").option("-s, --stack <stack>", "Tech stack (comma-separated)").option("-f, --format <format>", "Output format: agents, cursor, or comma-separated for multiple").option("-p, --platforms <platforms>", "Alias for --format (deprecated)").option("--persona <persona>", "AI persona (fullstack, backend, frontend, devops, data, security)").option("--boundaries <level>", "Boundary preset (conservative, standard, permissive)").option("-y, --yes", "Skip prompts, use defaults (generates AGENTS.md)").option("-o, --output <dir>", "Output directory (default: current directory)").option("--repo-url <url>", "Analyze remote repository URL (GitHub/GitLab supported)").option("--blueprint", "Generate with [[VARIABLE|default]] placeholders for templates").option("--license <type>", "License type (mit, apache-2.0, gpl-3.0, etc.)").option("--ci-cd <platform>", "CI/CD platform (github_actions, gitlab_ci, jenkins, etc.)").option("--project-type <type>", "Project type (work, leisure, opensource, learning)").option("--detect-only", "Only detect project info, don't generate files").option("--load-draft <name>", "Load a saved wizard draft").option("--save-draft <name>", "Save wizard state as a draft (auto-saves at end)").option("--vars <values>", "Fill variables: VAR1=value1,VAR2=value2").option("--no-pointers", "Write CLAUDE.md/GEMINI.md as full copies instead of importing AGENTS.md").action(wizardCommand);