lynxprompt 2.1.40 → 2.1.41
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/README.md +31 -1
- package/dist/index.js +307 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -278,12 +278,17 @@ var ApiClient = class {
|
|
|
278
278
|
`/api/v1/hierarchies${query ? `?${query}` : ""}`
|
|
279
279
|
);
|
|
280
280
|
}
|
|
281
|
-
|
|
281
|
+
/**
|
|
282
|
+
* A hierarchy and its blueprints. With includeContent the server returns each
|
|
283
|
+
* blueprint's content in the list; a server older than that leaves it out.
|
|
284
|
+
*/
|
|
285
|
+
async getHierarchy(id, { includeContent = false } = {}) {
|
|
282
286
|
let apiId = id;
|
|
283
287
|
if (!id.startsWith("ha_")) {
|
|
284
288
|
apiId = `ha_${id}`;
|
|
285
289
|
}
|
|
286
|
-
|
|
290
|
+
const query = includeContent ? "?include=content" : "";
|
|
291
|
+
return this.request(`/api/v1/hierarchies/${apiId}${query}`);
|
|
287
292
|
}
|
|
288
293
|
async createHierarchy(data) {
|
|
289
294
|
return this.request("/api/v1/hierarchies", {
|
|
@@ -533,7 +538,7 @@ function printOtherLogins() {
|
|
|
533
538
|
// src/commands/whoami.ts
|
|
534
539
|
import chalk3 from "chalk";
|
|
535
540
|
import ora2 from "ora";
|
|
536
|
-
async function whoamiCommand() {
|
|
541
|
+
async function whoamiCommand(options = {}) {
|
|
537
542
|
if (!isAuthenticated()) {
|
|
538
543
|
console.log(chalk3.yellow("Not logged in. Run 'lynxprompt login' to authenticate."));
|
|
539
544
|
process.exit(1);
|
|
@@ -547,6 +552,10 @@ async function whoamiCommand() {
|
|
|
547
552
|
email: user.email,
|
|
548
553
|
name: user.name
|
|
549
554
|
});
|
|
555
|
+
if (options.json) {
|
|
556
|
+
console.log(JSON.stringify({ user }, null, 2));
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
550
559
|
console.log();
|
|
551
560
|
console.log(chalk3.cyan("\u{1F431} LynxPrompt Account"));
|
|
552
561
|
console.log();
|
|
@@ -589,11 +598,16 @@ async function listCommand(options) {
|
|
|
589
598
|
const spinner = ora3("Fetching your blueprints...").start();
|
|
590
599
|
try {
|
|
591
600
|
const limit = parseInt(options.limit, 10) || 20;
|
|
592
|
-
const
|
|
601
|
+
const response = await api.listBlueprints({
|
|
593
602
|
limit,
|
|
594
603
|
visibility: options.visibility
|
|
595
604
|
});
|
|
596
605
|
spinner.stop();
|
|
606
|
+
if (options.json) {
|
|
607
|
+
console.log(JSON.stringify(response, null, 2));
|
|
608
|
+
return;
|
|
609
|
+
}
|
|
610
|
+
const { blueprints, total, has_more } = response;
|
|
597
611
|
if (blueprints.length === 0) {
|
|
598
612
|
console.log();
|
|
599
613
|
console.log(chalk4.yellow("No blueprints found."));
|
|
@@ -853,6 +867,7 @@ var PLATFORMS = [
|
|
|
853
867
|
name: "Claude Code",
|
|
854
868
|
file: "CLAUDE.md",
|
|
855
869
|
blueprintType: "CLAUDE_MD",
|
|
870
|
+
importsFiles: true,
|
|
856
871
|
icon: "\u{1F9E0}",
|
|
857
872
|
gradient: "from-orange-500 to-amber-500",
|
|
858
873
|
note: "Anthropic's agentic coding tool",
|
|
@@ -1146,6 +1161,7 @@ var PLATFORMS = [
|
|
|
1146
1161
|
name: "Gemini CLI",
|
|
1147
1162
|
file: "GEMINI.md",
|
|
1148
1163
|
blueprintType: "GEMINI_MD",
|
|
1164
|
+
importsFiles: true,
|
|
1149
1165
|
icon: "\u{1F48E}",
|
|
1150
1166
|
gradient: "from-blue-500 to-cyan-500",
|
|
1151
1167
|
note: "Google's Gemini in terminal",
|
|
@@ -1190,6 +1206,18 @@ var PLATFORMS = [
|
|
|
1190
1206
|
category: "other",
|
|
1191
1207
|
format: "markdown"
|
|
1192
1208
|
},
|
|
1209
|
+
{
|
|
1210
|
+
id: "devin",
|
|
1211
|
+
name: "Devin",
|
|
1212
|
+
file: ".devin/rules/project.md",
|
|
1213
|
+
rulesDirectory: ".devin/rules/",
|
|
1214
|
+
icon: "\u{1F6E0}\uFE0F",
|
|
1215
|
+
gradient: "from-emerald-600 to-teal-700",
|
|
1216
|
+
note: "Cognition's AI software engineer",
|
|
1217
|
+
category: "other",
|
|
1218
|
+
format: "markdown",
|
|
1219
|
+
url: "https://devin.ai"
|
|
1220
|
+
},
|
|
1193
1221
|
{
|
|
1194
1222
|
id: "firebender",
|
|
1195
1223
|
name: "Firebender",
|
|
@@ -1345,6 +1373,53 @@ var COMMANDS = [
|
|
|
1345
1373
|
note: "Custom commands for OpenCode TUI"
|
|
1346
1374
|
}
|
|
1347
1375
|
];
|
|
1376
|
+
var SKILL_BLUEPRINT_TYPE = "AGENT_SKILL";
|
|
1377
|
+
var SKILL_DIRECTORIES = [
|
|
1378
|
+
".claude/skills",
|
|
1379
|
+
".agents/skills",
|
|
1380
|
+
".github/skills",
|
|
1381
|
+
".cursor/skills",
|
|
1382
|
+
".gemini/skills",
|
|
1383
|
+
".opencode/skills"
|
|
1384
|
+
];
|
|
1385
|
+
function skillFolder(bp) {
|
|
1386
|
+
const lines = (bp.content ?? "").split("\n").map((l) => l.trimEnd());
|
|
1387
|
+
const end = lines[0] === "---" ? lines.indexOf("---", 1) : -1;
|
|
1388
|
+
const nameLine = end > 0 ? lines.slice(1, end).find((l) => l.startsWith("name:")) : void 0;
|
|
1389
|
+
const name = nameLine?.slice("name:".length).trim().replace(/^["']|["']$/g, "");
|
|
1390
|
+
const slug = (name || bp.name || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").split("-").filter(Boolean).join("-");
|
|
1391
|
+
return slug || "skill";
|
|
1392
|
+
}
|
|
1393
|
+
var MCP_BLUEPRINT_TYPE = "MCP_CONFIG";
|
|
1394
|
+
var MCP_CONFIGS = [
|
|
1395
|
+
{ id: "claude-mcp", name: "Claude Code", file: ".mcp.json", key: "mcpServers" },
|
|
1396
|
+
{ id: "cursor-mcp", name: "Cursor", file: ".cursor/mcp.json", key: "mcpServers" },
|
|
1397
|
+
{ id: "vscode-mcp", name: "VS Code (Copilot)", file: ".vscode/mcp.json", key: "servers" },
|
|
1398
|
+
{ id: "kiro-mcp", name: "Kiro", file: ".kiro/settings/mcp.json", key: "mcpServers" }
|
|
1399
|
+
];
|
|
1400
|
+
function convertMcpConfig(content, targetId) {
|
|
1401
|
+
const target = MCP_CONFIGS.find((c) => c.id === targetId);
|
|
1402
|
+
if (!target) throw new Error(`Unknown MCP target: ${targetId}`);
|
|
1403
|
+
const source = JSON.parse(content);
|
|
1404
|
+
const servers = source.mcpServers ?? source.servers;
|
|
1405
|
+
if (!servers || typeof servers !== "object" || Array.isArray(servers)) {
|
|
1406
|
+
throw new Error('No "mcpServers" or "servers" object in the MCP config');
|
|
1407
|
+
}
|
|
1408
|
+
const out = {};
|
|
1409
|
+
if (target.key === "servers") {
|
|
1410
|
+
out.servers = Object.fromEntries(
|
|
1411
|
+
Object.entries(servers).map(([name, server]) => [
|
|
1412
|
+
name,
|
|
1413
|
+
server.type ? server : { type: server.url ? "http" : "stdio", ...server }
|
|
1414
|
+
])
|
|
1415
|
+
);
|
|
1416
|
+
if (source.inputs) out.inputs = source.inputs;
|
|
1417
|
+
} else {
|
|
1418
|
+
out[target.key] = servers;
|
|
1419
|
+
}
|
|
1420
|
+
return `${JSON.stringify(out, null, 2)}
|
|
1421
|
+
`;
|
|
1422
|
+
}
|
|
1348
1423
|
function getPlatform(id) {
|
|
1349
1424
|
return PLATFORMS.find((p) => p.id === id);
|
|
1350
1425
|
}
|
|
@@ -1371,6 +1446,17 @@ var BLUEPRINT_TYPE_ALIASES = {
|
|
|
1371
1446
|
function platformForBlueprintType(type) {
|
|
1372
1447
|
return PLATFORMS.find((p) => p.blueprintType === type)?.id ?? BLUEPRINT_TYPE_ALIASES[type];
|
|
1373
1448
|
}
|
|
1449
|
+
var AGENTS_MD_POINTER = "@AGENTS.md\n";
|
|
1450
|
+
function agentsMdPointerFiles(targets) {
|
|
1451
|
+
const pointers = /* @__PURE__ */ new Set();
|
|
1452
|
+
if (!targets.some((t) => t.file === "AGENTS.md")) return pointers;
|
|
1453
|
+
for (const { file } of targets) {
|
|
1454
|
+
if (file === "AGENTS.md") continue;
|
|
1455
|
+
const readers = targets.filter((t) => t.file === file);
|
|
1456
|
+
if (readers.every((t) => getPlatform(t.platform)?.importsFiles)) pointers.add(file);
|
|
1457
|
+
}
|
|
1458
|
+
return pointers;
|
|
1459
|
+
}
|
|
1374
1460
|
var COMMAND_COUNT = COMMANDS.length;
|
|
1375
1461
|
|
|
1376
1462
|
// src/utils/generator.ts
|
|
@@ -1860,11 +1946,11 @@ var STATIC_FILE_PATHS = {
|
|
|
1860
1946
|
};
|
|
1861
1947
|
function generateConfig(options) {
|
|
1862
1948
|
const files = {};
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1949
|
+
const platforms = options.platforms.filter((platform2) => PLATFORM_FILES2[platform2]);
|
|
1950
|
+
const pointers = options.pointerFiles ? agentsMdPointerFiles(platforms.map((platform2) => ({ platform: platform2, file: PLATFORM_FILES2[platform2] }))) : /* @__PURE__ */ new Set();
|
|
1951
|
+
for (const platform2 of platforms) {
|
|
1952
|
+
const file = PLATFORM_FILES2[platform2];
|
|
1953
|
+
files[file] = pointers.has(file) ? AGENTS_MD_POINTER : generateFileContent(options, platform2);
|
|
1868
1954
|
}
|
|
1869
1955
|
const createLocalStaticFiles = options.staticFileHandling !== "config_only";
|
|
1870
1956
|
if (options.staticFiles && options.staticFiles.length > 0 && createLocalStaticFiles) {
|
|
@@ -1927,6 +2013,8 @@ function generateFileContent(options, platform2) {
|
|
|
1927
2013
|
sections.push("---", "inclusion: always", "---", "");
|
|
1928
2014
|
} else if (platform2 === "augment") {
|
|
1929
2015
|
sections.push("---", "type: always_apply", "---", "");
|
|
2016
|
+
} else if (platform2 === "devin") {
|
|
2017
|
+
sections.push("---", "trigger: always_on", "---", "");
|
|
1930
2018
|
}
|
|
1931
2019
|
sections.push(`# ${projectName} - AI Assistant Configuration`);
|
|
1932
2020
|
sections.push("");
|
|
@@ -2919,6 +3007,8 @@ function slugify(name) {
|
|
|
2919
3007
|
}
|
|
2920
3008
|
function blueprintFilename(bp) {
|
|
2921
3009
|
if (bp.repository_path) return bp.repository_path;
|
|
3010
|
+
if (bp.type === SKILL_BLUEPRINT_TYPE) return `${SKILL_DIRECTORIES[0]}/${skillFolder(bp)}/SKILL.md`;
|
|
3011
|
+
if (bp.type === MCP_BLUEPRINT_TYPE) return MCP_CONFIGS[0].file;
|
|
2922
3012
|
const platform2 = platformForBlueprintType(bp.type);
|
|
2923
3013
|
if (platform2 && PLATFORM_FILES2[platform2]) return PLATFORM_FILES2[platform2];
|
|
2924
3014
|
const command = COMMANDS.find((c) => c.id === platform2);
|
|
@@ -2947,11 +3037,28 @@ var atPath = (relativePath, file) => {
|
|
|
2947
3037
|
const p = normPath(relativePath);
|
|
2948
3038
|
return p === file || p.endsWith(`/${file}`);
|
|
2949
3039
|
};
|
|
3040
|
+
var inSkillFolder = (relativePath, dir) => {
|
|
3041
|
+
const parts = normPath(relativePath).split("/");
|
|
3042
|
+
const n = parts.length;
|
|
3043
|
+
return n >= 4 && parts[n - 1] === "skill.md" && parts.slice(n - 4, n - 2).join("/") === dir;
|
|
3044
|
+
};
|
|
2950
3045
|
var inFolder = (relativePath, folder) => {
|
|
2951
3046
|
const p = normPath(relativePath);
|
|
2952
3047
|
return p.startsWith(folder) || p.includes(`/${folder}`);
|
|
2953
3048
|
};
|
|
2954
3049
|
var CONFIG_PATTERNS = [
|
|
3050
|
+
// Agent Skills: <tool>/skills/<skill name>/SKILL.md
|
|
3051
|
+
...SKILL_DIRECTORIES.map((dir) => ({
|
|
3052
|
+
match: (p) => inSkillFolder(p, dir),
|
|
3053
|
+
type: SKILL_BLUEPRINT_TYPE,
|
|
3054
|
+
label: "Agent Skill"
|
|
3055
|
+
})),
|
|
3056
|
+
// MCP server configs
|
|
3057
|
+
...MCP_CONFIGS.map((c) => ({
|
|
3058
|
+
match: (p) => atPath(p, c.file),
|
|
3059
|
+
type: MCP_BLUEPRINT_TYPE,
|
|
3060
|
+
label: `MCP Servers (${c.name})`
|
|
3061
|
+
})),
|
|
2955
3062
|
// Commands: one file per command in the tool's folder
|
|
2956
3063
|
...COMMANDS.map((c) => ({
|
|
2957
3064
|
match: (p) => inFolder(p, `${c.directory}/`) && p.endsWith(c.extension),
|
|
@@ -3032,24 +3139,26 @@ function getSourceFromVisibility(visibility) {
|
|
|
3032
3139
|
function isHierarchyId(id) {
|
|
3033
3140
|
return id.startsWith("ha_");
|
|
3034
3141
|
}
|
|
3035
|
-
async function pullCommand(
|
|
3142
|
+
async function pullCommand(ids, options) {
|
|
3036
3143
|
if (!isAuthenticated()) {
|
|
3037
3144
|
console.log(
|
|
3038
3145
|
chalk5.yellow("Not logged in. Run 'lynxp login' to authenticate.")
|
|
3039
3146
|
);
|
|
3040
3147
|
process.exit(1);
|
|
3041
3148
|
}
|
|
3042
|
-
|
|
3043
|
-
|
|
3044
|
-
|
|
3045
|
-
|
|
3149
|
+
for (const id of Array.isArray(ids) ? ids : [ids]) {
|
|
3150
|
+
if (isHierarchyId(id)) {
|
|
3151
|
+
await pullHierarchy(id, options);
|
|
3152
|
+
} else {
|
|
3153
|
+
await pullBlueprint(id, options);
|
|
3154
|
+
}
|
|
3046
3155
|
}
|
|
3047
3156
|
}
|
|
3048
3157
|
async function pullHierarchy(id, options) {
|
|
3049
3158
|
const cwd = process.cwd();
|
|
3050
3159
|
const spinner = ora4(`Fetching hierarchy ${chalk5.cyan(id)}...`).start();
|
|
3051
3160
|
try {
|
|
3052
|
-
const response = await api.getHierarchy(id);
|
|
3161
|
+
const response = await api.getHierarchy(id, { includeContent: !options.preview });
|
|
3053
3162
|
const { hierarchy, blueprints } = response;
|
|
3054
3163
|
spinner.stop();
|
|
3055
3164
|
console.log();
|
|
@@ -3112,7 +3221,7 @@ async function pullHierarchy(id, options) {
|
|
|
3112
3221
|
continue;
|
|
3113
3222
|
}
|
|
3114
3223
|
}
|
|
3115
|
-
const
|
|
3224
|
+
const blueprint = typeof bp.content === "string" ? bp : (await api.getBlueprint(bp.id)).blueprint;
|
|
3116
3225
|
if (!blueprint.content) {
|
|
3117
3226
|
console.log(chalk5.yellow(` \u26A0 No content: ${filename}`));
|
|
3118
3227
|
skipped++;
|
|
@@ -4111,19 +4220,19 @@ function inferBlueprintType(filePath) {
|
|
|
4111
4220
|
function confirmSensitive(options, spinner) {
|
|
4112
4221
|
return async (matches) => {
|
|
4113
4222
|
spinner?.stop();
|
|
4114
|
-
console.log(chalk6.yellow("\n\u26A0 This blueprint
|
|
4223
|
+
console.log(chalk6.yellow("\n\u26A0 This blueprint may contain secrets:"));
|
|
4115
4224
|
for (const m of matches) {
|
|
4116
4225
|
console.log(chalk6.gray(` line ${m.line}: ${m.type}${m.snippet ? ` (${m.snippet})` : ""}`));
|
|
4117
4226
|
}
|
|
4118
4227
|
let publish = false;
|
|
4119
4228
|
if (options.allowSensitive) {
|
|
4120
|
-
console.log(chalk6.gray("
|
|
4229
|
+
console.log(chalk6.gray(" Pushing anyway (--allow-sensitive)."));
|
|
4121
4230
|
publish = true;
|
|
4122
4231
|
} else if (!options.yes && process.stdin.isTTY) {
|
|
4123
4232
|
const answer = await prompts2({
|
|
4124
4233
|
type: "confirm",
|
|
4125
4234
|
name: "publish",
|
|
4126
|
-
message: "
|
|
4235
|
+
message: "Push it anyway?",
|
|
4127
4236
|
initial: false
|
|
4128
4237
|
});
|
|
4129
4238
|
publish = answer.publish === true;
|
|
@@ -4132,7 +4241,7 @@ function confirmSensitive(options, spinner) {
|
|
|
4132
4241
|
spinner?.start();
|
|
4133
4242
|
} else {
|
|
4134
4243
|
console.log(
|
|
4135
|
-
chalk6.gray(" Remove them,
|
|
4244
|
+
chalk6.gray(" Remove them, or run again with --allow-sensitive to push anyway.")
|
|
4136
4245
|
);
|
|
4137
4246
|
}
|
|
4138
4247
|
return publish;
|
|
@@ -6652,7 +6761,7 @@ var TEST_FRAMEWORKS2 = TEST_FRAMEWORKS;
|
|
|
6652
6761
|
|
|
6653
6762
|
// src/commands/wizard.ts
|
|
6654
6763
|
var DRAFTS_DIR = ".lynxprompt/drafts";
|
|
6655
|
-
var CLI_VERSION = "2.1.
|
|
6764
|
+
var CLI_VERSION = "2.1.41";
|
|
6656
6765
|
async function saveDraftLocally(name, config2, stepReached) {
|
|
6657
6766
|
const draftsPath = join3(process.cwd(), DRAFTS_DIR);
|
|
6658
6767
|
await mkdir3(draftsPath, { recursive: true });
|
|
@@ -7790,8 +7899,11 @@ async function runWizardWithDraftProtection(options) {
|
|
|
7790
7899
|
...config2,
|
|
7791
7900
|
blueprintMode: options.blueprint || config2.blueprintMode || false,
|
|
7792
7901
|
variables,
|
|
7793
|
-
enableAutoUpdate: false
|
|
7902
|
+
enableAutoUpdate: false,
|
|
7794
7903
|
// Don't generate curl header yet
|
|
7904
|
+
// One rule set: CLAUDE.md/GEMINI.md import AGENTS.md. Not with Cloud
|
|
7905
|
+
// Sync, which uploads one of the files and must upload real rules.
|
|
7906
|
+
pointerFiles: options.pointers !== false && !config2.enableAutoUpdate
|
|
7795
7907
|
};
|
|
7796
7908
|
let files = generateConfig({ ...finalConfig, apiUrl: getApiUrl() });
|
|
7797
7909
|
let savedBlueprintId = null;
|
|
@@ -7858,7 +7970,8 @@ async function runWizardWithDraftProtection(options) {
|
|
|
7858
7970
|
await mkdir3(dir, { recursive: true });
|
|
7859
7971
|
}
|
|
7860
7972
|
await writeFile3(outputPath, content, "utf-8");
|
|
7861
|
-
|
|
7973
|
+
const note = content === AGENTS_MD_POINTER ? chalk7.gray(" (imports AGENTS.md; --no-pointers for a full copy)") : "";
|
|
7974
|
+
console.log(` ${chalk7.cyan("\u2192")} ${chalk7.bold(filename)}${note}`);
|
|
7862
7975
|
if (savedBlueprintId && syncedFile && syncedFile.file === filename) {
|
|
7863
7976
|
await trackBlueprint(process.cwd(), {
|
|
7864
7977
|
id: savedBlueprintId,
|
|
@@ -10027,8 +10140,13 @@ async function searchCommand(query, options) {
|
|
|
10027
10140
|
const spinner = ora7(`Searching for "${query}"...`).start();
|
|
10028
10141
|
try {
|
|
10029
10142
|
const limit = parseInt(options.limit, 10) || 20;
|
|
10030
|
-
const
|
|
10143
|
+
const response = await api.searchBlueprints(query, limit);
|
|
10031
10144
|
spinner.stop();
|
|
10145
|
+
if (options.json) {
|
|
10146
|
+
console.log(JSON.stringify(response, null, 2));
|
|
10147
|
+
return;
|
|
10148
|
+
}
|
|
10149
|
+
const { templates, total, hasMore } = response;
|
|
10032
10150
|
if (templates.length === 0) {
|
|
10033
10151
|
console.log();
|
|
10034
10152
|
console.log(chalk8.yellow(`No blueprints found for "${query}".`));
|
|
@@ -10259,6 +10377,94 @@ import { readFile as readFile6, readdir as readdir2, stat } from "fs/promises";
|
|
|
10259
10377
|
import { join as join5 } from "path";
|
|
10260
10378
|
import { existsSync as existsSync3 } from "fs";
|
|
10261
10379
|
import * as yaml2 from "yaml";
|
|
10380
|
+
|
|
10381
|
+
// src/utils/hidden-unicode.ts
|
|
10382
|
+
var NAMES = {
|
|
10383
|
+
1564: "ARABIC LETTER MARK",
|
|
10384
|
+
6158: "MONGOLIAN VOWEL SEPARATOR",
|
|
10385
|
+
8203: "ZERO WIDTH SPACE",
|
|
10386
|
+
8204: "ZERO WIDTH NON-JOINER",
|
|
10387
|
+
8205: "ZERO WIDTH JOINER",
|
|
10388
|
+
8206: "LEFT-TO-RIGHT MARK",
|
|
10389
|
+
8207: "RIGHT-TO-LEFT MARK",
|
|
10390
|
+
8234: "LEFT-TO-RIGHT EMBEDDING",
|
|
10391
|
+
8235: "RIGHT-TO-LEFT EMBEDDING",
|
|
10392
|
+
8236: "POP DIRECTIONAL FORMATTING",
|
|
10393
|
+
8237: "LEFT-TO-RIGHT OVERRIDE",
|
|
10394
|
+
8238: "RIGHT-TO-LEFT OVERRIDE",
|
|
10395
|
+
8288: "WORD JOINER",
|
|
10396
|
+
8289: "FUNCTION APPLICATION",
|
|
10397
|
+
8290: "INVISIBLE TIMES",
|
|
10398
|
+
8291: "INVISIBLE SEPARATOR",
|
|
10399
|
+
8292: "INVISIBLE PLUS",
|
|
10400
|
+
8294: "LEFT-TO-RIGHT ISOLATE",
|
|
10401
|
+
8295: "RIGHT-TO-LEFT ISOLATE",
|
|
10402
|
+
8296: "FIRST STRONG ISOLATE",
|
|
10403
|
+
8297: "POP DIRECTIONAL ISOLATE",
|
|
10404
|
+
65279: "ZERO WIDTH NO-BREAK SPACE"
|
|
10405
|
+
};
|
|
10406
|
+
var CONTEXTUAL = /* @__PURE__ */ new Set([1564, 8204, 8205, 8206, 8207]);
|
|
10407
|
+
var BLACK_FLAG = 127988;
|
|
10408
|
+
var CANCEL_TAG = 917631;
|
|
10409
|
+
var isTag = (cp) => cp >= 917504 && cp <= 917631;
|
|
10410
|
+
var isVariationSelectorSupplement = (cp) => cp >= 917760 && cp <= 917999;
|
|
10411
|
+
function isHidden(cp) {
|
|
10412
|
+
return cp in NAMES || isTag(cp) || isVariationSelectorSupplement(cp);
|
|
10413
|
+
}
|
|
10414
|
+
function nameOf(cp) {
|
|
10415
|
+
if (cp in NAMES) return NAMES[cp];
|
|
10416
|
+
if (isTag(cp)) return "TAG CHARACTER";
|
|
10417
|
+
return "VARIATION SELECTOR";
|
|
10418
|
+
}
|
|
10419
|
+
var RGI_SUBDIVISIONS = /* @__PURE__ */ new Set(["gbeng", "gbsct", "gbwls"]);
|
|
10420
|
+
function flagTagRunLength(cps, i) {
|
|
10421
|
+
if (cps[i - 1] !== BLACK_FLAG) return 0;
|
|
10422
|
+
let j = i;
|
|
10423
|
+
while (j < cps.length && cps[j] >= 917536 && cps[j] < CANCEL_TAG) j++;
|
|
10424
|
+
if (cps[j] !== CANCEL_TAG) return 0;
|
|
10425
|
+
const code = String.fromCharCode(...cps.slice(i, j).map((cp) => cp - 917504));
|
|
10426
|
+
return RGI_SUBDIVISIONS.has(code) ? j - i + 1 : 0;
|
|
10427
|
+
}
|
|
10428
|
+
var isVisibleNonAscii = (cp) => cp !== void 0 && cp > 127 && !isHidden(cp);
|
|
10429
|
+
function findHiddenUnicode(content) {
|
|
10430
|
+
const cps = Array.from(content, (c) => c.codePointAt(0));
|
|
10431
|
+
const found = [];
|
|
10432
|
+
let line = 1;
|
|
10433
|
+
let column = 0;
|
|
10434
|
+
for (let i = 0; i < cps.length; i++) {
|
|
10435
|
+
const cp = cps[i];
|
|
10436
|
+
if (cp === 10) {
|
|
10437
|
+
line++;
|
|
10438
|
+
column = 0;
|
|
10439
|
+
continue;
|
|
10440
|
+
}
|
|
10441
|
+
column++;
|
|
10442
|
+
if (!isHidden(cp)) continue;
|
|
10443
|
+
if (cp === 65279 && i === 0) continue;
|
|
10444
|
+
if (CONTEXTUAL.has(cp) && isVisibleNonAscii(cps[i - 1]) && isVisibleNonAscii(cps[i + 1])) continue;
|
|
10445
|
+
const flagRun = flagTagRunLength(cps, i);
|
|
10446
|
+
if (flagRun > 0) {
|
|
10447
|
+
i += flagRun - 1;
|
|
10448
|
+
column += flagRun - 1;
|
|
10449
|
+
continue;
|
|
10450
|
+
}
|
|
10451
|
+
found.push({
|
|
10452
|
+
line,
|
|
10453
|
+
column,
|
|
10454
|
+
codePoint: `U+${cp.toString(16).toUpperCase().padStart(4, "0")}`,
|
|
10455
|
+
name: nameOf(cp)
|
|
10456
|
+
});
|
|
10457
|
+
}
|
|
10458
|
+
return found;
|
|
10459
|
+
}
|
|
10460
|
+
function describeHiddenUnicode(filename, found, shown = 5) {
|
|
10461
|
+
const where = found.slice(0, shown).map((h) => `line ${h.line} col ${h.column} ${h.codePoint} ${h.name}`).join("; ");
|
|
10462
|
+
const more = found.length > shown ? `; and ${found.length - shown} more` : "";
|
|
10463
|
+
const n = found.length;
|
|
10464
|
+
return `${filename}: ${n} hidden Unicode character${n === 1 ? "" : "s"} that can carry instructions a reviewer cannot see (${where}${more})`;
|
|
10465
|
+
}
|
|
10466
|
+
|
|
10467
|
+
// src/commands/check.ts
|
|
10262
10468
|
var CONFIG_FILES2 = [
|
|
10263
10469
|
{ path: "AGENTS.md", name: "AGENTS.md" },
|
|
10264
10470
|
{ path: "CLAUDE.md", name: "CLAUDE.md" },
|
|
@@ -10285,6 +10491,7 @@ var CONFIG_DIRS2 = [
|
|
|
10285
10491
|
{ path: ".trae/rules", name: "Trae" },
|
|
10286
10492
|
{ path: ".augment/rules", name: "Augment" },
|
|
10287
10493
|
{ path: ".roo/rules", name: "Roo Code" },
|
|
10494
|
+
{ path: ".devin/rules", name: "Devin" },
|
|
10288
10495
|
{ path: ".kilocode/rules", name: "Kilo Code" },
|
|
10289
10496
|
{ path: ".amazonq/rules", name: "Amazon Q" },
|
|
10290
10497
|
{ path: ".idx/rules", name: "Firebase Studio" },
|
|
@@ -10329,6 +10536,10 @@ function validateMarkdown(content, filename) {
|
|
|
10329
10536
|
}
|
|
10330
10537
|
return { errors, warnings };
|
|
10331
10538
|
}
|
|
10539
|
+
function validateHiddenUnicode(content, filename) {
|
|
10540
|
+
const found = findHiddenUnicode(content);
|
|
10541
|
+
return found.length > 0 ? [describeHiddenUnicode(filename, found)] : [];
|
|
10542
|
+
}
|
|
10332
10543
|
async function validateLynxPromptConfig(cwd) {
|
|
10333
10544
|
const errors = [];
|
|
10334
10545
|
const warnings = [];
|
|
@@ -10392,8 +10603,9 @@ function validateMdc(content, filename) {
|
|
|
10392
10603
|
}
|
|
10393
10604
|
async function checkCommand(options = {}) {
|
|
10394
10605
|
const isCi = options.ci;
|
|
10606
|
+
const isJson = options.json;
|
|
10395
10607
|
const cwd = process.cwd();
|
|
10396
|
-
if (!isCi) {
|
|
10608
|
+
if (!isCi && !isJson) {
|
|
10397
10609
|
console.log();
|
|
10398
10610
|
console.log(chalk10.cyan("\u{1F431} LynxPrompt Check"));
|
|
10399
10611
|
console.log();
|
|
@@ -10404,7 +10616,7 @@ async function checkCommand(options = {}) {
|
|
|
10404
10616
|
warnings: [],
|
|
10405
10617
|
files: []
|
|
10406
10618
|
};
|
|
10407
|
-
const spinner = !isCi ? ora8("Scanning for configuration files...").start() : null;
|
|
10619
|
+
const spinner = !isCi && !isJson ? ora8("Scanning for configuration files...").start() : null;
|
|
10408
10620
|
for (const file of CONFIG_FILES2) {
|
|
10409
10621
|
const filePath = join5(cwd, file.path);
|
|
10410
10622
|
if (existsSync3(filePath) && (await stat(filePath)).isFile()) {
|
|
@@ -10412,7 +10624,7 @@ async function checkCommand(options = {}) {
|
|
|
10412
10624
|
try {
|
|
10413
10625
|
const content = await readFile6(filePath, "utf-8");
|
|
10414
10626
|
const validation = validateMarkdown(content, file.path);
|
|
10415
|
-
result.errors.push(...validation.errors);
|
|
10627
|
+
result.errors.push(...validation.errors, ...validateHiddenUnicode(content, file.path));
|
|
10416
10628
|
result.warnings.push(...validation.warnings);
|
|
10417
10629
|
} catch (error) {
|
|
10418
10630
|
result.errors.push(`${file.path}: Could not read file`);
|
|
@@ -10430,6 +10642,7 @@ async function checkCommand(options = {}) {
|
|
|
10430
10642
|
if (fileStat.isFile()) {
|
|
10431
10643
|
result.files.push(`${dir.path}/${file}`);
|
|
10432
10644
|
const content = await readFile6(filePath, "utf-8");
|
|
10645
|
+
result.errors.push(...validateHiddenUnicode(content, `${dir.path}/${file}`));
|
|
10433
10646
|
if (file.endsWith(".mdc")) {
|
|
10434
10647
|
const validation = validateMdc(content, `${dir.path}/${file}`);
|
|
10435
10648
|
result.errors.push(...validation.errors);
|
|
@@ -10450,7 +10663,10 @@ async function checkCommand(options = {}) {
|
|
|
10450
10663
|
result.warnings.push(...lynxpromptValidation.warnings);
|
|
10451
10664
|
spinner?.stop();
|
|
10452
10665
|
result.valid = result.errors.length === 0;
|
|
10453
|
-
if (
|
|
10666
|
+
if (isJson) {
|
|
10667
|
+
console.log(JSON.stringify(result, null, 2));
|
|
10668
|
+
if (!result.valid || isCi && result.files.length === 0) process.exitCode = 1;
|
|
10669
|
+
} else if (isCi) {
|
|
10454
10670
|
if (!result.valid) {
|
|
10455
10671
|
console.error("\u2717 Validation failed");
|
|
10456
10672
|
for (const error of result.errors) {
|
|
@@ -11509,7 +11725,9 @@ var PLATFORM_FRONTMATTER = {
|
|
|
11509
11725
|
firebender: cursorFrontmatter,
|
|
11510
11726
|
// Firebender reads Cursor-style .mdc rules
|
|
11511
11727
|
kiro: () => ["inclusion: always"],
|
|
11512
|
-
augment: (description) => ["type: always_apply", `description: ${yamlString(description)}`]
|
|
11728
|
+
augment: (description) => ["type: always_apply", `description: ${yamlString(description)}`],
|
|
11729
|
+
devin: () => ["trigger: always_on"]
|
|
11730
|
+
// .devin/rules/ uses Windsurf's rule frontmatter
|
|
11513
11731
|
};
|
|
11514
11732
|
var FRONTMATTER_PATTERN = /^---\r?\n[\s\S]*?\r?\n---[ \t]*(?:\r?\n)+/;
|
|
11515
11733
|
function frontmatterLines(platform2, description) {
|
|
@@ -11631,6 +11849,7 @@ var PLATFORM_NAMES = {
|
|
|
11631
11849
|
codex: "Codex",
|
|
11632
11850
|
openhands: "OpenHands",
|
|
11633
11851
|
crush: "Crush",
|
|
11852
|
+
devin: "Devin",
|
|
11634
11853
|
firebender: "Firebender",
|
|
11635
11854
|
"cursor-command": "Cursor Command",
|
|
11636
11855
|
"claude-command": "Claude Code Command",
|
|
@@ -11659,6 +11878,16 @@ async function convertCommand(first, second, options) {
|
|
|
11659
11878
|
console.log(chalk16.gray(" Convert AI IDE configuration between formats"));
|
|
11660
11879
|
console.log();
|
|
11661
11880
|
const cwd = process.cwd();
|
|
11881
|
+
const mcpTarget = MCP_CONFIGS.find((c) => c.id === target.toLowerCase());
|
|
11882
|
+
const mcpSource = source !== void 0 && matchConfigFile(source)?.type === "MCP_CONFIG";
|
|
11883
|
+
if (mcpTarget || mcpSource) {
|
|
11884
|
+
if (!mcpTarget) {
|
|
11885
|
+
console.log(chalk16.red(` \u2717 An MCP config converts only to another tool's MCP config: ${MCP_CONFIGS.map((c) => c.id).join(", ")}`));
|
|
11886
|
+
process.exit(1);
|
|
11887
|
+
}
|
|
11888
|
+
await convertMcp(cwd, source, mcpTarget, options);
|
|
11889
|
+
return;
|
|
11890
|
+
}
|
|
11662
11891
|
let sourcePath;
|
|
11663
11892
|
let sourcePlatform;
|
|
11664
11893
|
if (source) {
|
|
@@ -11702,6 +11931,9 @@ async function convertCommand(first, second, options) {
|
|
|
11702
11931
|
if (isStructuredPlatform(key)) continue;
|
|
11703
11932
|
console.log(chalk16.gray(` \u2022 ${key.padEnd(15)} \u2192 ${name}`));
|
|
11704
11933
|
}
|
|
11934
|
+
for (const c of MCP_CONFIGS) {
|
|
11935
|
+
console.log(chalk16.gray(` \u2022 ${c.id.padEnd(15)} \u2192 MCP servers for ${c.name} (${c.file})`));
|
|
11936
|
+
}
|
|
11705
11937
|
process.exit(1);
|
|
11706
11938
|
}
|
|
11707
11939
|
const structured = [sourcePlatform, normalizedTarget].find(isStructuredPlatform);
|
|
@@ -11756,6 +11988,42 @@ async function convertCommand(first, second, options) {
|
|
|
11756
11988
|
process.exit(1);
|
|
11757
11989
|
}
|
|
11758
11990
|
}
|
|
11991
|
+
async function convertMcp(cwd, source, target, options) {
|
|
11992
|
+
let sourceFile = source;
|
|
11993
|
+
if (sourceFile === void 0) {
|
|
11994
|
+
for (const c of MCP_CONFIGS) {
|
|
11995
|
+
if (c.id !== target.id && await access6(resolve2(cwd, c.file)).then(() => true, () => false)) {
|
|
11996
|
+
sourceFile = c.file;
|
|
11997
|
+
break;
|
|
11998
|
+
}
|
|
11999
|
+
}
|
|
12000
|
+
}
|
|
12001
|
+
if (sourceFile === void 0) {
|
|
12002
|
+
console.log(chalk16.red(" \u2717 No MCP config found. Looked for:"));
|
|
12003
|
+
for (const c of MCP_CONFIGS) console.log(chalk16.gray(` \u2022 ${c.file}`));
|
|
12004
|
+
process.exit(1);
|
|
12005
|
+
}
|
|
12006
|
+
let converted;
|
|
12007
|
+
try {
|
|
12008
|
+
converted = convertMcpConfig(await readFile9(resolve2(cwd, sourceFile), "utf-8"), target.id);
|
|
12009
|
+
} catch (error) {
|
|
12010
|
+
console.log(chalk16.red(` \u2717 Could not convert ${sourceFile}: ${error instanceof Error ? error.message : "unreadable"}`));
|
|
12011
|
+
process.exit(1);
|
|
12012
|
+
}
|
|
12013
|
+
const outputFile = options.output || target.file;
|
|
12014
|
+
const outputPath = resolve2(cwd, outputFile);
|
|
12015
|
+
const exists = await access6(outputPath).then(() => true, () => false);
|
|
12016
|
+
if (exists && !options.force) {
|
|
12017
|
+
console.log(chalk16.yellow(` \u26A0\uFE0F File already exists: ${outputFile}`));
|
|
12018
|
+
console.log(chalk16.gray(" Use --force to overwrite"));
|
|
12019
|
+
process.exit(1);
|
|
12020
|
+
}
|
|
12021
|
+
const { mkdir: mkdir5 } = await import("fs/promises");
|
|
12022
|
+
await mkdir5(dirname5(outputPath), { recursive: true });
|
|
12023
|
+
await writeFile5(outputPath, converted, "utf-8");
|
|
12024
|
+
console.log(chalk16.green(` \u2713 Converted ${sourceFile} to ${outputFile} (MCP servers for ${target.name})`));
|
|
12025
|
+
console.log();
|
|
12026
|
+
}
|
|
11759
12027
|
|
|
11760
12028
|
// src/commands/merge.ts
|
|
11761
12029
|
import chalk17 from "chalk";
|
|
@@ -12449,20 +12717,20 @@ async function configCommand(action, valueArg) {
|
|
|
12449
12717
|
}
|
|
12450
12718
|
|
|
12451
12719
|
// src/index.ts
|
|
12452
|
-
var CLI_VERSION2 = "2.1.
|
|
12720
|
+
var CLI_VERSION2 = "2.1.41";
|
|
12453
12721
|
var program = new Command();
|
|
12454
12722
|
program.name("lynxprompt").description("CLI for LynxPrompt - Generate AI IDE configuration files").version(CLI_VERSION2);
|
|
12455
|
-
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").action(wizardCommand);
|
|
12456
|
-
program.command("check").description("Validate AI configuration files (for CI/CD)").option("--ci", "CI mode - exit codes only (0=pass, 1=fail)").action(checkCommand);
|
|
12723
|
+
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);
|
|
12724
|
+
program.command("check").description("Validate AI configuration files (for CI/CD)").option("--ci", "CI mode - exit codes only (0=pass, 1=fail)").option("-j, --json", "Output as JSON (for scripting)").action(checkCommand);
|
|
12457
12725
|
program.command("analyze").description("Analyze project configuration without generating files").option("-r, --remote <url>", "Analyze a remote repository (GitHub/GitLab)").option("-j, --json", "Output as JSON (for scripting)").action(analyzeCommand);
|
|
12458
12726
|
program.command("convert <source> [target]").description("Convert AI config between formats (e.g., AGENTS.md \u2192 cursor); with one argument it is the target").option("-o, --output <file>", "Output filename").option("-f, --force", "Overwrite existing output file").action(convertCommand);
|
|
12459
12727
|
program.command("merge <files...>").description("Merge multiple AI configuration files into one").option("-o, --output <file>", "Output filename (default: merged.md)").option("-s, --strategy <type>", "Merge strategy: concat, sections, smart (default: smart)").option("-f, --force", "Overwrite existing output file").option("-i, --interactive", "Review and select sections to include").action(mergeCommand);
|
|
12460
12728
|
program.command("import [path]").description("Scan and import AGENTS.md files from a repository").option("--dry-run", "Preview what would be imported without changes").option("--no-recursive", "Don't scan subdirectories").option("--depth <n>", "Max directory depth to scan", "10").option("--pattern <file>", "Custom config filename to look for").option("-v, --verbose", "Show detailed section information").option("-j, --json", "Output as JSON").action(importCommand);
|
|
12461
12729
|
program.command("status").description("Show current AI configuration and tracked blueprints").action(statusCommand);
|
|
12462
|
-
program.command("pull <
|
|
12463
|
-
program.command("search <query>").description("Search public blueprints in the marketplace").option("-l, --limit <number>", "Number of results", "20").action(searchCommand);
|
|
12464
|
-
program.command("list").description("List your blueprints").option("-l, --limit <number>", "Number of results", "20").option("-v, --visibility <visibility>", "Filter: PRIVATE, TEAM, PUBLIC, or all").action(listCommand);
|
|
12465
|
-
program.command("push [file]").description("Push local file to LynxPrompt cloud as a blueprint").option("-a, --all", "Scan recursively and push ALL AI config files (40+ types)").option("-n, --name <name>", "Blueprint name").option("-d, --description <desc>", "Blueprint description").option("-v, --visibility <vis>", "Visibility: PRIVATE, TEAM, or PUBLIC (default: PRIVATE)").option("-t, --tags <tags>", "Tags (comma-separated)").option("-y, --yes", "Skip prompts").option("-f, --force", "Force push (overwrite remote changes)").option("--allow-sensitive", "
|
|
12730
|
+
program.command("pull <ids...>").description("Download blueprints (bp_xxx) or entire hierarchies (ha_xxx), one or several").option("-o, --output <path>", "Output directory", ".").option("-y, --yes", "Overwrite existing files without prompting").option("--preview", "Preview content without downloading").option("--no-track", "Don't track the blueprint for future syncs").option("--vars <values>", "Fill [[VARIABLES]]: VAR1=value1,VAR2=value2 (others get their defaults)").action(pullCommand);
|
|
12731
|
+
program.command("search <query>").description("Search public blueprints in the marketplace").option("-l, --limit <number>", "Number of results", "20").option("-j, --json", "Output as JSON (for scripting)").action(searchCommand);
|
|
12732
|
+
program.command("list").description("List your blueprints").option("-l, --limit <number>", "Number of results", "20").option("-v, --visibility <visibility>", "Filter: PRIVATE, TEAM, PUBLIC, or all").option("-j, --json", "Output as JSON (for scripting)").action(listCommand);
|
|
12733
|
+
program.command("push [file]").description("Push local file to LynxPrompt cloud as a blueprint").option("-a, --all", "Scan recursively and push ALL AI config files (40+ types)").option("-n, --name <name>", "Blueprint name").option("-d, --description <desc>", "Blueprint description").option("-v, --visibility <vis>", "Visibility: PRIVATE, TEAM, or PUBLIC (default: PRIVATE)").option("-t, --tags <tags>", "Tags (comma-separated)").option("-y, --yes", "Skip prompts").option("-f, --force", "Force push (overwrite remote changes)").option("--allow-sensitive", "Push public content or MCP configs even if they look like they hold secrets").action(pushCommand);
|
|
12466
12734
|
program.command("hierarchies").description("List your blueprint hierarchies (monorepo groupings)").option("-l, --limit <number>", "Number of results", "50").option("-j, --json", "Output as JSON").action(hierarchiesCommand);
|
|
12467
12735
|
program.command("link [file] [blueprint-id]").description("Link a local file to a cloud blueprint for tracking").option("--list", "List all tracked blueprints").action(linkCommand);
|
|
12468
12736
|
program.command("unlink [file]").description("Disconnect a local file from its cloud blueprint").action(unlinkCommand);
|
|
@@ -12470,7 +12738,7 @@ program.command("diff [file-or-id]").description("Compare tracked files with the
|
|
|
12470
12738
|
program.command("sync [file]").description("Pull cloud changes and push local ones for tracked files; conflicts go to <file>.remote").option("--dry-run", "Show what would change without writing or pushing").action(syncCommand);
|
|
12471
12739
|
program.command("login").description("Authenticate with LynxPrompt (opens browser)").action(loginCommand);
|
|
12472
12740
|
program.command("logout").description("Log out and remove stored credentials").action(logoutCommand);
|
|
12473
|
-
program.command("whoami").description("Show current authenticated user").action(whoamiCommand);
|
|
12741
|
+
program.command("whoami").description("Show current authenticated user").option("-j, --json", "Output as JSON (for scripting)").action(whoamiCommand);
|
|
12474
12742
|
program.command("config [action] [value]").description("View or change CLI settings (set-url, reset-url, path)").action(configCommand);
|
|
12475
12743
|
program.addHelpText(
|
|
12476
12744
|
"beforeAll",
|
|
@@ -12500,6 +12768,7 @@ ${chalk21.cyan("Marketplace:")}
|
|
|
12500
12768
|
${chalk21.white("$ lynxp search nextjs")} ${chalk21.gray("Search blueprints")}
|
|
12501
12769
|
${chalk21.white("$ lynxp pull bp_abc123")} ${chalk21.gray("Download and track a blueprint")}
|
|
12502
12770
|
${chalk21.white("$ lynxp pull ha_xyz789")} ${chalk21.gray("Download entire hierarchy")}
|
|
12771
|
+
${chalk21.white("$ lynxp pull bp_a bp_b")} ${chalk21.gray("Download several at once")}
|
|
12503
12772
|
${chalk21.white("$ lynxp push")} ${chalk21.gray("Push local file to cloud")}
|
|
12504
12773
|
${chalk21.white("$ lynxp push --all")} ${chalk21.gray("Push ALL config files recursively")}
|
|
12505
12774
|
${chalk21.white("$ lynxp hierarchies")} ${chalk21.gray("List your hierarchies")}
|
|
@@ -12514,6 +12783,7 @@ ${chalk21.cyan("Blueprint Tracking:")}
|
|
|
12514
12783
|
|
|
12515
12784
|
${chalk21.cyan("CI/CD:")}
|
|
12516
12785
|
${chalk21.white("$ lynxp check --ci")} ${chalk21.gray("Validate config (exit code)")}
|
|
12786
|
+
${chalk21.white("$ lynxp check --json")} ${chalk21.gray("Validation result as JSON")}
|
|
12517
12787
|
|
|
12518
12788
|
${chalk21.cyan("Configuration:")}
|
|
12519
12789
|
${chalk21.white("$ lynxp config")} ${chalk21.gray("Show current settings")}
|