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 +647 -640
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
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
|
|
1405
|
-
const end =
|
|
1406
|
-
const nameLine = end > 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
|
|
1510
|
-
return
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
1535
|
+
lines2.push(` export LYNXPROMPT_API_URL=${appUrl}`);
|
|
1536
1536
|
}
|
|
1537
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1559
|
-
return
|
|
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
|
|
1564
|
+
const lines2 = syncInstructions(opts);
|
|
1565
1565
|
if (ext === "yaml" || ext === "yml" || ext === "toml") {
|
|
1566
|
-
return
|
|
1566
|
+
return lines2.map((l) => l ? `# ${l}` : "#").join("\n") + "\n\n" + content;
|
|
1567
1567
|
}
|
|
1568
|
-
const block = ["<!--", ...
|
|
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
|
|
2130
|
-
if (config2.packageManager)
|
|
2131
|
-
if (config2.jsRuntime)
|
|
2132
|
-
if (config2.monorepoTool)
|
|
2133
|
-
if (config2.orm)
|
|
2134
|
-
return
|
|
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
|
|
2139
|
-
if (commands.typecheck)
|
|
2140
|
-
if (commands.format)
|
|
2141
|
-
if (commands.preCommit)
|
|
2142
|
-
if (commands.clean)
|
|
2143
|
-
return
|
|
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
|
|
2162
|
+
const lines2 = [];
|
|
2163
2163
|
if (style.maxFileLength && style.maxFileLength !== DEFAULT_MAX_FILE_LENGTH) {
|
|
2164
|
-
|
|
2164
|
+
lines2.push(`- **File length**: keep files under ${style.maxFileLength} lines; split larger ones`);
|
|
2165
2165
|
}
|
|
2166
|
-
if (style.importOrder)
|
|
2167
|
-
if (style.commentLanguage)
|
|
2168
|
-
if (style.docStyle)
|
|
2169
|
-
return
|
|
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
|
|
2183
|
-
if (testing.tddPreference)
|
|
2184
|
-
if (testing.snapshotTesting)
|
|
2185
|
-
if (testing.mockStrategy)
|
|
2186
|
-
return
|
|
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
|
|
2214
|
+
const lines2 = [];
|
|
2215
2215
|
const branch = config2.defaultBranch || "main";
|
|
2216
|
-
if (config2.branchStrategy)
|
|
2217
|
-
if (config2.defaultBranch)
|
|
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
|
-
|
|
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)
|
|
2224
|
-
if (config2.versionTagFormat)
|
|
2225
|
-
if (config2.changelogTool)
|
|
2226
|
-
return
|
|
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
|
|
2249
|
-
if (config2.planModeFrequency)
|
|
2250
|
-
if (config2.explanationVerbosity)
|
|
2251
|
-
if (config2.accessibilityFocus)
|
|
2252
|
-
if (config2.performanceFocus)
|
|
2253
|
-
return
|
|
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
|
|
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
|
-
|
|
2278
|
+
lines2.push(`- **Server access**: via SSH. ${keyInfo}`);
|
|
2279
2279
|
}
|
|
2280
2280
|
if (config2.manualDeployment) {
|
|
2281
|
-
|
|
2281
|
+
lines2.push(
|
|
2282
2282
|
config2.deploymentMethod ? `- **Deployment**: ${label(DEPLOYMENT_METHODS, config2.deploymentMethod)}` : "- **Deployment**: manual, not through CI/CD"
|
|
2283
2283
|
);
|
|
2284
2284
|
}
|
|
2285
|
-
|
|
2286
|
-
return
|
|
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
|
|
2424
|
+
const lines2 = [];
|
|
2425
2425
|
const bp = config2.blueprintMode;
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
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
|
-
|
|
2431
|
-
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
}
|
|
2438
|
-
|
|
2439
|
-
|
|
2440
|
-
|
|
2441
|
-
|
|
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
|
-
|
|
2457
|
+
lines2.push(`**Architecture Pattern**: ${bpVar(bp, "ARCHITECTURE_PATTERN", archValue)}`);
|
|
2458
2458
|
}
|
|
2459
2459
|
if (config2.isPublic !== void 0) {
|
|
2460
|
-
|
|
2460
|
+
lines2.push(`**Visibility**: ${config2.isPublic ? "Public repository" : "Private repository"}`);
|
|
2461
2461
|
}
|
|
2462
2462
|
if (config2.devOS) {
|
|
2463
|
-
|
|
2463
|
+
lines2.push(`**Development OS**: ${formatDevOSDisplay(config2)}`);
|
|
2464
2464
|
}
|
|
2465
|
-
|
|
2465
|
+
lines2.push("");
|
|
2466
2466
|
const hasRepoInfo = config2.repoUrl || config2.repoHosts?.length || config2.repoHost;
|
|
2467
2467
|
if (hasRepoInfo) {
|
|
2468
|
-
|
|
2468
|
+
lines2.push("### Repository");
|
|
2469
2469
|
if (config2.repoUrl) {
|
|
2470
|
-
|
|
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
|
-
|
|
2490
|
+
lines2.push(`- **Platform${hosts.length > 1 ? "s" : ""}**: ${bpVar(bp, "REPO_HOST", hostLabels)}`);
|
|
2491
2491
|
if (hosts.length > 1 && config2.multiRepoReason) {
|
|
2492
|
-
|
|
2492
|
+
lines2.push(`- **Why multiple platforms**: ${config2.multiRepoReason}`);
|
|
2493
2493
|
}
|
|
2494
2494
|
}
|
|
2495
|
-
|
|
2495
|
+
lines2.push("");
|
|
2496
2496
|
}
|
|
2497
2497
|
if (config2.devOS) {
|
|
2498
2498
|
const osList = resolveDevOS(config2);
|
|
2499
|
-
|
|
2499
|
+
lines2.push("### Development Environment");
|
|
2500
2500
|
if (isMultiPlatformOS(config2) || osList.length > 1) {
|
|
2501
|
-
|
|
2502
|
-
|
|
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
|
-
|
|
2505
|
-
|
|
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
|
-
|
|
2508
|
-
|
|
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
|
-
|
|
2510
|
+
lines2.push("- Use standard Unix/Linux commands (bash, zsh)");
|
|
2511
2511
|
} else if (osList.includes("macos")) {
|
|
2512
|
-
|
|
2512
|
+
lines2.push("- Use standard Unix commands, macOS-specific tools are acceptable");
|
|
2513
2513
|
}
|
|
2514
|
-
|
|
2514
|
+
lines2.push("");
|
|
2515
2515
|
}
|
|
2516
2516
|
if (config2.exampleRepoUrl || config2.documentationUrl) {
|
|
2517
|
-
|
|
2517
|
+
lines2.push("### Reference Materials");
|
|
2518
2518
|
if (config2.exampleRepoUrl) {
|
|
2519
|
-
|
|
2520
|
-
|
|
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
|
-
|
|
2524
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2544
|
+
lines2.push(`**Database${config2.databases.length > 1 ? "s" : ""}**: ${bpVarArray(bp, "DATABASES", dbs)}`);
|
|
2545
2545
|
}
|
|
2546
2546
|
if (tooling.length > 0) {
|
|
2547
|
-
|
|
2548
|
-
|
|
2547
|
+
lines2.push("");
|
|
2548
|
+
lines2.push(...tooling);
|
|
2549
2549
|
}
|
|
2550
2550
|
if (config2.letAiDecide) {
|
|
2551
|
-
|
|
2551
|
+
lines2.push("");
|
|
2552
2552
|
if (config2.languages.length > 0 || config2.frameworks.length > 0) {
|
|
2553
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2558
|
+
lines2.push("");
|
|
2559
2559
|
}
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
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
|
-
|
|
2565
|
+
lines2.push("### Developer Profile");
|
|
2566
2566
|
if (user.skillLevel) {
|
|
2567
2567
|
const authorName = user.displayName || user.name || "Developer";
|
|
2568
|
-
|
|
2568
|
+
lines2.push(`- **Author**: ${bpVar(bp, "AUTHOR_NAME", authorName)}`);
|
|
2569
2569
|
}
|
|
2570
2570
|
if (user.persona) {
|
|
2571
|
-
|
|
2571
|
+
lines2.push(`- **Developer Background**: ${user.persona.replace(/_/g, " ")} \u2014 adapt responses to this domain expertise`);
|
|
2572
2572
|
}
|
|
2573
|
-
if (!user.skillLevel)
|
|
2573
|
+
if (!user.skillLevel) lines2.push("");
|
|
2574
2574
|
}
|
|
2575
2575
|
if (config2.includePersonalData !== false && user.skillLevel) {
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
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
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
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
|
-
|
|
2585
|
-
|
|
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
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2603
|
-
|
|
2604
|
-
|
|
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
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
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
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
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
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2628
|
+
lines2.push("### Formatting & Documentation");
|
|
2629
|
+
lines2.push(...styleExtras);
|
|
2630
|
+
lines2.push("");
|
|
2631
2631
|
}
|
|
2632
2632
|
if (config2.codeStyle?.notes) {
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
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
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
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)
|
|
2645
|
+
if (ruleText) lines2.push(`- ${ruleText}`);
|
|
2646
2646
|
});
|
|
2647
|
-
|
|
2647
|
+
lines2.push(...aiPrefs);
|
|
2648
2648
|
if (config2.attemptWorkarounds === true) {
|
|
2649
|
-
|
|
2649
|
+
lines2.push("- When stuck, **attempt creative workarounds** before asking for help");
|
|
2650
2650
|
} else if (config2.attemptWorkarounds === false) {
|
|
2651
|
-
|
|
2651
|
+
lines2.push("- When stuck, **stop and ask** rather than attempting workarounds");
|
|
2652
2652
|
}
|
|
2653
|
-
|
|
2653
|
+
lines2.push("");
|
|
2654
2654
|
}
|
|
2655
|
-
|
|
2656
|
-
|
|
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
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
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
|
-
|
|
2689
|
+
lines2.push(bpVar(bp, "IMPORTANT_FILES", allFiles.join(", ")));
|
|
2690
2690
|
} else {
|
|
2691
|
-
allFiles.forEach((f) =>
|
|
2691
|
+
allFiles.forEach((f) => lines2.push(`- ${f}`));
|
|
2692
2692
|
}
|
|
2693
|
-
|
|
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
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
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
|
-
|
|
2702
|
+
lines2.push("### \u2705 ALWAYS DO (no need to ask)");
|
|
2703
2703
|
const alwaysItems = config2.boundaries.always.join(", ");
|
|
2704
2704
|
if (bp) {
|
|
2705
|
-
|
|
2705
|
+
lines2.push(bpVar(bp, "ALWAYS_DO", alwaysItems));
|
|
2706
2706
|
} else {
|
|
2707
|
-
config2.boundaries.always.forEach((item) =>
|
|
2707
|
+
config2.boundaries.always.forEach((item) => lines2.push(`- ${item}`));
|
|
2708
2708
|
}
|
|
2709
|
-
|
|
2709
|
+
lines2.push("");
|
|
2710
2710
|
}
|
|
2711
2711
|
if (config2.boundaries.ask?.length) {
|
|
2712
|
-
|
|
2712
|
+
lines2.push("### \u2753 ASK FIRST (get confirmation before doing)");
|
|
2713
2713
|
const askItems = config2.boundaries.ask.join(", ");
|
|
2714
2714
|
if (bp) {
|
|
2715
|
-
|
|
2715
|
+
lines2.push(bpVar(bp, "ASK_FIRST", askItems));
|
|
2716
2716
|
} else {
|
|
2717
|
-
config2.boundaries.ask.forEach((item) =>
|
|
2717
|
+
config2.boundaries.ask.forEach((item) => lines2.push(`- ${item}`));
|
|
2718
2718
|
}
|
|
2719
|
-
|
|
2719
|
+
lines2.push("");
|
|
2720
2720
|
}
|
|
2721
2721
|
if (config2.boundaries.never?.length) {
|
|
2722
|
-
|
|
2722
|
+
lines2.push("### \u{1F6AB} NEVER DO (strictly prohibited)");
|
|
2723
2723
|
const neverItems = config2.boundaries.never.join(", ");
|
|
2724
2724
|
if (bp) {
|
|
2725
|
-
|
|
2725
|
+
lines2.push(bpVar(bp, "NEVER_DO", neverItems));
|
|
2726
2726
|
} else {
|
|
2727
|
-
config2.boundaries.never.forEach((item) =>
|
|
2727
|
+
config2.boundaries.never.forEach((item) => lines2.push(`- ${item}`));
|
|
2728
2728
|
}
|
|
2729
|
-
|
|
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
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
if (config2.commands.build)
|
|
2739
|
-
if (config2.commands.test)
|
|
2740
|
-
if (config2.commands.lint)
|
|
2741
|
-
if (config2.commands.dev)
|
|
2742
|
-
|
|
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
|
-
|
|
2745
|
-
|
|
2746
|
-
config2.commands.additional.forEach((cmd) =>
|
|
2744
|
+
lines2.push("");
|
|
2745
|
+
lines2.push("**Other useful commands**:");
|
|
2746
|
+
config2.commands.additional.forEach((cmd) => lines2.push(`- \`${cmd}\``));
|
|
2747
2747
|
}
|
|
2748
|
-
|
|
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
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
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
|
-
|
|
2765
|
+
lines2.push("**Testing Levels**:");
|
|
2766
2766
|
config2.testingStrategy.levels.forEach((level) => {
|
|
2767
|
-
|
|
2767
|
+
lines2.push(`- ${levelDescriptions[level] || optionLabel(TEST_LEVELS, level)}`);
|
|
2768
2768
|
});
|
|
2769
|
-
|
|
2769
|
+
lines2.push("");
|
|
2770
2770
|
}
|
|
2771
2771
|
if (config2.testingStrategy.frameworks?.length) {
|
|
2772
2772
|
const frameworksValue = config2.testingStrategy.frameworks.join(", ");
|
|
2773
|
-
|
|
2773
|
+
lines2.push(`**Testing Frameworks**: ${bpVar(bp, "TEST_FRAMEWORKS", frameworksValue)}`);
|
|
2774
2774
|
}
|
|
2775
2775
|
if (config2.testingStrategy.coverage !== void 0) {
|
|
2776
|
-
|
|
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
|
-
|
|
2781
|
-
|
|
2780
|
+
lines2.push("");
|
|
2781
|
+
lines2.push(...testingExtras);
|
|
2782
2782
|
}
|
|
2783
2783
|
if (config2.testingStrategy.notes) {
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2784
|
+
lines2.push("");
|
|
2785
|
+
lines2.push("**Additional testing notes**:");
|
|
2786
|
+
lines2.push(bpVar(bp, "TEST_NOTES", config2.testingStrategy.notes));
|
|
2787
2787
|
}
|
|
2788
|
-
|
|
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
|
-
|
|
2804
|
-
|
|
2803
|
+
lines2.push("## Project Type Context");
|
|
2804
|
+
lines2.push("");
|
|
2805
2805
|
const projectTypeValue = projectTypeLabels[config2.projectType] || config2.projectType;
|
|
2806
|
-
|
|
2807
|
-
|
|
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
|
-
|
|
2809
|
+
lines2.push(`- ${instruction}`);
|
|
2810
2810
|
});
|
|
2811
|
-
|
|
2811
|
+
lines2.push("");
|
|
2812
2812
|
}
|
|
2813
2813
|
if (config2.additionalFeedback) {
|
|
2814
|
-
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
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
|
-
|
|
2824
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2856
|
+
lines2.push(`**Deployment Target${config2.deploymentTarget.length > 1 ? "s" : ""}**: ${bpVar(bp, "DEPLOYMENT_TARGETS", deployNames)}`);
|
|
2857
2857
|
}
|
|
2858
2858
|
if (config2.buildContainer) {
|
|
2859
|
-
|
|
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
|
-
|
|
2870
|
+
lines2.push(`**Container Registry**: ${bpVar(bp, "CONTAINER_REGISTRY", registryValue)}`);
|
|
2871
2871
|
}
|
|
2872
|
-
|
|
2872
|
+
lines2.push(...dockerImageLines(config2));
|
|
2873
2873
|
}
|
|
2874
|
-
|
|
2874
|
+
lines2.push("");
|
|
2875
2875
|
}
|
|
2876
2876
|
const gitWorkflow = gitWorkflowLines(config2);
|
|
2877
2877
|
if (gitWorkflow.length > 0) {
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
}
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
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
|
-
|
|
2891
|
+
lines2.push("- **Conventional commits**: Use conventional commit messages (feat:, fix:, docs:, chore:, refactor:, test:, style:)");
|
|
2892
2892
|
}
|
|
2893
2893
|
if (config2.semver) {
|
|
2894
|
-
|
|
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
|
-
|
|
2900
|
+
lines2.push(`- **Dependency updates**: Keep dependencies updated (${tools.join("/")}) configured)`);
|
|
2901
2901
|
}
|
|
2902
|
-
|
|
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
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
if (config2.staticFiles.editorconfig)
|
|
2910
|
-
if (config2.staticFiles.contributing)
|
|
2911
|
-
if (config2.staticFiles.codeOfConduct)
|
|
2912
|
-
if (config2.staticFiles.security)
|
|
2913
|
-
if (config2.staticFiles.roadmap)
|
|
2914
|
-
if (config2.staticFiles.gitignoreMode && config2.staticFiles.gitignoreMode !== "skip")
|
|
2915
|
-
if (config2.buildContainer || config2.staticFiles.dockerignoreMode && config2.staticFiles.dockerignoreMode !== "skip")
|
|
2916
|
-
if (config2.funding)
|
|
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
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2929
|
-
|
|
2930
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2939
|
-
|
|
2938
|
+
lines2.push("## \u{1F510} Security Configuration");
|
|
2939
|
+
lines2.push("");
|
|
2940
2940
|
if (security.secretsManagement?.length) {
|
|
2941
|
-
|
|
2942
|
-
|
|
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
|
-
|
|
2964
|
+
lines2.push(`- ${secretsLabels[s] || s}`);
|
|
2965
2965
|
}
|
|
2966
|
-
|
|
2966
|
+
lines2.push("");
|
|
2967
2967
|
}
|
|
2968
2968
|
if (security.securityTooling?.length) {
|
|
2969
|
-
|
|
2970
|
-
|
|
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
|
-
|
|
3000
|
+
lines2.push(`- ${toolingLabels[t] || t}`);
|
|
3001
3001
|
}
|
|
3002
|
-
|
|
3002
|
+
lines2.push("");
|
|
3003
3003
|
}
|
|
3004
3004
|
if (security.authPatterns?.length) {
|
|
3005
|
-
|
|
3006
|
-
|
|
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
|
-
|
|
3030
|
+
lines2.push(`- ${authLabels[a] || a}`);
|
|
3031
3031
|
}
|
|
3032
|
-
|
|
3032
|
+
lines2.push("");
|
|
3033
3033
|
}
|
|
3034
3034
|
if (security.dataHandling?.length) {
|
|
3035
|
-
|
|
3036
|
-
|
|
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
|
-
|
|
3059
|
+
lines2.push(`- ${dataLabels[d] || d}`);
|
|
3060
3060
|
}
|
|
3061
|
-
|
|
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
|
-
|
|
3071
|
-
|
|
3072
|
-
for (const item of items)
|
|
3073
|
-
|
|
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
|
-
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
}
|
|
3081
|
-
}
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
return
|
|
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
|
|
3114
|
+
const lines2 = [];
|
|
3115
3115
|
const bp = config2.blueprintMode;
|
|
3116
|
-
|
|
3117
|
-
|
|
3116
|
+
lines2.push(`# ${bpVar(bp, "PROJECT_NAME", config2.projectName || "Project")} - AI Agent Instructions`);
|
|
3117
|
+
lines2.push("");
|
|
3118
3118
|
if (config2.useGitWorktrees) {
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
}
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
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
|
-
|
|
3146
|
+
lines2.push(`**Architecture Pattern**: ${bpVar(bp, "ARCHITECTURE_PATTERN", archValue)}`);
|
|
3147
3147
|
}
|
|
3148
3148
|
if (config2.isPublic !== void 0) {
|
|
3149
|
-
|
|
3149
|
+
lines2.push(`**Visibility**: ${config2.isPublic ? "Public repository" : "Private repository"}`);
|
|
3150
3150
|
}
|
|
3151
3151
|
if (config2.devOS) {
|
|
3152
|
-
|
|
3152
|
+
lines2.push(`**Development OS**: ${formatDevOSDisplay(config2)}`);
|
|
3153
3153
|
}
|
|
3154
|
-
|
|
3154
|
+
lines2.push("");
|
|
3155
3155
|
const hasRepoInfoAgents = config2.repoUrl || config2.repoHosts?.length || config2.repoHost;
|
|
3156
3156
|
if (hasRepoInfoAgents) {
|
|
3157
|
-
|
|
3157
|
+
lines2.push("### Repository");
|
|
3158
3158
|
if (config2.repoUrl) {
|
|
3159
|
-
|
|
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
|
-
|
|
3179
|
+
lines2.push(`- **Platform${hosts.length > 1 ? "s" : ""}**: ${hostLabels}`);
|
|
3180
3180
|
if (hosts.length > 1 && config2.multiRepoReason) {
|
|
3181
|
-
|
|
3181
|
+
lines2.push(`- **Why multiple platforms**: ${config2.multiRepoReason}`);
|
|
3182
3182
|
}
|
|
3183
3183
|
}
|
|
3184
|
-
|
|
3184
|
+
lines2.push("");
|
|
3185
3185
|
}
|
|
3186
3186
|
if (config2.exampleRepoUrl || config2.documentationUrl) {
|
|
3187
|
-
|
|
3187
|
+
lines2.push("### Reference Materials");
|
|
3188
3188
|
if (config2.exampleRepoUrl) {
|
|
3189
|
-
|
|
3189
|
+
lines2.push(`- **Example Repository**: ${bpVar(bp, "EXAMPLE_REPO_URL", config2.exampleRepoUrl)}`);
|
|
3190
3190
|
}
|
|
3191
3191
|
if (config2.documentationUrl) {
|
|
3192
|
-
|
|
3192
|
+
lines2.push(`- **External Documentation**: ${bpVar(bp, "DOCUMENTATION_URL", config2.documentationUrl)}`);
|
|
3193
3193
|
}
|
|
3194
|
-
|
|
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
|
-
|
|
3199
|
-
|
|
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
|
-
|
|
3204
|
-
|
|
3203
|
+
lines2.push(`### Languages`);
|
|
3204
|
+
lines2.push(`${bpVarArray(bp, "LANGUAGES", langs)}`);
|
|
3205
3205
|
} else {
|
|
3206
|
-
|
|
3207
|
-
langs.forEach((lang) =>
|
|
3206
|
+
lines2.push("### Languages");
|
|
3207
|
+
langs.forEach((lang) => lines2.push(`- ${lang}`));
|
|
3208
3208
|
}
|
|
3209
|
-
|
|
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
|
-
|
|
3215
|
-
|
|
3214
|
+
lines2.push(`### Frameworks & Libraries`);
|
|
3215
|
+
lines2.push(`${bpVarArray(bp, "FRAMEWORKS", fws)}`);
|
|
3216
3216
|
} else {
|
|
3217
|
-
|
|
3218
|
-
fws.forEach((fw) =>
|
|
3217
|
+
lines2.push("### Frameworks & Libraries");
|
|
3218
|
+
fws.forEach((fw) => lines2.push(`- ${fw}`));
|
|
3219
3219
|
}
|
|
3220
|
-
|
|
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
|
-
|
|
3226
|
-
|
|
3225
|
+
lines2.push(`### Database${config2.databases.length > 1 ? "s" : ""}`);
|
|
3226
|
+
lines2.push(`${bpVarArray(bp, "DATABASES", dbs)}`);
|
|
3227
3227
|
} else {
|
|
3228
|
-
|
|
3229
|
-
dbs.forEach((db) =>
|
|
3228
|
+
lines2.push(`### Database${config2.databases.length > 1 ? "s" : ""}`);
|
|
3229
|
+
dbs.forEach((db) => lines2.push(`- ${db}`));
|
|
3230
3230
|
}
|
|
3231
|
-
|
|
3231
|
+
lines2.push("");
|
|
3232
3232
|
}
|
|
3233
3233
|
if (tooling.length > 0) {
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3234
|
+
lines2.push("### Tooling");
|
|
3235
|
+
lines2.push(...tooling);
|
|
3236
|
+
lines2.push("");
|
|
3237
3237
|
}
|
|
3238
3238
|
if (config2.letAiDecide) {
|
|
3239
|
-
|
|
3239
|
+
lines2.push("### AI Technology Selection");
|
|
3240
3240
|
if (config2.languages.length > 0 || config2.frameworks.length > 0) {
|
|
3241
|
-
|
|
3241
|
+
lines2.push("For technologies beyond those listed, analyze the codebase and suggest appropriate solutions.");
|
|
3242
3242
|
} else {
|
|
3243
|
-
|
|
3243
|
+
lines2.push("Analyze the codebase to determine appropriate languages, frameworks, and tools.");
|
|
3244
3244
|
}
|
|
3245
|
-
|
|
3245
|
+
lines2.push("");
|
|
3246
3246
|
}
|
|
3247
3247
|
}
|
|
3248
|
-
|
|
3249
|
-
|
|
3248
|
+
lines2.push("## Development Guidelines");
|
|
3249
|
+
lines2.push("");
|
|
3250
3250
|
if (config2.includePersonalData !== false && (user.skillLevel || user.persona)) {
|
|
3251
|
-
|
|
3251
|
+
lines2.push("### Communication Style");
|
|
3252
3252
|
if (user.skillLevel === "novice" || user.skillLevel === "beginner") {
|
|
3253
|
-
|
|
3254
|
-
|
|
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
|
-
|
|
3257
|
-
|
|
3256
|
+
lines2.push("- Balance explanations with efficiency");
|
|
3257
|
+
lines2.push("- Explain non-obvious decisions, skip basics");
|
|
3258
3258
|
} else if (user.skillLevel) {
|
|
3259
|
-
|
|
3259
|
+
lines2.push("- Be concise and direct");
|
|
3260
3260
|
}
|
|
3261
3261
|
if (user.persona) {
|
|
3262
|
-
|
|
3262
|
+
lines2.push(`- Developer background: ${user.persona.replace(/_/g, " ")} \u2014 adapt responses to this domain expertise`);
|
|
3263
3263
|
}
|
|
3264
3264
|
if (user.skillLevel) {
|
|
3265
|
-
|
|
3265
|
+
lines2.push(`- Skill level: ${user.skillLevel.charAt(0).toUpperCase() + user.skillLevel.slice(1)}`);
|
|
3266
3266
|
}
|
|
3267
|
-
|
|
3267
|
+
lines2.push("");
|
|
3268
3268
|
}
|
|
3269
3269
|
const aiPrefsAgents = aiPreferenceLines(config2);
|
|
3270
3270
|
if (config2.aiBehaviorRules.length > 0 || aiPrefsAgents.length > 0) {
|
|
3271
|
-
|
|
3271
|
+
lines2.push("### Workflow Rules");
|
|
3272
3272
|
config2.aiBehaviorRules.forEach((rule) => {
|
|
3273
3273
|
const ruleText = getRuleDescription(rule);
|
|
3274
|
-
if (ruleText)
|
|
3274
|
+
if (ruleText) lines2.push(`- ${ruleText}`);
|
|
3275
3275
|
});
|
|
3276
|
-
|
|
3276
|
+
lines2.push(...aiPrefsAgents);
|
|
3277
3277
|
if (config2.attemptWorkarounds === true) {
|
|
3278
|
-
|
|
3278
|
+
lines2.push("- When stuck, **attempt creative workarounds** before asking for help");
|
|
3279
3279
|
} else if (config2.attemptWorkarounds === false) {
|
|
3280
|
-
|
|
3280
|
+
lines2.push("- When stuck, **stop and ask** rather than attempting workarounds");
|
|
3281
3281
|
}
|
|
3282
|
-
|
|
3282
|
+
lines2.push("");
|
|
3283
3283
|
}
|
|
3284
|
-
|
|
3285
|
-
|
|
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
|
-
|
|
3303
|
-
|
|
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
|
-
|
|
3316
|
+
lines2.push(bpVar(bp, "IMPORTANT_FILES", allFilesAgents.join(", ")));
|
|
3317
3317
|
} else {
|
|
3318
|
-
allFilesAgents.forEach((f) =>
|
|
3318
|
+
allFilesAgents.forEach((f) => lines2.push(`- ${f}`));
|
|
3319
3319
|
}
|
|
3320
|
-
|
|
3320
|
+
lines2.push("");
|
|
3321
3321
|
}
|
|
3322
3322
|
if (config2.projectType && PROJECT_TYPE_INSTRUCTIONS[config2.projectType]) {
|
|
3323
|
-
|
|
3323
|
+
lines2.push("### Project Context");
|
|
3324
3324
|
PROJECT_TYPE_INSTRUCTIONS[config2.projectType].forEach((instruction) => {
|
|
3325
|
-
|
|
3325
|
+
lines2.push(`- ${instruction}`);
|
|
3326
3326
|
});
|
|
3327
|
-
|
|
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
|
-
|
|
3331
|
-
if (config2.commands.build)
|
|
3332
|
-
if (config2.commands.test)
|
|
3333
|
-
if (config2.commands.lint)
|
|
3334
|
-
if (config2.commands.dev)
|
|
3335
|
-
|
|
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) =>
|
|
3337
|
+
config2.commands.additional.forEach((cmd) => lines2.push(`- \`${cmd}\``));
|
|
3338
3338
|
}
|
|
3339
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3368
|
+
lines2.push(`- **Logging**: ${optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions)}`);
|
|
3369
3369
|
}
|
|
3370
|
-
|
|
3370
|
+
lines2.push(...styleExtrasAgents);
|
|
3371
3371
|
if (config2.codeStyle?.notes) {
|
|
3372
|
-
|
|
3372
|
+
lines2.push(`- **Additional Notes**: ${config2.codeStyle.notes}`);
|
|
3373
3373
|
}
|
|
3374
|
-
|
|
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
|
-
|
|
3379
|
-
|
|
3378
|
+
lines2.push("### Boundaries & Permissions");
|
|
3379
|
+
lines2.push("");
|
|
3380
3380
|
if (config2.boundaries.always?.length) {
|
|
3381
|
-
|
|
3382
|
-
config2.boundaries.always.forEach((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
|
-
|
|
3386
|
-
|
|
3387
|
-
config2.boundaries.ask.forEach((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
|
-
|
|
3391
|
-
|
|
3392
|
-
config2.boundaries.never.forEach((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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3407
|
+
lines2.push("**Testing Levels**:");
|
|
3408
3408
|
config2.testingStrategy.levels.forEach((level) => {
|
|
3409
|
-
|
|
3409
|
+
lines2.push(`- ${levelDescriptions[level] || optionLabel(TEST_LEVELS, level)}`);
|
|
3410
3410
|
});
|
|
3411
3411
|
}
|
|
3412
3412
|
if (config2.testingStrategy.frameworks?.length) {
|
|
3413
|
-
|
|
3413
|
+
lines2.push(`**Frameworks**: ${config2.testingStrategy.frameworks.join(", ")}`);
|
|
3414
3414
|
}
|
|
3415
3415
|
if (config2.testingStrategy.coverage !== void 0) {
|
|
3416
|
-
|
|
3416
|
+
lines2.push(`**Coverage Target**: ${config2.testingStrategy.coverage}% minimum`);
|
|
3417
3417
|
}
|
|
3418
3418
|
if (config2.testingStrategy.notes) {
|
|
3419
|
-
|
|
3419
|
+
lines2.push(`**Notes**: ${config2.testingStrategy.notes}`);
|
|
3420
3420
|
}
|
|
3421
|
-
|
|
3422
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3458
|
+
lines2.push(`- **Deployment Target${config2.deploymentTarget.length > 1 ? "s" : ""}**: ${deployNames}`);
|
|
3459
3459
|
}
|
|
3460
3460
|
if (config2.buildContainer) {
|
|
3461
|
-
|
|
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
|
-
|
|
3471
|
+
lines2.push(`- **Container Registry**: ${registryLabels[config2.containerRegistry] || optionLabel(CONTAINER_REGISTRIES, config2.containerRegistry)}`);
|
|
3472
3472
|
}
|
|
3473
|
-
|
|
3473
|
+
lines2.push(...dockerImageLines(config2));
|
|
3474
3474
|
}
|
|
3475
|
-
|
|
3475
|
+
lines2.push("");
|
|
3476
3476
|
}
|
|
3477
3477
|
const gitWorkflowAgents = gitWorkflowLines(config2);
|
|
3478
3478
|
if (gitWorkflowAgents.length > 0) {
|
|
3479
|
-
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
}
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
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
|
-
|
|
3489
|
+
lines2.push("- **Conventional commits**: Use conventional commit messages (feat:, fix:, docs:, chore:, refactor:, test:, style:)");
|
|
3490
3490
|
}
|
|
3491
3491
|
if (config2.semver) {
|
|
3492
|
-
|
|
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
|
-
|
|
3498
|
+
lines2.push(`- **Dependency updates**: Keep dependencies updated (${tools.join("/")}) configured)`);
|
|
3499
3499
|
}
|
|
3500
|
-
|
|
3500
|
+
lines2.push("");
|
|
3501
3501
|
if (config2.additionalFeedback) {
|
|
3502
|
-
|
|
3503
|
-
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
|
|
3507
|
-
|
|
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
|
-
|
|
3511
|
-
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3515
|
-
|
|
3516
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3525
|
-
|
|
3524
|
+
lines2.push("## \u{1F510} Security Configuration");
|
|
3525
|
+
lines2.push("");
|
|
3526
3526
|
if (security2.authProviders?.length) {
|
|
3527
|
-
|
|
3528
|
-
|
|
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
|
-
|
|
3552
|
+
lines2.push(`- Other: ${security2.authProvidersOther}`);
|
|
3553
3553
|
} else {
|
|
3554
|
-
|
|
3554
|
+
lines2.push(`- ${authProviderLabels[p] || p}`);
|
|
3555
3555
|
}
|
|
3556
3556
|
}
|
|
3557
|
-
|
|
3557
|
+
lines2.push("");
|
|
3558
3558
|
}
|
|
3559
3559
|
if (security2.secretsManagement?.length) {
|
|
3560
|
-
|
|
3561
|
-
|
|
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
|
-
|
|
3584
|
+
lines2.push(`- Other: ${security2.secretsManagementOther}`);
|
|
3585
3585
|
} else {
|
|
3586
|
-
|
|
3586
|
+
lines2.push(`- ${secretsLabels[s] || s}`);
|
|
3587
3587
|
}
|
|
3588
3588
|
}
|
|
3589
|
-
|
|
3589
|
+
lines2.push("");
|
|
3590
3590
|
}
|
|
3591
3591
|
if (security2.securityTooling?.length) {
|
|
3592
|
-
|
|
3593
|
-
|
|
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
|
-
|
|
3624
|
+
lines2.push(`- Other: ${security2.securityToolingOther}`);
|
|
3625
3625
|
} else {
|
|
3626
|
-
|
|
3626
|
+
lines2.push(`- ${toolingLabels[t] || t}`);
|
|
3627
3627
|
}
|
|
3628
3628
|
}
|
|
3629
|
-
|
|
3629
|
+
lines2.push("");
|
|
3630
3630
|
}
|
|
3631
3631
|
if (security2.authPatterns?.length) {
|
|
3632
|
-
|
|
3633
|
-
|
|
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
|
-
|
|
3658
|
+
lines2.push(`- Other: ${security2.authPatternsOther}`);
|
|
3659
3659
|
} else {
|
|
3660
|
-
|
|
3660
|
+
lines2.push(`- ${authLabels[a] || a}`);
|
|
3661
3661
|
}
|
|
3662
3662
|
}
|
|
3663
|
-
|
|
3663
|
+
lines2.push("");
|
|
3664
3664
|
}
|
|
3665
3665
|
if (security2.dataHandling?.length) {
|
|
3666
|
-
|
|
3667
|
-
|
|
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
|
-
|
|
3691
|
+
lines2.push(`- Other: ${security2.dataHandlingOther}`);
|
|
3692
3692
|
} else {
|
|
3693
|
-
|
|
3693
|
+
lines2.push(`- ${dataLabels[d] || d}`);
|
|
3694
3694
|
}
|
|
3695
3695
|
}
|
|
3696
|
-
|
|
3696
|
+
lines2.push("");
|
|
3697
3697
|
}
|
|
3698
3698
|
if (security2.compliance?.length) {
|
|
3699
|
-
|
|
3700
|
-
|
|
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
|
-
|
|
3712
|
+
lines2.push(`- Other: ${security2.complianceOther}`);
|
|
3713
3713
|
} else {
|
|
3714
|
-
|
|
3714
|
+
lines2.push(`- ${complianceLabels[c] || c}`);
|
|
3715
3715
|
}
|
|
3716
3716
|
}
|
|
3717
|
-
|
|
3717
|
+
lines2.push("");
|
|
3718
3718
|
}
|
|
3719
3719
|
if (security2.analytics?.length) {
|
|
3720
|
-
|
|
3721
|
-
|
|
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
|
-
|
|
3735
|
+
lines2.push(`- Other: ${security2.analyticsOther}`);
|
|
3736
3736
|
} else {
|
|
3737
|
-
|
|
3737
|
+
lines2.push(`- ${analyticsLabels[a] || a}`);
|
|
3738
3738
|
}
|
|
3739
3739
|
}
|
|
3740
|
-
|
|
3740
|
+
lines2.push("");
|
|
3741
3741
|
}
|
|
3742
3742
|
if (security2.additionalNotes) {
|
|
3743
|
-
|
|
3744
|
-
|
|
3745
|
-
|
|
3743
|
+
lines2.push("### Notes");
|
|
3744
|
+
lines2.push(security2.additionalNotes);
|
|
3745
|
+
lines2.push("");
|
|
3746
3746
|
}
|
|
3747
3747
|
}
|
|
3748
|
-
|
|
3749
|
-
|
|
3750
|
-
|
|
3751
|
-
|
|
3752
|
-
|
|
3753
|
-
|
|
3754
|
-
|
|
3755
|
-
return
|
|
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
|
|
4196
|
+
const lines2 = [];
|
|
4197
4197
|
const bp = config2.blueprintMode;
|
|
4198
|
-
|
|
4199
|
-
|
|
4200
|
-
|
|
4201
|
-
|
|
4202
|
-
|
|
4203
|
-
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4209
|
-
|
|
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
|
-
|
|
4212
|
-
|
|
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
|
-
|
|
4215
|
+
lines2.push(` - ${cleanLang.toLowerCase()}`);
|
|
4216
4216
|
});
|
|
4217
|
-
|
|
4217
|
+
lines2.push("");
|
|
4218
4218
|
}
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
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
|
-
|
|
4225
|
+
lines2.push(`# Description: ${bpVar(bp, "PROJECT_DESCRIPTION", config2.projectDescription)}`);
|
|
4226
4226
|
}
|
|
4227
|
-
|
|
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
|
-
|
|
4242
|
+
lines2.push(`# Architecture: ${archLabels[config2.architecturePattern] || optionLabel(ARCHITECTURE_PATTERNS, config2.architecturePattern)}`);
|
|
4243
4243
|
}
|
|
4244
|
-
|
|
4244
|
+
lines2.push("#");
|
|
4245
4245
|
if (config2.frameworks.length > 0 || config2.databases && config2.databases.length > 0) {
|
|
4246
|
-
|
|
4247
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4254
|
+
lines2.push(`# Databases: ${dbs.join(", ")}`);
|
|
4255
4255
|
}
|
|
4256
|
-
|
|
4256
|
+
lines2.push("#");
|
|
4257
4257
|
}
|
|
4258
|
-
|
|
4259
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4280
|
+
lines2.push(`# Error Handling: ${errorDesc[config2.codeStyle.errorHandling] || config2.codeStyle.errorHandling}`);
|
|
4281
4281
|
}
|
|
4282
4282
|
if (config2.codeStyle?.loggingConventions) {
|
|
4283
|
-
|
|
4283
|
+
lines2.push(`# Logging: ${optionLabel(LOGGING_OPTIONS, config2.codeStyle.loggingConventions)}`);
|
|
4284
4284
|
}
|
|
4285
4285
|
if (config2.codeStyle?.notes) {
|
|
4286
|
-
|
|
4286
|
+
lines2.push(`# Style Notes: ${config2.codeStyle.notes}`);
|
|
4287
4287
|
}
|
|
4288
|
-
|
|
4288
|
+
lines2.push("#");
|
|
4289
4289
|
if (config2.includePersonalData !== false && user.skillLevel) {
|
|
4290
|
-
|
|
4291
|
-
|
|
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
|
-
|
|
4294
|
-
|
|
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
|
-
|
|
4296
|
+
lines2.push(`# Developer Background: ${user.persona.replace(/_/g, " ")} - adapt responses to this domain expertise`);
|
|
4297
4297
|
}
|
|
4298
|
-
|
|
4298
|
+
lines2.push("#");
|
|
4299
4299
|
}
|
|
4300
4300
|
if (config2.aiBehaviorRules.length > 0) {
|
|
4301
|
-
|
|
4302
|
-
|
|
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)
|
|
4305
|
+
if (ruleText) lines2.push(`# - ${ruleText}`);
|
|
4306
4306
|
});
|
|
4307
|
-
|
|
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
|
-
|
|
4312
|
-
|
|
4313
|
-
if (config2.commands.build)
|
|
4314
|
-
if (config2.commands.test)
|
|
4315
|
-
if (config2.commands.lint)
|
|
4316
|
-
if (config2.commands.dev)
|
|
4317
|
-
|
|
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
|
-
|
|
4322
|
-
|
|
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
|
-
|
|
4324
|
+
lines2.push("# \u2705 ALWAYS DO: " + config2.boundaries.always.join(", "));
|
|
4325
4325
|
}
|
|
4326
4326
|
if (config2.boundaries.ask?.length) {
|
|
4327
|
-
|
|
4327
|
+
lines2.push("# \u2753 ASK FIRST: " + config2.boundaries.ask.join(", "));
|
|
4328
4328
|
}
|
|
4329
4329
|
if (config2.boundaries.never?.length) {
|
|
4330
|
-
|
|
4330
|
+
lines2.push("# \u{1F6AB} NEVER DO: " + config2.boundaries.never.join(", "));
|
|
4331
4331
|
}
|
|
4332
|
-
|
|
4332
|
+
lines2.push("#");
|
|
4333
4333
|
}
|
|
4334
4334
|
if (config2.testingStrategy && (config2.testingStrategy.levels?.length || config2.testingStrategy.frameworks?.length)) {
|
|
4335
|
-
|
|
4336
|
-
|
|
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
|
-
|
|
4338
|
+
lines2.push(`# Testing Levels: ${config2.testingStrategy.levels.join(", ")}`);
|
|
4339
4339
|
}
|
|
4340
4340
|
if (config2.testingStrategy.frameworks?.length) {
|
|
4341
|
-
|
|
4341
|
+
lines2.push(`# Frameworks: ${config2.testingStrategy.frameworks.join(", ")}`);
|
|
4342
4342
|
}
|
|
4343
4343
|
if (config2.testingStrategy.coverage) {
|
|
4344
|
-
|
|
4344
|
+
lines2.push(`# Coverage Target: ${config2.testingStrategy.coverage}%`);
|
|
4345
4345
|
}
|
|
4346
|
-
|
|
4346
|
+
lines2.push("#");
|
|
4347
4347
|
}
|
|
4348
4348
|
const hasCiCd = config2.cicd?.length > 0 || config2.deploymentTarget?.length || config2.buildContainer;
|
|
4349
4349
|
if (hasCiCd) {
|
|
4350
|
-
|
|
4351
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4374
|
+
lines2.push(`# Deploy: ${config2.deploymentTarget.map((d) => deployLabels[d] || optionLabel(DEPLOYMENT_TARGETS, d)).join(", ")}`);
|
|
4375
4375
|
}
|
|
4376
|
-
|
|
4376
|
+
lines2.push("#");
|
|
4377
4377
|
}
|
|
4378
4378
|
if (config2.projectType && PROJECT_TYPE_INSTRUCTIONS[config2.projectType]) {
|
|
4379
|
-
|
|
4380
|
-
|
|
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
|
-
|
|
4391
|
-
|
|
4390
|
+
lines2.push(`# Type: ${projectTypeLabels[config2.projectType] || config2.projectType}`);
|
|
4391
|
+
lines2.push("# Guidelines:");
|
|
4392
4392
|
PROJECT_TYPE_INSTRUCTIONS[config2.projectType].forEach((instruction) => {
|
|
4393
|
-
|
|
4393
|
+
lines2.push(`# - ${instruction}`);
|
|
4394
4394
|
});
|
|
4395
|
-
|
|
4396
|
-
}
|
|
4397
|
-
|
|
4398
|
-
|
|
4399
|
-
|
|
4400
|
-
|
|
4401
|
-
|
|
4402
|
-
|
|
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
|
-
|
|
4404
|
+
lines2.push("# - Use conventional commits (feat:, fix:, docs:, chore:)");
|
|
4405
4405
|
}
|
|
4406
4406
|
if (config2.semver) {
|
|
4407
|
-
|
|
4407
|
+
lines2.push("# - Follow semantic versioning (MAJOR.MINOR.PATCH)");
|
|
4408
4408
|
}
|
|
4409
|
-
|
|
4409
|
+
lines2.push("#");
|
|
4410
4410
|
if (config2.additionalFeedback) {
|
|
4411
|
-
|
|
4412
|
-
|
|
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) =>
|
|
4415
|
-
|
|
4414
|
+
feedbackLines.forEach((line) => lines2.push(`# ${line}`));
|
|
4415
|
+
lines2.push("#");
|
|
4416
4416
|
}
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
return
|
|
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
|
|
6673
|
-
const previewLines =
|
|
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 (
|
|
6691
|
+
if (lines2.length > 50) {
|
|
6688
6692
|
console.log();
|
|
6689
|
-
console.log(chalk5.gray(`... ${
|
|
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
|
|
6755
|
-
for (const line of
|
|
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
|
|
8168
|
-
for (const line of
|
|
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 = "
|
|
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
|
|
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(
|
|
10206
|
+
resolve5(lines2.join("\n"));
|
|
10203
10207
|
return;
|
|
10204
10208
|
}
|
|
10205
|
-
if (line === "" &&
|
|
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
|
-
|
|
10217
|
+
lines2.push(line);
|
|
10214
10218
|
});
|
|
10215
10219
|
rl.on("close", () => {
|
|
10216
|
-
resolve5(
|
|
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(
|
|
10892
|
-
const maxLen = Math.max(...
|
|
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
|
|
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
|
|
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} (${
|
|
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
|
|
13721
|
-
for (const line of
|
|
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
|
|
14123
|
-
const newLines = newText
|
|
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
|
|
15401
|
+
const lines2 = [];
|
|
15395
15402
|
const flush = () => {
|
|
15396
15403
|
if (current) {
|
|
15397
|
-
current.content =
|
|
15404
|
+
current.content = lines2.join("\n");
|
|
15398
15405
|
sections.push(current);
|
|
15399
|
-
} else if (
|
|
15400
|
-
sections.push({ title: "Introduction", level: 0, content:
|
|
15406
|
+
} else if (lines2.join("").trim()) {
|
|
15407
|
+
sections.push({ title: "Introduction", level: 0, content: lines2.join("\n"), source: sourceName });
|
|
15401
15408
|
}
|
|
15402
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
15681
|
+
const lines2 = content.split("\n");
|
|
15675
15682
|
let currentSection = null;
|
|
15676
15683
|
let contentLines = [];
|
|
15677
|
-
for (const line of
|
|
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 = "
|
|
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);
|