@omnidev-ai/cli 0.16.0 → 0.18.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 +1002 -457
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1287,45 +1287,6 @@ var init_dist = __esm(() => {
|
|
|
1287
1287
|
dist_default = { parse, stringify, TomlDate, TomlError };
|
|
1288
1288
|
});
|
|
1289
1289
|
|
|
1290
|
-
// ../core/src/config/parser.ts
|
|
1291
|
-
function parseOmniConfig(tomlContent) {
|
|
1292
|
-
try {
|
|
1293
|
-
return parse(tomlContent);
|
|
1294
|
-
} catch (error) {
|
|
1295
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1296
|
-
throw new Error(`Invalid TOML in config: ${message}`);
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
function validateCapabilityConfig(parsed) {
|
|
1300
|
-
const cap = parsed["capability"];
|
|
1301
|
-
if (typeof cap !== "object" || cap === null) {
|
|
1302
|
-
throw new Error("capability.id is required in capability.toml");
|
|
1303
|
-
}
|
|
1304
|
-
const capability = cap;
|
|
1305
|
-
if (typeof capability["id"] !== "string") {
|
|
1306
|
-
throw new Error("capability.id is required in capability.toml");
|
|
1307
|
-
}
|
|
1308
|
-
if (typeof capability["name"] !== "string") {
|
|
1309
|
-
throw new Error("capability.name is required in capability.toml");
|
|
1310
|
-
}
|
|
1311
|
-
if (typeof capability["version"] !== "string") {
|
|
1312
|
-
throw new Error("capability.version is required in capability.toml");
|
|
1313
|
-
}
|
|
1314
|
-
}
|
|
1315
|
-
function parseCapabilityConfig(tomlContent) {
|
|
1316
|
-
try {
|
|
1317
|
-
const parsed = parse(tomlContent);
|
|
1318
|
-
validateCapabilityConfig(parsed);
|
|
1319
|
-
return parsed;
|
|
1320
|
-
} catch (error) {
|
|
1321
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1322
|
-
throw new Error(`Invalid capability.toml: ${message}`);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
var init_parser = __esm(() => {
|
|
1326
|
-
init_dist();
|
|
1327
|
-
});
|
|
1328
|
-
|
|
1329
1290
|
// ../core/src/hooks/constants.ts
|
|
1330
1291
|
var HOOK_EVENTS, MATCHER_EVENTS, PROMPT_HOOK_EVENTS, HOOK_TYPES, COMMON_TOOL_MATCHERS, NOTIFICATION_MATCHERS, SESSION_START_MATCHERS, PRE_COMPACT_MATCHERS, DEFAULT_COMMAND_TIMEOUT = 60, DEFAULT_PROMPT_TIMEOUT = 30, VARIABLE_MAPPINGS, HOOKS_CONFIG_FILENAME = "hooks.toml", CLAUDE_HOOKS_CONFIG_FILENAME = "hooks.json", HOOKS_DIRECTORY = "hooks";
|
|
1331
1292
|
var init_constants = __esm(() => {
|
|
@@ -2411,21 +2372,207 @@ var init_loader = __esm(() => {
|
|
|
2411
2372
|
init_constants();
|
|
2412
2373
|
});
|
|
2413
2374
|
|
|
2414
|
-
// ../core/src/
|
|
2415
|
-
|
|
2375
|
+
// ../core/src/providers.ts
|
|
2376
|
+
function normalizeProviderId(provider) {
|
|
2377
|
+
if (provider in PROVIDER_ALIAS_MAP) {
|
|
2378
|
+
return PROVIDER_ALIAS_MAP[provider];
|
|
2379
|
+
}
|
|
2380
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
2381
|
+
}
|
|
2382
|
+
function normalizeProviderApplicability(value, fieldName) {
|
|
2383
|
+
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
2384
|
+
throw new Error(`${fieldName} must be a table of provider = boolean entries`);
|
|
2385
|
+
}
|
|
2386
|
+
const normalized = {};
|
|
2387
|
+
for (const [rawProvider, rawEnabled] of Object.entries(value)) {
|
|
2388
|
+
if (typeof rawEnabled !== "boolean") {
|
|
2389
|
+
throw new Error(`${fieldName}.${rawProvider} must be a boolean`);
|
|
2390
|
+
}
|
|
2391
|
+
const canonicalProvider = normalizeProviderId(rawProvider);
|
|
2392
|
+
const existing = normalized[canonicalProvider];
|
|
2393
|
+
if (existing !== undefined && existing !== rawEnabled) {
|
|
2394
|
+
throw new Error(`Conflicting provider entries in ${fieldName}: ${rawProvider} maps to ${canonicalProvider}`);
|
|
2395
|
+
}
|
|
2396
|
+
normalized[canonicalProvider] = rawEnabled;
|
|
2397
|
+
}
|
|
2398
|
+
return normalized;
|
|
2399
|
+
}
|
|
2400
|
+
var PROVIDER_ALIAS_MAP;
|
|
2401
|
+
var init_providers = __esm(() => {
|
|
2402
|
+
PROVIDER_ALIAS_MAP = {
|
|
2403
|
+
claude: "claude-code",
|
|
2404
|
+
"claude-code": "claude-code",
|
|
2405
|
+
codex: "codex",
|
|
2406
|
+
cursor: "cursor",
|
|
2407
|
+
opencode: "opencode"
|
|
2408
|
+
};
|
|
2409
|
+
});
|
|
2410
|
+
|
|
2411
|
+
// ../core/src/config/parser.ts
|
|
2412
|
+
function parseOmniConfig(tomlContent) {
|
|
2413
|
+
try {
|
|
2414
|
+
return parse(tomlContent);
|
|
2415
|
+
} catch (error) {
|
|
2416
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2417
|
+
throw new Error(`Invalid TOML in config: ${message}`);
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
function validateCapabilityConfig(parsed) {
|
|
2421
|
+
const cap = parsed["capability"];
|
|
2422
|
+
if (typeof cap !== "object" || cap === null) {
|
|
2423
|
+
throw new Error("capability.id is required in capability.toml");
|
|
2424
|
+
}
|
|
2425
|
+
const capability = cap;
|
|
2426
|
+
if (typeof capability["id"] !== "string") {
|
|
2427
|
+
throw new Error("capability.id is required in capability.toml");
|
|
2428
|
+
}
|
|
2429
|
+
if (typeof capability["name"] !== "string") {
|
|
2430
|
+
throw new Error("capability.name is required in capability.toml");
|
|
2431
|
+
}
|
|
2432
|
+
if (typeof capability["version"] !== "string") {
|
|
2433
|
+
throw new Error("capability.version is required in capability.toml");
|
|
2434
|
+
}
|
|
2435
|
+
if (capability["providers"] !== undefined) {
|
|
2436
|
+
capability["providers"] = normalizeProviderApplicability(capability["providers"], "capability.providers");
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2439
|
+
function parseCapabilityConfig(tomlContent) {
|
|
2440
|
+
try {
|
|
2441
|
+
const parsed = parse(tomlContent);
|
|
2442
|
+
validateCapabilityConfig(parsed);
|
|
2443
|
+
return parsed;
|
|
2444
|
+
} catch (error) {
|
|
2445
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2446
|
+
throw new Error(`Invalid capability.toml: ${message}`);
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
var init_parser = __esm(() => {
|
|
2450
|
+
init_dist();
|
|
2451
|
+
init_providers();
|
|
2452
|
+
});
|
|
2453
|
+
|
|
2454
|
+
// ../core/src/capability/env.ts
|
|
2455
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
2416
2456
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
2417
|
-
import {
|
|
2457
|
+
import { join as join4 } from "node:path";
|
|
2458
|
+
import { parseEnv } from "node:util";
|
|
2459
|
+
function mergeEnvSources(capabilityEnv) {
|
|
2460
|
+
const merged = { ...capabilityEnv };
|
|
2461
|
+
for (const [key, value] of Object.entries(process.env)) {
|
|
2462
|
+
if (typeof value === "string") {
|
|
2463
|
+
merged[key] = value;
|
|
2464
|
+
}
|
|
2465
|
+
}
|
|
2466
|
+
return merged;
|
|
2467
|
+
}
|
|
2468
|
+
async function loadCapabilityEnvVariables(capabilityPath) {
|
|
2469
|
+
const envPath = join4(capabilityPath, CAPABILITY_ENV_FILE);
|
|
2470
|
+
if (!existsSync6(envPath)) {
|
|
2471
|
+
return mergeEnvSources({});
|
|
2472
|
+
}
|
|
2473
|
+
const envContent = await readFile3(envPath, "utf-8");
|
|
2474
|
+
const capabilityEnv = Object.fromEntries(Object.entries(parseEnv(envContent)).filter((entry) => typeof entry[1] === "string"));
|
|
2475
|
+
return mergeEnvSources(capabilityEnv);
|
|
2476
|
+
}
|
|
2477
|
+
var CAPABILITY_ENV_FILE = ".env";
|
|
2478
|
+
var init_env = () => {};
|
|
2479
|
+
|
|
2480
|
+
// ../core/src/capability/mcp-env.ts
|
|
2481
|
+
function hasEnvPlaceholder(value) {
|
|
2482
|
+
return ENV_PLACEHOLDER_DETECTOR.test(value);
|
|
2483
|
+
}
|
|
2484
|
+
function resolveString(value, variables, capabilityId, fieldPath) {
|
|
2485
|
+
if (!hasEnvPlaceholder(value)) {
|
|
2486
|
+
return value;
|
|
2487
|
+
}
|
|
2488
|
+
return value.replace(ENV_PLACEHOLDER, (_match, variableName) => {
|
|
2489
|
+
const resolved = variables[variableName];
|
|
2490
|
+
if (resolved === undefined) {
|
|
2491
|
+
throw new Error(`Missing environment variable "${variableName}" required by capability "${capabilityId}" in ${fieldPath}`);
|
|
2492
|
+
}
|
|
2493
|
+
return resolved;
|
|
2494
|
+
});
|
|
2495
|
+
}
|
|
2496
|
+
function mcpHasPlaceholders(mcp) {
|
|
2497
|
+
const strings = [];
|
|
2498
|
+
if (mcp.command) {
|
|
2499
|
+
strings.push(mcp.command);
|
|
2500
|
+
}
|
|
2501
|
+
if (mcp.cwd) {
|
|
2502
|
+
strings.push(mcp.cwd);
|
|
2503
|
+
}
|
|
2504
|
+
if (mcp.url) {
|
|
2505
|
+
strings.push(mcp.url);
|
|
2506
|
+
}
|
|
2507
|
+
if (mcp.args) {
|
|
2508
|
+
strings.push(...mcp.args);
|
|
2509
|
+
}
|
|
2510
|
+
if (mcp.env) {
|
|
2511
|
+
strings.push(...Object.values(mcp.env));
|
|
2512
|
+
}
|
|
2513
|
+
if (mcp.headers) {
|
|
2514
|
+
strings.push(...Object.values(mcp.headers));
|
|
2515
|
+
}
|
|
2516
|
+
return strings.some((value) => hasEnvPlaceholder(value));
|
|
2517
|
+
}
|
|
2518
|
+
async function resolveCapabilityMcpEnv(config, capabilityPath, variables) {
|
|
2519
|
+
if (!config.mcp || !mcpHasPlaceholders(config.mcp)) {
|
|
2520
|
+
return config;
|
|
2521
|
+
}
|
|
2522
|
+
const resolvedVariables = variables ?? await loadCapabilityEnvVariables(capabilityPath);
|
|
2523
|
+
const resolvedMcp = { ...config.mcp };
|
|
2524
|
+
const capabilityId = config.capability.id;
|
|
2525
|
+
if (resolvedMcp.command) {
|
|
2526
|
+
resolvedMcp.command = resolveString(resolvedMcp.command, resolvedVariables, capabilityId, "mcp.command");
|
|
2527
|
+
}
|
|
2528
|
+
if (resolvedMcp.cwd) {
|
|
2529
|
+
resolvedMcp.cwd = resolveString(resolvedMcp.cwd, resolvedVariables, capabilityId, "mcp.cwd");
|
|
2530
|
+
}
|
|
2531
|
+
if (resolvedMcp.url) {
|
|
2532
|
+
resolvedMcp.url = resolveString(resolvedMcp.url, resolvedVariables, capabilityId, "mcp.url");
|
|
2533
|
+
}
|
|
2534
|
+
if (resolvedMcp.args) {
|
|
2535
|
+
resolvedMcp.args = resolvedMcp.args.map((arg, index) => resolveString(arg, resolvedVariables, capabilityId, `mcp.args[${index}]`));
|
|
2536
|
+
}
|
|
2537
|
+
if (resolvedMcp.env) {
|
|
2538
|
+
resolvedMcp.env = Object.fromEntries(Object.entries(resolvedMcp.env).map(([key, value]) => [
|
|
2539
|
+
key,
|
|
2540
|
+
resolveString(value, resolvedVariables, capabilityId, `mcp.env.${key}`)
|
|
2541
|
+
]));
|
|
2542
|
+
}
|
|
2543
|
+
if (resolvedMcp.headers) {
|
|
2544
|
+
resolvedMcp.headers = Object.fromEntries(Object.entries(resolvedMcp.headers).map(([key, value]) => [
|
|
2545
|
+
key,
|
|
2546
|
+
resolveString(value, resolvedVariables, capabilityId, `mcp.headers.${key}`)
|
|
2547
|
+
]));
|
|
2548
|
+
}
|
|
2549
|
+
return {
|
|
2550
|
+
...config,
|
|
2551
|
+
mcp: resolvedMcp
|
|
2552
|
+
};
|
|
2553
|
+
}
|
|
2554
|
+
var ENV_PLACEHOLDER, ENV_PLACEHOLDER_DETECTOR;
|
|
2555
|
+
var init_mcp_env = __esm(() => {
|
|
2556
|
+
init_env();
|
|
2557
|
+
ENV_PLACEHOLDER = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
2558
|
+
ENV_PLACEHOLDER_DETECTOR = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/;
|
|
2559
|
+
});
|
|
2560
|
+
|
|
2561
|
+
// ../core/src/capability/rules.ts
|
|
2562
|
+
import { existsSync as existsSync7, readdirSync as readdirSync3 } from "node:fs";
|
|
2563
|
+
import { readFile as readFile4 } from "node:fs/promises";
|
|
2564
|
+
import { basename as basename3, join as join5 } from "node:path";
|
|
2418
2565
|
async function loadRules(capabilityPath, capabilityId) {
|
|
2419
|
-
const rulesDir =
|
|
2420
|
-
if (!
|
|
2566
|
+
const rulesDir = join5(capabilityPath, "rules");
|
|
2567
|
+
if (!existsSync7(rulesDir)) {
|
|
2421
2568
|
return [];
|
|
2422
2569
|
}
|
|
2423
2570
|
const rules = [];
|
|
2424
2571
|
const entries = readdirSync3(rulesDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
2425
2572
|
for (const entry of entries) {
|
|
2426
2573
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2427
|
-
const rulePath =
|
|
2428
|
-
const content = await
|
|
2574
|
+
const rulePath = join5(rulesDir, entry.name);
|
|
2575
|
+
const content = await readFile4(rulePath, "utf-8");
|
|
2429
2576
|
rules.push({
|
|
2430
2577
|
name: basename3(entry.name, ".md"),
|
|
2431
2578
|
content: content.trim(),
|
|
@@ -2438,23 +2585,59 @@ async function loadRules(capabilityPath, capabilityId) {
|
|
|
2438
2585
|
var init_rules = () => {};
|
|
2439
2586
|
|
|
2440
2587
|
// ../core/src/capability/skills.ts
|
|
2441
|
-
import { existsSync as
|
|
2442
|
-
import { readFile as
|
|
2443
|
-
import { join as
|
|
2444
|
-
|
|
2588
|
+
import { existsSync as existsSync8, readdirSync as readdirSync4 } from "node:fs";
|
|
2589
|
+
import { readFile as readFile5 } from "node:fs/promises";
|
|
2590
|
+
import { join as join6 } from "node:path";
|
|
2591
|
+
function hasSkillPlaceholder(value) {
|
|
2592
|
+
return SKILL_PLACEHOLDER_DETECTOR.test(value);
|
|
2593
|
+
}
|
|
2594
|
+
function resolveSkillPlaceholders(content, variables, capabilityId, sourceLabel) {
|
|
2595
|
+
if (!hasSkillPlaceholder(content)) {
|
|
2596
|
+
return content;
|
|
2597
|
+
}
|
|
2598
|
+
return content.replace(SKILL_PLACEHOLDER, (match, variableName) => {
|
|
2599
|
+
const resolved = variables[variableName];
|
|
2600
|
+
if (resolved === undefined) {
|
|
2601
|
+
throw new Error(`Missing environment variable "${variableName}" required by capability "${capabilityId}" in ${sourceLabel} (placeholder "${match}")`);
|
|
2602
|
+
}
|
|
2603
|
+
return resolved;
|
|
2604
|
+
});
|
|
2605
|
+
}
|
|
2606
|
+
function parseSkillMarkdown(content, capabilityId, options) {
|
|
2607
|
+
const resolvedContent = options?.variables && options.sourceLabel ? resolveSkillPlaceholders(content, options.variables, capabilityId, options.sourceLabel) : content;
|
|
2608
|
+
const parsed = parseFrontmatterWithMarkdown(resolvedContent);
|
|
2609
|
+
if (!parsed) {
|
|
2610
|
+
const sourceLabel = options?.sourceLabel ?? "skill content";
|
|
2611
|
+
throw new Error(`Invalid SKILL.md format at ${sourceLabel}: missing YAML frontmatter`);
|
|
2612
|
+
}
|
|
2613
|
+
const frontmatter = parsed.frontmatter;
|
|
2614
|
+
const instructions = parsed.markdown;
|
|
2615
|
+
if (!frontmatter.name || !frontmatter.description) {
|
|
2616
|
+
const sourceLabel = options?.sourceLabel ?? "skill content";
|
|
2617
|
+
throw new Error(`Invalid SKILL.md at ${sourceLabel}: name and description required in frontmatter`);
|
|
2618
|
+
}
|
|
2619
|
+
return {
|
|
2620
|
+
name: frontmatter.name,
|
|
2621
|
+
description: frontmatter.description,
|
|
2622
|
+
instructions: instructions.trim(),
|
|
2623
|
+
capabilityId
|
|
2624
|
+
};
|
|
2625
|
+
}
|
|
2626
|
+
async function loadSkills(capabilityPath, capabilityId, variables) {
|
|
2445
2627
|
const skills = [];
|
|
2446
2628
|
const possibleDirNames = ["skills", "skill"];
|
|
2629
|
+
const resolvedVariables = variables ?? await loadCapabilityEnvVariables(capabilityPath);
|
|
2447
2630
|
for (const dirName of possibleDirNames) {
|
|
2448
|
-
const dir =
|
|
2449
|
-
if (!
|
|
2631
|
+
const dir = join6(capabilityPath, dirName);
|
|
2632
|
+
if (!existsSync8(dir)) {
|
|
2450
2633
|
continue;
|
|
2451
2634
|
}
|
|
2452
2635
|
const entries = readdirSync4(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
2453
2636
|
for (const entry of entries) {
|
|
2454
2637
|
if (entry.isDirectory()) {
|
|
2455
|
-
const skillPath =
|
|
2456
|
-
if (
|
|
2457
|
-
const skill = await parseSkillFile(skillPath, capabilityId);
|
|
2638
|
+
const skillPath = join6(dir, entry.name, "SKILL.md");
|
|
2639
|
+
if (existsSync8(skillPath)) {
|
|
2640
|
+
const skill = await parseSkillFile(skillPath, capabilityId, resolvedVariables, `skill file ${skillPath}`);
|
|
2458
2641
|
skills.push(skill);
|
|
2459
2642
|
}
|
|
2460
2643
|
}
|
|
@@ -2462,51 +2645,45 @@ async function loadSkills(capabilityPath, capabilityId) {
|
|
|
2462
2645
|
}
|
|
2463
2646
|
return skills;
|
|
2464
2647
|
}
|
|
2465
|
-
async function parseSkillFile(filePath, capabilityId) {
|
|
2466
|
-
const content = await
|
|
2467
|
-
|
|
2468
|
-
|
|
2469
|
-
|
|
2470
|
-
}
|
|
2471
|
-
const frontmatter = parsed.frontmatter;
|
|
2472
|
-
const instructions = parsed.markdown;
|
|
2473
|
-
if (!frontmatter.name || !frontmatter.description) {
|
|
2474
|
-
throw new Error(`Invalid SKILL.md at ${filePath}: name and description required in frontmatter`);
|
|
2475
|
-
}
|
|
2476
|
-
return {
|
|
2477
|
-
name: frontmatter.name,
|
|
2478
|
-
description: frontmatter.description,
|
|
2479
|
-
instructions: instructions.trim(),
|
|
2480
|
-
capabilityId
|
|
2481
|
-
};
|
|
2648
|
+
async function parseSkillFile(filePath, capabilityId, variables, sourceLabel) {
|
|
2649
|
+
const content = await readFile5(filePath, "utf-8");
|
|
2650
|
+
return parseSkillMarkdown(content, capabilityId, {
|
|
2651
|
+
variables,
|
|
2652
|
+
sourceLabel
|
|
2653
|
+
});
|
|
2482
2654
|
}
|
|
2483
|
-
var
|
|
2655
|
+
var SKILL_PLACEHOLDER, SKILL_PLACEHOLDER_DETECTOR;
|
|
2656
|
+
var init_skills = __esm(() => {
|
|
2657
|
+
init_env();
|
|
2658
|
+
SKILL_PLACEHOLDER = /\{OMNIDEV_([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
2659
|
+
SKILL_PLACEHOLDER_DETECTOR = /\{OMNIDEV_([A-Za-z_][A-Za-z0-9_]*)\}/;
|
|
2660
|
+
});
|
|
2484
2661
|
|
|
2485
2662
|
// ../core/src/capability/subagents.ts
|
|
2486
|
-
import { existsSync as
|
|
2487
|
-
import { readFile as
|
|
2488
|
-
import { basename as basename4, join as
|
|
2663
|
+
import { existsSync as existsSync9, readdirSync as readdirSync5 } from "node:fs";
|
|
2664
|
+
import { readFile as readFile6 } from "node:fs/promises";
|
|
2665
|
+
import { basename as basename4, join as join7 } from "node:path";
|
|
2489
2666
|
async function loadSubagents(capabilityPath, capabilityId) {
|
|
2490
2667
|
const subagents = [];
|
|
2491
2668
|
const possibleDirNames = ["subagents", "agents", "agent", "subagent"];
|
|
2492
2669
|
for (const dirName of possibleDirNames) {
|
|
2493
|
-
const dir =
|
|
2494
|
-
if (!
|
|
2670
|
+
const dir = join7(capabilityPath, dirName);
|
|
2671
|
+
if (!existsSync9(dir)) {
|
|
2495
2672
|
continue;
|
|
2496
2673
|
}
|
|
2497
2674
|
const entries = readdirSync5(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
2498
2675
|
for (const entry of entries) {
|
|
2499
2676
|
if (entry.isDirectory()) {
|
|
2500
|
-
let subagentPath =
|
|
2501
|
-
if (!
|
|
2502
|
-
subagentPath =
|
|
2677
|
+
let subagentPath = join7(dir, entry.name, "SUBAGENT.md");
|
|
2678
|
+
if (!existsSync9(subagentPath)) {
|
|
2679
|
+
subagentPath = join7(dir, entry.name, "AGENT.md");
|
|
2503
2680
|
}
|
|
2504
|
-
if (
|
|
2681
|
+
if (existsSync9(subagentPath)) {
|
|
2505
2682
|
const subagent = await parseSubagentFile(subagentPath, capabilityId);
|
|
2506
2683
|
subagents.push(subagent);
|
|
2507
2684
|
}
|
|
2508
2685
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2509
|
-
const subagentPath =
|
|
2686
|
+
const subagentPath = join7(dir, entry.name);
|
|
2510
2687
|
const subagent = await parseSubagentFile(subagentPath, capabilityId);
|
|
2511
2688
|
subagents.push(subagent);
|
|
2512
2689
|
}
|
|
@@ -2515,7 +2692,7 @@ async function loadSubagents(capabilityPath, capabilityId) {
|
|
|
2515
2692
|
return subagents;
|
|
2516
2693
|
}
|
|
2517
2694
|
async function parseSubagentFile(filePath, capabilityId) {
|
|
2518
|
-
const content = await
|
|
2695
|
+
const content = await readFile6(filePath, "utf-8");
|
|
2519
2696
|
const parsed = parseFrontmatterWithMarkdown(content);
|
|
2520
2697
|
if (!parsed) {
|
|
2521
2698
|
throw new Error(`Invalid SUBAGENT.md format at ${filePath}: missing YAML frontmatter`);
|
|
@@ -2559,18 +2736,18 @@ function parseCommaSeparatedList(value) {
|
|
|
2559
2736
|
var init_subagents = () => {};
|
|
2560
2737
|
|
|
2561
2738
|
// ../core/src/capability/loader.ts
|
|
2562
|
-
import { existsSync as
|
|
2563
|
-
import { readFile as
|
|
2564
|
-
import { join as
|
|
2739
|
+
import { existsSync as existsSync10, readdirSync as readdirSync6 } from "node:fs";
|
|
2740
|
+
import { readFile as readFile7 } from "node:fs/promises";
|
|
2741
|
+
import { join as join8 } from "node:path";
|
|
2565
2742
|
async function discoverCapabilities() {
|
|
2566
2743
|
const capabilities = [];
|
|
2567
|
-
if (
|
|
2744
|
+
if (existsSync10(CAPABILITIES_DIR)) {
|
|
2568
2745
|
const entries = readdirSync6(CAPABILITIES_DIR, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
2569
2746
|
for (const entry of entries) {
|
|
2570
2747
|
if (entry.isDirectory()) {
|
|
2571
|
-
const entryPath =
|
|
2572
|
-
const configPath =
|
|
2573
|
-
if (
|
|
2748
|
+
const entryPath = join8(CAPABILITIES_DIR, entry.name);
|
|
2749
|
+
const configPath = join8(entryPath, "capability.toml");
|
|
2750
|
+
if (existsSync10(configPath)) {
|
|
2574
2751
|
capabilities.push(entryPath);
|
|
2575
2752
|
}
|
|
2576
2753
|
}
|
|
@@ -2579,28 +2756,28 @@ async function discoverCapabilities() {
|
|
|
2579
2756
|
return capabilities;
|
|
2580
2757
|
}
|
|
2581
2758
|
async function loadCapabilityConfig(capabilityPath) {
|
|
2582
|
-
const configPath =
|
|
2583
|
-
const content = await
|
|
2759
|
+
const configPath = join8(capabilityPath, "capability.toml");
|
|
2760
|
+
const content = await readFile7(configPath, "utf-8");
|
|
2584
2761
|
const config = parseCapabilityConfig(content);
|
|
2585
2762
|
return config;
|
|
2586
2763
|
}
|
|
2587
2764
|
async function importCapabilityExports(capabilityPath) {
|
|
2588
|
-
const builtIndexPath =
|
|
2589
|
-
const jsIndexPath =
|
|
2590
|
-
const tsIndexPath =
|
|
2765
|
+
const builtIndexPath = join8(capabilityPath, "dist", "index.js");
|
|
2766
|
+
const jsIndexPath = join8(capabilityPath, "index.js");
|
|
2767
|
+
const tsIndexPath = join8(capabilityPath, "index.ts");
|
|
2591
2768
|
let indexPath = null;
|
|
2592
|
-
if (
|
|
2769
|
+
if (existsSync10(builtIndexPath)) {
|
|
2593
2770
|
indexPath = builtIndexPath;
|
|
2594
|
-
} else if (
|
|
2771
|
+
} else if (existsSync10(jsIndexPath)) {
|
|
2595
2772
|
indexPath = jsIndexPath;
|
|
2596
|
-
} else if (
|
|
2773
|
+
} else if (existsSync10(tsIndexPath)) {
|
|
2597
2774
|
indexPath = tsIndexPath;
|
|
2598
2775
|
}
|
|
2599
2776
|
if (!indexPath) {
|
|
2600
2777
|
return {};
|
|
2601
2778
|
}
|
|
2602
2779
|
try {
|
|
2603
|
-
const absolutePath =
|
|
2780
|
+
const absolutePath = join8(process.cwd(), indexPath);
|
|
2604
2781
|
const module = await import(absolutePath);
|
|
2605
2782
|
return module;
|
|
2606
2783
|
} catch (error) {
|
|
@@ -2620,46 +2797,19 @@ If this is a project-specific capability, install dependencies or remove it from
|
|
|
2620
2797
|
}
|
|
2621
2798
|
}
|
|
2622
2799
|
async function loadTypeDefinitions(capabilityPath) {
|
|
2623
|
-
const typesPath =
|
|
2624
|
-
if (!
|
|
2800
|
+
const typesPath = join8(capabilityPath, "types.d.ts");
|
|
2801
|
+
if (!existsSync10(typesPath)) {
|
|
2625
2802
|
return;
|
|
2626
2803
|
}
|
|
2627
|
-
return
|
|
2804
|
+
return readFile7(typesPath, "utf-8");
|
|
2628
2805
|
}
|
|
2629
|
-
function convertSkillExports(skillExports, capabilityId) {
|
|
2630
|
-
return skillExports.map((skillExport) => {
|
|
2806
|
+
function convertSkillExports(skillExports, capabilityId, variables) {
|
|
2807
|
+
return skillExports.map((skillExport, index) => {
|
|
2631
2808
|
const exportObj = skillExport;
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
let instructions = exportObj.skillMd;
|
|
2637
|
-
if (lines[0]?.trim() === "---") {
|
|
2638
|
-
const endIndex = lines.findIndex((line, i) => i > 0 && line.trim() === "---");
|
|
2639
|
-
if (endIndex > 0) {
|
|
2640
|
-
const frontmatter = lines.slice(1, endIndex);
|
|
2641
|
-
instructions = lines.slice(endIndex + 1).join(`
|
|
2642
|
-
`).trim();
|
|
2643
|
-
for (const line of frontmatter) {
|
|
2644
|
-
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
2645
|
-
if (match?.[1] && match[2]) {
|
|
2646
|
-
const key = match[1];
|
|
2647
|
-
const value = match[2];
|
|
2648
|
-
if (key === "name") {
|
|
2649
|
-
name = value.replace(/^["']|["']$/g, "");
|
|
2650
|
-
} else if (key === "description") {
|
|
2651
|
-
description = value.replace(/^["']|["']$/g, "");
|
|
2652
|
-
}
|
|
2653
|
-
}
|
|
2654
|
-
}
|
|
2655
|
-
}
|
|
2656
|
-
}
|
|
2657
|
-
return {
|
|
2658
|
-
name,
|
|
2659
|
-
description,
|
|
2660
|
-
instructions,
|
|
2661
|
-
capabilityId
|
|
2662
|
-
};
|
|
2809
|
+
return parseSkillMarkdown(exportObj.skillMd, capabilityId, {
|
|
2810
|
+
variables,
|
|
2811
|
+
sourceLabel: `programmatic skill export[${index}]`
|
|
2812
|
+
});
|
|
2663
2813
|
});
|
|
2664
2814
|
}
|
|
2665
2815
|
function convertRuleExports(ruleExports, capabilityId) {
|
|
@@ -2812,7 +2962,9 @@ function mergeByName(fileBased, programmatic) {
|
|
|
2812
2962
|
return Array.from(byName.values());
|
|
2813
2963
|
}
|
|
2814
2964
|
async function loadCapability(capabilityPath) {
|
|
2815
|
-
const
|
|
2965
|
+
const capabilityEnvVariables = await loadCapabilityEnvVariables(capabilityPath);
|
|
2966
|
+
const rawConfig = await loadCapabilityConfig(capabilityPath);
|
|
2967
|
+
const config = await resolveCapabilityMcpEnv(rawConfig, capabilityPath, capabilityEnvVariables);
|
|
2816
2968
|
const id = config.capability.id;
|
|
2817
2969
|
const exports = await importCapabilityExports(capabilityPath);
|
|
2818
2970
|
const exportsAny = exports;
|
|
@@ -2827,8 +2979,8 @@ async function loadCapability(capabilityPath) {
|
|
|
2827
2979
|
return;
|
|
2828
2980
|
};
|
|
2829
2981
|
const skillsExport = getExportValue("skills");
|
|
2830
|
-
const programmaticSkills = Array.isArray(skillsExport) ? convertSkillExports(skillsExport, id) : [];
|
|
2831
|
-
const fileSkills = await loadSkills(capabilityPath, id);
|
|
2982
|
+
const programmaticSkills = Array.isArray(skillsExport) ? convertSkillExports(skillsExport, id, capabilityEnvVariables) : [];
|
|
2983
|
+
const fileSkills = await loadSkills(capabilityPath, id, capabilityEnvVariables);
|
|
2832
2984
|
const skills = mergeByName(fileSkills, programmaticSkills);
|
|
2833
2985
|
const rulesExport = getExportValue("rules");
|
|
2834
2986
|
const programmaticRules = Array.isArray(rulesExport) ? convertRuleExports(rulesExport, id) : [];
|
|
@@ -2876,18 +3028,20 @@ async function loadCapability(capabilityPath) {
|
|
|
2876
3028
|
}
|
|
2877
3029
|
var CAPABILITIES_DIR = ".omni/capabilities";
|
|
2878
3030
|
var init_loader2 = __esm(() => {
|
|
2879
|
-
init_parser();
|
|
2880
3031
|
init_loader();
|
|
3032
|
+
init_parser();
|
|
2881
3033
|
init_commands();
|
|
2882
3034
|
init_docs();
|
|
3035
|
+
init_env();
|
|
3036
|
+
init_mcp_env();
|
|
2883
3037
|
init_rules();
|
|
2884
3038
|
init_skills();
|
|
2885
3039
|
init_subagents();
|
|
2886
3040
|
});
|
|
2887
3041
|
|
|
2888
3042
|
// ../core/src/config/config.ts
|
|
2889
|
-
import { existsSync as
|
|
2890
|
-
import { readFile as
|
|
3043
|
+
import { existsSync as existsSync11 } from "node:fs";
|
|
3044
|
+
import { readFile as readFile8, writeFile } from "node:fs/promises";
|
|
2891
3045
|
function mergeConfigs(base, override) {
|
|
2892
3046
|
const merged = { ...base, ...override };
|
|
2893
3047
|
merged.profiles = { ...base.profiles };
|
|
@@ -2929,8 +3083,8 @@ function mergeConfigs(base, override) {
|
|
|
2929
3083
|
return merged;
|
|
2930
3084
|
}
|
|
2931
3085
|
async function loadBaseConfig() {
|
|
2932
|
-
if (
|
|
2933
|
-
const content = await
|
|
3086
|
+
if (existsSync11(CONFIG_PATH)) {
|
|
3087
|
+
const content = await readFile8(CONFIG_PATH, "utf-8");
|
|
2934
3088
|
return parseOmniConfig(content);
|
|
2935
3089
|
}
|
|
2936
3090
|
return {};
|
|
@@ -2938,8 +3092,8 @@ async function loadBaseConfig() {
|
|
|
2938
3092
|
async function loadConfig() {
|
|
2939
3093
|
const baseConfig = await loadBaseConfig();
|
|
2940
3094
|
let localConfig = {};
|
|
2941
|
-
if (
|
|
2942
|
-
const content = await
|
|
3095
|
+
if (existsSync11(LOCAL_CONFIG)) {
|
|
3096
|
+
const content = await readFile8(LOCAL_CONFIG, "utf-8");
|
|
2943
3097
|
localConfig = parseOmniConfig(content);
|
|
2944
3098
|
}
|
|
2945
3099
|
return mergeConfigs(baseConfig, localConfig);
|
|
@@ -3103,14 +3257,14 @@ var init_config = __esm(() => {
|
|
|
3103
3257
|
});
|
|
3104
3258
|
|
|
3105
3259
|
// ../core/src/state/active-profile.ts
|
|
3106
|
-
import { existsSync as
|
|
3107
|
-
import { readFile as
|
|
3260
|
+
import { existsSync as existsSync12, mkdirSync } from "node:fs";
|
|
3261
|
+
import { readFile as readFile9, unlink, writeFile as writeFile2 } from "node:fs/promises";
|
|
3108
3262
|
async function readActiveProfileState() {
|
|
3109
|
-
if (!
|
|
3263
|
+
if (!existsSync12(ACTIVE_PROFILE_PATH)) {
|
|
3110
3264
|
return null;
|
|
3111
3265
|
}
|
|
3112
3266
|
try {
|
|
3113
|
-
const content = await
|
|
3267
|
+
const content = await readFile9(ACTIVE_PROFILE_PATH, "utf-8");
|
|
3114
3268
|
const trimmed = content.trim();
|
|
3115
3269
|
return trimmed || null;
|
|
3116
3270
|
} catch {
|
|
@@ -3122,7 +3276,7 @@ async function writeActiveProfileState(profileName) {
|
|
|
3122
3276
|
await writeFile2(ACTIVE_PROFILE_PATH, profileName, "utf-8");
|
|
3123
3277
|
}
|
|
3124
3278
|
async function clearActiveProfileState() {
|
|
3125
|
-
if (
|
|
3279
|
+
if (existsSync12(ACTIVE_PROFILE_PATH)) {
|
|
3126
3280
|
await unlink(ACTIVE_PROFILE_PATH);
|
|
3127
3281
|
}
|
|
3128
3282
|
}
|
|
@@ -3366,10 +3520,10 @@ function getActiveProviders(config) {
|
|
|
3366
3520
|
var init_types2 = () => {};
|
|
3367
3521
|
|
|
3368
3522
|
// ../core/src/capability/sources.ts
|
|
3369
|
-
import { existsSync as
|
|
3523
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
3370
3524
|
import { spawn } from "node:child_process";
|
|
3371
|
-
import { cp, mkdir, readdir, readFile as
|
|
3372
|
-
import { join as
|
|
3525
|
+
import { cp, mkdir, readdir, readFile as readFile10, rename, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
|
|
3526
|
+
import { join as join9 } from "node:path";
|
|
3373
3527
|
import { createHash } from "node:crypto";
|
|
3374
3528
|
async function spawnCapture(command, args, options) {
|
|
3375
3529
|
const timeout = options?.timeout ?? 60000;
|
|
@@ -3426,10 +3580,10 @@ function parseFileSourcePath(source) {
|
|
|
3426
3580
|
return source.slice(7);
|
|
3427
3581
|
}
|
|
3428
3582
|
async function readCapabilityIdFromPath(capabilityPath) {
|
|
3429
|
-
const tomlPath =
|
|
3430
|
-
if (
|
|
3583
|
+
const tomlPath = join9(capabilityPath, "capability.toml");
|
|
3584
|
+
if (existsSync13(tomlPath)) {
|
|
3431
3585
|
try {
|
|
3432
|
-
const content = await
|
|
3586
|
+
const content = await readFile10(tomlPath, "utf-8");
|
|
3433
3587
|
const parsed = parse(content);
|
|
3434
3588
|
const capability = parsed["capability"];
|
|
3435
3589
|
if (capability?.["id"] && typeof capability["id"] === "string") {
|
|
@@ -3482,18 +3636,18 @@ function sourceToGitUrl(source) {
|
|
|
3482
3636
|
return source;
|
|
3483
3637
|
}
|
|
3484
3638
|
function getSourceCapabilityPath(id) {
|
|
3485
|
-
return
|
|
3639
|
+
return join9(OMNI_LOCAL, "capabilities", id);
|
|
3486
3640
|
}
|
|
3487
3641
|
function getLockFilePath() {
|
|
3488
3642
|
return "omni.lock.toml";
|
|
3489
3643
|
}
|
|
3490
3644
|
async function loadLockFile() {
|
|
3491
3645
|
const lockPath = getLockFilePath();
|
|
3492
|
-
if (!
|
|
3646
|
+
if (!existsSync13(lockPath)) {
|
|
3493
3647
|
return { capabilities: {} };
|
|
3494
3648
|
}
|
|
3495
3649
|
try {
|
|
3496
|
-
const content = await
|
|
3650
|
+
const content = await readFile10(lockPath, "utf-8");
|
|
3497
3651
|
const parsed = parse(content);
|
|
3498
3652
|
const rawCapabilities = parsed["capabilities"];
|
|
3499
3653
|
if (!rawCapabilities) {
|
|
@@ -3551,7 +3705,7 @@ function stringifyLockFile(lockFile) {
|
|
|
3551
3705
|
}
|
|
3552
3706
|
async function saveLockFile(lockFile) {
|
|
3553
3707
|
const lockPath = getLockFilePath();
|
|
3554
|
-
await mkdir(
|
|
3708
|
+
await mkdir(join9(OMNI_LOCAL, "capabilities"), { recursive: true });
|
|
3555
3709
|
const header = `# Auto-generated by OmniDev - DO NOT EDIT
|
|
3556
3710
|
# Records installed capability versions for reproducibility
|
|
3557
3711
|
# Last updated: ${new Date().toISOString()}
|
|
@@ -3585,7 +3739,7 @@ async function computeContentHash(dirPath, excludePatterns = CONTENT_HASH_EXCLUD
|
|
|
3585
3739
|
const entries = await readdir(currentPath, { withFileTypes: true });
|
|
3586
3740
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
3587
3741
|
for (const entry of entries) {
|
|
3588
|
-
const fullPath =
|
|
3742
|
+
const fullPath = join9(currentPath, entry.name);
|
|
3589
3743
|
const relativePath = fullPath.slice(relativeTo.length + 1);
|
|
3590
3744
|
if (excludePatterns.some((pattern) => entry.name === pattern || relativePath.startsWith(`${pattern}/`))) {
|
|
3591
3745
|
continue;
|
|
@@ -3593,7 +3747,7 @@ async function computeContentHash(dirPath, excludePatterns = CONTENT_HASH_EXCLUD
|
|
|
3593
3747
|
if (entry.isDirectory()) {
|
|
3594
3748
|
await collectFiles(fullPath, relativeTo);
|
|
3595
3749
|
} else if (entry.isFile()) {
|
|
3596
|
-
const content = await
|
|
3750
|
+
const content = await readFile10(fullPath);
|
|
3597
3751
|
files.push({ relativePath, content });
|
|
3598
3752
|
}
|
|
3599
3753
|
}
|
|
@@ -3607,10 +3761,10 @@ async function computeContentHash(dirPath, excludePatterns = CONTENT_HASH_EXCLUD
|
|
|
3607
3761
|
return hash.digest("hex");
|
|
3608
3762
|
}
|
|
3609
3763
|
async function detectDisplayVersion(dirPath, fallback, fallbackSource) {
|
|
3610
|
-
const capTomlPath =
|
|
3611
|
-
if (
|
|
3764
|
+
const capTomlPath = join9(dirPath, "capability.toml");
|
|
3765
|
+
if (existsSync13(capTomlPath)) {
|
|
3612
3766
|
try {
|
|
3613
|
-
const content = await
|
|
3767
|
+
const content = await readFile10(capTomlPath, "utf-8");
|
|
3614
3768
|
const parsed = parse(content);
|
|
3615
3769
|
const capability = parsed["capability"];
|
|
3616
3770
|
if (capability?.["version"] && typeof capability["version"] === "string") {
|
|
@@ -3618,20 +3772,20 @@ async function detectDisplayVersion(dirPath, fallback, fallbackSource) {
|
|
|
3618
3772
|
}
|
|
3619
3773
|
} catch {}
|
|
3620
3774
|
}
|
|
3621
|
-
const pluginJsonPath =
|
|
3622
|
-
if (
|
|
3775
|
+
const pluginJsonPath = join9(dirPath, ".claude-plugin", "plugin.json");
|
|
3776
|
+
if (existsSync13(pluginJsonPath)) {
|
|
3623
3777
|
try {
|
|
3624
|
-
const content = await
|
|
3778
|
+
const content = await readFile10(pluginJsonPath, "utf-8");
|
|
3625
3779
|
const parsed = JSON.parse(content);
|
|
3626
3780
|
if (parsed.version && typeof parsed.version === "string") {
|
|
3627
3781
|
return { version: parsed.version, source: "plugin.json" };
|
|
3628
3782
|
}
|
|
3629
3783
|
} catch {}
|
|
3630
3784
|
}
|
|
3631
|
-
const pkgJsonPath =
|
|
3632
|
-
if (
|
|
3785
|
+
const pkgJsonPath = join9(dirPath, "package.json");
|
|
3786
|
+
if (existsSync13(pkgJsonPath)) {
|
|
3633
3787
|
try {
|
|
3634
|
-
const content = await
|
|
3788
|
+
const content = await readFile10(pkgJsonPath, "utf-8");
|
|
3635
3789
|
const parsed = JSON.parse(content);
|
|
3636
3790
|
if (parsed.version && typeof parsed.version === "string") {
|
|
3637
3791
|
return { version: parsed.version, source: "package.json" };
|
|
@@ -3642,9 +3796,9 @@ async function detectDisplayVersion(dirPath, fallback, fallbackSource) {
|
|
|
3642
3796
|
}
|
|
3643
3797
|
async function validateGitCapability(sourceUrl, subPath) {
|
|
3644
3798
|
const gitUrl = sourceToGitUrl(sourceUrl);
|
|
3645
|
-
const tempPath =
|
|
3799
|
+
const tempPath = join9(OMNI_LOCAL, "_temp", `_validate-${Date.now()}`);
|
|
3646
3800
|
try {
|
|
3647
|
-
await mkdir(
|
|
3801
|
+
await mkdir(join9(tempPath, ".."), { recursive: true });
|
|
3648
3802
|
const args = ["clone", "--depth", "1", gitUrl, tempPath];
|
|
3649
3803
|
const { exitCode, stderr } = await spawnCapture("git", args, { timeout: 30000 });
|
|
3650
3804
|
if (exitCode !== 0) {
|
|
@@ -3680,8 +3834,8 @@ async function validateGitCapability(sourceUrl, subPath) {
|
|
|
3680
3834
|
error: `Failed to clone repository: ${stderr.trim()}`
|
|
3681
3835
|
};
|
|
3682
3836
|
}
|
|
3683
|
-
const checkPath = subPath ?
|
|
3684
|
-
if (subPath && !
|
|
3837
|
+
const checkPath = subPath ? join9(tempPath, subPath) : tempPath;
|
|
3838
|
+
if (subPath && !existsSync13(checkPath)) {
|
|
3685
3839
|
return {
|
|
3686
3840
|
valid: false,
|
|
3687
3841
|
hasCapabilityToml: false,
|
|
@@ -3692,9 +3846,9 @@ async function validateGitCapability(sourceUrl, subPath) {
|
|
|
3692
3846
|
const hasCapToml = hasCapabilityToml(checkPath);
|
|
3693
3847
|
let capabilityId;
|
|
3694
3848
|
if (hasCapToml) {
|
|
3695
|
-
const tomlPath =
|
|
3849
|
+
const tomlPath = join9(checkPath, "capability.toml");
|
|
3696
3850
|
try {
|
|
3697
|
-
const content = await
|
|
3851
|
+
const content = await readFile10(tomlPath, "utf-8");
|
|
3698
3852
|
const parsed = parse(content);
|
|
3699
3853
|
const capability = parsed["capability"];
|
|
3700
3854
|
if (capability?.["id"] && typeof capability["id"] === "string") {
|
|
@@ -3726,27 +3880,27 @@ async function validateGitCapability(sourceUrl, subPath) {
|
|
|
3726
3880
|
canBeWrapped: true
|
|
3727
3881
|
};
|
|
3728
3882
|
} finally {
|
|
3729
|
-
if (
|
|
3883
|
+
if (existsSync13(tempPath)) {
|
|
3730
3884
|
await rm(tempPath, { recursive: true });
|
|
3731
3885
|
}
|
|
3732
3886
|
}
|
|
3733
3887
|
}
|
|
3734
3888
|
async function detectPinVersion(sourceUrl, subPath) {
|
|
3735
3889
|
const gitUrl = sourceToGitUrl(sourceUrl);
|
|
3736
|
-
const tempPath =
|
|
3890
|
+
const tempPath = join9(OMNI_LOCAL, "_temp", `_pin-detect-${Date.now()}`);
|
|
3737
3891
|
try {
|
|
3738
|
-
await mkdir(
|
|
3892
|
+
await mkdir(join9(tempPath, ".."), { recursive: true });
|
|
3739
3893
|
const args = ["clone", "--depth", "1", gitUrl, tempPath];
|
|
3740
3894
|
const { exitCode, stderr } = await spawnCapture("git", args);
|
|
3741
3895
|
if (exitCode !== 0) {
|
|
3742
3896
|
throw new Error(`Failed to clone ${gitUrl}: ${stderr.trim()}`);
|
|
3743
3897
|
}
|
|
3744
3898
|
const commit = await getRepoCommit(tempPath);
|
|
3745
|
-
const checkPath = subPath ?
|
|
3746
|
-
const capTomlPath =
|
|
3747
|
-
if (
|
|
3899
|
+
const checkPath = subPath ? join9(tempPath, subPath) : tempPath;
|
|
3900
|
+
const capTomlPath = join9(checkPath, "capability.toml");
|
|
3901
|
+
if (existsSync13(capTomlPath)) {
|
|
3748
3902
|
try {
|
|
3749
|
-
const content = await
|
|
3903
|
+
const content = await readFile10(capTomlPath, "utf-8");
|
|
3750
3904
|
const parsed = parse(content);
|
|
3751
3905
|
const capability = parsed["capability"];
|
|
3752
3906
|
if (capability?.["version"] && typeof capability["version"] === "string") {
|
|
@@ -3754,10 +3908,10 @@ async function detectPinVersion(sourceUrl, subPath) {
|
|
|
3754
3908
|
}
|
|
3755
3909
|
} catch {}
|
|
3756
3910
|
}
|
|
3757
|
-
const pluginJsonPath =
|
|
3758
|
-
if (
|
|
3911
|
+
const pluginJsonPath = join9(checkPath, ".claude-plugin", "plugin.json");
|
|
3912
|
+
if (existsSync13(pluginJsonPath)) {
|
|
3759
3913
|
try {
|
|
3760
|
-
const content = await
|
|
3914
|
+
const content = await readFile10(pluginJsonPath, "utf-8");
|
|
3761
3915
|
const parsed = JSON.parse(content);
|
|
3762
3916
|
if (parsed.version && typeof parsed.version === "string") {
|
|
3763
3917
|
return parsed.version;
|
|
@@ -3766,13 +3920,13 @@ async function detectPinVersion(sourceUrl, subPath) {
|
|
|
3766
3920
|
}
|
|
3767
3921
|
return commit;
|
|
3768
3922
|
} finally {
|
|
3769
|
-
if (
|
|
3923
|
+
if (existsSync13(tempPath)) {
|
|
3770
3924
|
await rm(tempPath, { recursive: true });
|
|
3771
3925
|
}
|
|
3772
3926
|
}
|
|
3773
3927
|
}
|
|
3774
3928
|
async function cloneRepo(gitUrl, targetPath, ref) {
|
|
3775
|
-
await mkdir(
|
|
3929
|
+
await mkdir(join9(targetPath, ".."), { recursive: true });
|
|
3776
3930
|
const args = ["clone", "--depth", "1"];
|
|
3777
3931
|
if (ref) {
|
|
3778
3932
|
args.push("--branch", ref);
|
|
@@ -3830,16 +3984,16 @@ async function fetchRepo(repoPath, ref) {
|
|
|
3830
3984
|
return true;
|
|
3831
3985
|
}
|
|
3832
3986
|
function hasCapabilityToml(dirPath) {
|
|
3833
|
-
return
|
|
3987
|
+
return existsSync13(join9(dirPath, "capability.toml"));
|
|
3834
3988
|
}
|
|
3835
3989
|
async function shouldWrapDirectory(dirPath) {
|
|
3836
|
-
if (
|
|
3990
|
+
if (existsSync13(join9(dirPath, ".claude-plugin", "plugin.json"))) {
|
|
3837
3991
|
return true;
|
|
3838
3992
|
}
|
|
3839
3993
|
const allDirs = [...SKILL_DIRS, ...AGENT_DIRS, ...COMMAND_DIRS, ...RULE_DIRS, ...DOC_DIRS];
|
|
3840
3994
|
for (const dirName of allDirs) {
|
|
3841
|
-
const checkPath =
|
|
3842
|
-
if (
|
|
3995
|
+
const checkPath = join9(dirPath, dirName);
|
|
3996
|
+
if (existsSync13(checkPath)) {
|
|
3843
3997
|
const stats = await stat(checkPath);
|
|
3844
3998
|
if (stats.isDirectory()) {
|
|
3845
3999
|
return true;
|
|
@@ -3848,10 +4002,64 @@ async function shouldWrapDirectory(dirPath) {
|
|
|
3848
4002
|
}
|
|
3849
4003
|
return false;
|
|
3850
4004
|
}
|
|
4005
|
+
function isRecognizedWrappedDirectory(dirName, keepGitDir = false) {
|
|
4006
|
+
if (keepGitDir && dirName === ".git") {
|
|
4007
|
+
return true;
|
|
4008
|
+
}
|
|
4009
|
+
return WRAPPED_CONTENT_DIRS.has(dirName);
|
|
4010
|
+
}
|
|
4011
|
+
function isMandatoryWrappedRootFile(fileName) {
|
|
4012
|
+
if (WRAPPED_ROOT_FILES_EXACT.has(fileName)) {
|
|
4013
|
+
return true;
|
|
4014
|
+
}
|
|
4015
|
+
return WRAPPED_ROOT_FILE_PATTERNS.some((pattern) => pattern.test(fileName));
|
|
4016
|
+
}
|
|
4017
|
+
async function copyWrappedContentOnly(sourcePath, targetPath) {
|
|
4018
|
+
await mkdir(targetPath, { recursive: true });
|
|
4019
|
+
const entries = await readdir(sourcePath, { withFileTypes: true });
|
|
4020
|
+
for (const entry of entries) {
|
|
4021
|
+
if (entry.isDirectory() && !isRecognizedWrappedDirectory(entry.name)) {
|
|
4022
|
+
continue;
|
|
4023
|
+
}
|
|
4024
|
+
if (entry.isFile() && !isMandatoryWrappedRootFile(entry.name)) {
|
|
4025
|
+
continue;
|
|
4026
|
+
}
|
|
4027
|
+
if (!entry.isDirectory() && !entry.isFile()) {
|
|
4028
|
+
continue;
|
|
4029
|
+
}
|
|
4030
|
+
const sourceEntryPath = join9(sourcePath, entry.name);
|
|
4031
|
+
const targetEntryPath = join9(targetPath, entry.name);
|
|
4032
|
+
if (entry.isDirectory()) {
|
|
4033
|
+
await cp(sourceEntryPath, targetEntryPath, { recursive: true });
|
|
4034
|
+
} else {
|
|
4035
|
+
await cp(sourceEntryPath, targetEntryPath);
|
|
4036
|
+
}
|
|
4037
|
+
}
|
|
4038
|
+
}
|
|
4039
|
+
async function pruneUnknownWrappedEntries(repoPath, keepGitDir = false) {
|
|
4040
|
+
const entries = await readdir(repoPath, { withFileTypes: true });
|
|
4041
|
+
for (const entry of entries) {
|
|
4042
|
+
if (entry.isDirectory()) {
|
|
4043
|
+
if (isRecognizedWrappedDirectory(entry.name, keepGitDir)) {
|
|
4044
|
+
continue;
|
|
4045
|
+
}
|
|
4046
|
+
await rm(join9(repoPath, entry.name), { recursive: true, force: true });
|
|
4047
|
+
continue;
|
|
4048
|
+
}
|
|
4049
|
+
if (entry.isFile()) {
|
|
4050
|
+
if (isMandatoryWrappedRootFile(entry.name)) {
|
|
4051
|
+
continue;
|
|
4052
|
+
}
|
|
4053
|
+
await rm(join9(repoPath, entry.name), { force: true });
|
|
4054
|
+
continue;
|
|
4055
|
+
}
|
|
4056
|
+
await rm(join9(repoPath, entry.name), { recursive: true, force: true });
|
|
4057
|
+
}
|
|
4058
|
+
}
|
|
3851
4059
|
async function findMatchingDirs(basePath, names) {
|
|
3852
4060
|
for (const name of names) {
|
|
3853
|
-
const dirPath =
|
|
3854
|
-
if (
|
|
4061
|
+
const dirPath = join9(basePath, name);
|
|
4062
|
+
if (existsSync13(dirPath)) {
|
|
3855
4063
|
const stats = await stat(dirPath);
|
|
3856
4064
|
if (stats.isDirectory()) {
|
|
3857
4065
|
return dirPath;
|
|
@@ -3862,15 +4070,15 @@ async function findMatchingDirs(basePath, names) {
|
|
|
3862
4070
|
}
|
|
3863
4071
|
async function findContentItems(dirPath, filePatterns) {
|
|
3864
4072
|
const items = [];
|
|
3865
|
-
if (!
|
|
4073
|
+
if (!existsSync13(dirPath)) {
|
|
3866
4074
|
return items;
|
|
3867
4075
|
}
|
|
3868
4076
|
const entries = (await readdir(dirPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
3869
4077
|
for (const entry of entries) {
|
|
3870
|
-
const entryPath =
|
|
4078
|
+
const entryPath = join9(dirPath, entry.name);
|
|
3871
4079
|
if (entry.isDirectory()) {
|
|
3872
4080
|
for (const pattern of filePatterns) {
|
|
3873
|
-
if (
|
|
4081
|
+
if (existsSync13(join9(entryPath, pattern))) {
|
|
3874
4082
|
items.push({
|
|
3875
4083
|
name: entry.name,
|
|
3876
4084
|
path: entryPath,
|
|
@@ -3891,12 +4099,12 @@ async function findContentItems(dirPath, filePatterns) {
|
|
|
3891
4099
|
return items;
|
|
3892
4100
|
}
|
|
3893
4101
|
async function parsePluginJson(dirPath) {
|
|
3894
|
-
const pluginJsonPath =
|
|
3895
|
-
if (!
|
|
4102
|
+
const pluginJsonPath = join9(dirPath, ".claude-plugin", "plugin.json");
|
|
4103
|
+
if (!existsSync13(pluginJsonPath)) {
|
|
3896
4104
|
return null;
|
|
3897
4105
|
}
|
|
3898
4106
|
try {
|
|
3899
|
-
const content = await
|
|
4107
|
+
const content = await readFile10(pluginJsonPath, "utf-8");
|
|
3900
4108
|
const data = JSON.parse(content);
|
|
3901
4109
|
const result = {
|
|
3902
4110
|
name: data.name,
|
|
@@ -3916,12 +4124,12 @@ async function parsePluginJson(dirPath) {
|
|
|
3916
4124
|
}
|
|
3917
4125
|
}
|
|
3918
4126
|
async function readReadmeDescription(dirPath) {
|
|
3919
|
-
const readmePath =
|
|
3920
|
-
if (!
|
|
4127
|
+
const readmePath = join9(dirPath, "README.md");
|
|
4128
|
+
if (!existsSync13(readmePath)) {
|
|
3921
4129
|
return null;
|
|
3922
4130
|
}
|
|
3923
4131
|
try {
|
|
3924
|
-
const content = await
|
|
4132
|
+
const content = await readFile10(readmePath, "utf-8");
|
|
3925
4133
|
const lines = content.split(`
|
|
3926
4134
|
`);
|
|
3927
4135
|
let description = "";
|
|
@@ -3956,9 +4164,9 @@ async function normalizeFolderNames(repoPath) {
|
|
|
3956
4164
|
{ from: "rule", to: "rules" }
|
|
3957
4165
|
];
|
|
3958
4166
|
for (const { from, to } of renameMappings) {
|
|
3959
|
-
const fromPath =
|
|
3960
|
-
const toPath =
|
|
3961
|
-
if (
|
|
4167
|
+
const fromPath = join9(repoPath, from);
|
|
4168
|
+
const toPath = join9(repoPath, to);
|
|
4169
|
+
if (existsSync13(fromPath) && !existsSync13(toPath)) {
|
|
3962
4170
|
try {
|
|
3963
4171
|
const stats = await stat(fromPath);
|
|
3964
4172
|
if (stats.isDirectory()) {
|
|
@@ -4047,7 +4255,7 @@ repository = "${escapeTomlString(repoUrl)}"
|
|
|
4047
4255
|
wrapped = true
|
|
4048
4256
|
commit = "${commit}"
|
|
4049
4257
|
`;
|
|
4050
|
-
await writeFile3(
|
|
4258
|
+
await writeFile3(join9(repoPath, "capability.toml"), tomlContent, "utf-8");
|
|
4051
4259
|
}
|
|
4052
4260
|
async function fetchGitCapabilitySource(id, config, options) {
|
|
4053
4261
|
const gitUrl = sourceToGitUrl(config.source);
|
|
@@ -4055,31 +4263,40 @@ async function fetchGitCapabilitySource(id, config, options) {
|
|
|
4055
4263
|
let updated = false;
|
|
4056
4264
|
let commit;
|
|
4057
4265
|
let repoPath;
|
|
4266
|
+
let needsWrap = false;
|
|
4058
4267
|
const gitRef = config.version && config.version !== "latest" ? config.version : undefined;
|
|
4059
4268
|
if (config.path) {
|
|
4060
|
-
const tempPath =
|
|
4061
|
-
if (
|
|
4269
|
+
const tempPath = join9(OMNI_LOCAL, "_temp", `${id}-repo`);
|
|
4270
|
+
if (existsSync13(join9(tempPath, ".git"))) {
|
|
4062
4271
|
updated = await fetchRepo(tempPath, gitRef);
|
|
4063
4272
|
commit = await getRepoCommit(tempPath);
|
|
4064
4273
|
} else {
|
|
4065
|
-
await mkdir(
|
|
4274
|
+
await mkdir(join9(tempPath, ".."), { recursive: true });
|
|
4066
4275
|
await cloneRepo(gitUrl, tempPath, gitRef);
|
|
4067
4276
|
commit = await getRepoCommit(tempPath);
|
|
4068
4277
|
updated = true;
|
|
4069
4278
|
}
|
|
4070
|
-
const sourcePath =
|
|
4071
|
-
if (!
|
|
4279
|
+
const sourcePath = join9(tempPath, config.path);
|
|
4280
|
+
if (!existsSync13(sourcePath)) {
|
|
4072
4281
|
throw new Error(`Path not found in repository: ${config.path}`);
|
|
4073
4282
|
}
|
|
4074
|
-
|
|
4283
|
+
const sourceHasCapabilityToml = hasCapabilityToml(sourcePath);
|
|
4284
|
+
if (!sourceHasCapabilityToml) {
|
|
4285
|
+
needsWrap = await shouldWrapDirectory(sourcePath);
|
|
4286
|
+
}
|
|
4287
|
+
if (existsSync13(targetPath)) {
|
|
4075
4288
|
await rm(targetPath, { recursive: true });
|
|
4076
4289
|
}
|
|
4077
|
-
await mkdir(
|
|
4078
|
-
|
|
4290
|
+
await mkdir(join9(targetPath, ".."), { recursive: true });
|
|
4291
|
+
if (needsWrap) {
|
|
4292
|
+
await copyWrappedContentOnly(sourcePath, targetPath);
|
|
4293
|
+
} else {
|
|
4294
|
+
await cp(sourcePath, targetPath, { recursive: true });
|
|
4295
|
+
}
|
|
4079
4296
|
await rm(tempPath, { recursive: true });
|
|
4080
4297
|
repoPath = targetPath;
|
|
4081
4298
|
} else {
|
|
4082
|
-
if (
|
|
4299
|
+
if (existsSync13(join9(targetPath, ".git"))) {
|
|
4083
4300
|
if (!options?.silent) {
|
|
4084
4301
|
console.log(` Checking ${id}...`);
|
|
4085
4302
|
}
|
|
@@ -4095,11 +4312,11 @@ async function fetchGitCapabilitySource(id, config, options) {
|
|
|
4095
4312
|
}
|
|
4096
4313
|
repoPath = targetPath;
|
|
4097
4314
|
}
|
|
4098
|
-
|
|
4099
|
-
if (!hasCapabilityToml(repoPath)) {
|
|
4315
|
+
if (!config.path && !hasCapabilityToml(repoPath)) {
|
|
4100
4316
|
needsWrap = await shouldWrapDirectory(repoPath);
|
|
4101
4317
|
}
|
|
4102
4318
|
if (needsWrap) {
|
|
4319
|
+
await pruneUnknownWrappedEntries(repoPath, true);
|
|
4103
4320
|
await normalizeFolderNames(repoPath);
|
|
4104
4321
|
const content = await discoverContent(repoPath);
|
|
4105
4322
|
await generateCapabilityToml(id, repoPath, config.source, commit, content);
|
|
@@ -4130,7 +4347,7 @@ async function fetchGitCapabilitySource(id, config, options) {
|
|
|
4130
4347
|
async function fetchFileCapabilitySource(id, config, options) {
|
|
4131
4348
|
const sourcePath = parseFileSourcePath(config.source);
|
|
4132
4349
|
const targetPath = getSourceCapabilityPath(id);
|
|
4133
|
-
if (!
|
|
4350
|
+
if (!existsSync13(sourcePath)) {
|
|
4134
4351
|
throw new Error(`File source not found: ${sourcePath}`);
|
|
4135
4352
|
}
|
|
4136
4353
|
const sourceStats = await stat(sourcePath);
|
|
@@ -4138,7 +4355,7 @@ async function fetchFileCapabilitySource(id, config, options) {
|
|
|
4138
4355
|
throw new Error(`File source must be a directory: ${sourcePath}`);
|
|
4139
4356
|
}
|
|
4140
4357
|
const contentHash = await computeContentHash(sourcePath);
|
|
4141
|
-
const hasCapToml =
|
|
4358
|
+
const hasCapToml = existsSync13(join9(sourcePath, "capability.toml"));
|
|
4142
4359
|
let needsWrap = false;
|
|
4143
4360
|
if (!hasCapToml) {
|
|
4144
4361
|
needsWrap = await shouldWrapDirectory(sourcePath);
|
|
@@ -4149,11 +4366,15 @@ async function fetchFileCapabilitySource(id, config, options) {
|
|
|
4149
4366
|
if (!options?.silent) {
|
|
4150
4367
|
console.log(` Copying ${id} from ${sourcePath}...`);
|
|
4151
4368
|
}
|
|
4152
|
-
if (
|
|
4369
|
+
if (existsSync13(targetPath)) {
|
|
4153
4370
|
await rm(targetPath, { recursive: true });
|
|
4154
4371
|
}
|
|
4155
|
-
await mkdir(
|
|
4156
|
-
|
|
4372
|
+
await mkdir(join9(targetPath, ".."), { recursive: true });
|
|
4373
|
+
if (needsWrap) {
|
|
4374
|
+
await copyWrappedContentOnly(sourcePath, targetPath);
|
|
4375
|
+
} else {
|
|
4376
|
+
await cp(sourcePath, targetPath, { recursive: true });
|
|
4377
|
+
}
|
|
4157
4378
|
if (needsWrap) {
|
|
4158
4379
|
await normalizeFolderNames(targetPath);
|
|
4159
4380
|
const content = await discoverContent(targetPath);
|
|
@@ -4232,7 +4453,7 @@ description = "${escapeTomlString(description)}"
|
|
|
4232
4453
|
wrapped = true
|
|
4233
4454
|
source = "${escapeTomlString(source)}"
|
|
4234
4455
|
`;
|
|
4235
|
-
await writeFile3(
|
|
4456
|
+
await writeFile3(join9(targetPath, "capability.toml"), tomlContent, "utf-8");
|
|
4236
4457
|
}
|
|
4237
4458
|
async function fetchCapabilitySource(id, sourceConfig, options) {
|
|
4238
4459
|
const config = parseSourceConfig(sourceConfig);
|
|
@@ -4305,16 +4526,16 @@ generated_from_omni_toml = true
|
|
|
4305
4526
|
}
|
|
4306
4527
|
async function generateMcpCapabilityToml(id, mcpConfig, targetPath) {
|
|
4307
4528
|
const tomlContent = generateMcpCapabilityTomlContent(id, mcpConfig);
|
|
4308
|
-
await writeFile3(
|
|
4529
|
+
await writeFile3(join9(targetPath, "capability.toml"), tomlContent, "utf-8");
|
|
4309
4530
|
}
|
|
4310
4531
|
async function isGeneratedMcpCapability(capabilityDir) {
|
|
4311
|
-
const tomlPath =
|
|
4312
|
-
if (!
|
|
4532
|
+
const tomlPath = join9(capabilityDir, "capability.toml");
|
|
4533
|
+
if (!existsSync13(tomlPath)) {
|
|
4313
4534
|
console.warn("no capability.toml found in", capabilityDir);
|
|
4314
4535
|
return false;
|
|
4315
4536
|
}
|
|
4316
4537
|
try {
|
|
4317
|
-
const content = await
|
|
4538
|
+
const content = await readFile10(tomlPath, "utf-8");
|
|
4318
4539
|
const parsed = parse(content);
|
|
4319
4540
|
const capability = parsed["capability"];
|
|
4320
4541
|
const metadata = capability?.["metadata"];
|
|
@@ -4324,14 +4545,14 @@ async function isGeneratedMcpCapability(capabilityDir) {
|
|
|
4324
4545
|
}
|
|
4325
4546
|
}
|
|
4326
4547
|
async function cleanupStaleMcpCapabilities(currentMcpIds) {
|
|
4327
|
-
const capabilitiesDir =
|
|
4328
|
-
if (!
|
|
4548
|
+
const capabilitiesDir = join9(OMNI_LOCAL, "capabilities");
|
|
4549
|
+
if (!existsSync13(capabilitiesDir)) {
|
|
4329
4550
|
return;
|
|
4330
4551
|
}
|
|
4331
4552
|
const entries = await readdir(capabilitiesDir, { withFileTypes: true });
|
|
4332
4553
|
for (const entry of entries) {
|
|
4333
4554
|
if (entry.isDirectory()) {
|
|
4334
|
-
const capDir =
|
|
4555
|
+
const capDir = join9(capabilitiesDir, entry.name);
|
|
4335
4556
|
const isGenerated = await isGeneratedMcpCapability(capDir);
|
|
4336
4557
|
if (isGenerated && !currentMcpIds.has(entry.name)) {
|
|
4337
4558
|
await rm(capDir, { recursive: true });
|
|
@@ -4344,10 +4565,10 @@ async function generateMcpCapabilities(config) {
|
|
|
4344
4565
|
await cleanupStaleMcpCapabilities(new Set);
|
|
4345
4566
|
return;
|
|
4346
4567
|
}
|
|
4347
|
-
const mcpCapabilitiesDir =
|
|
4568
|
+
const mcpCapabilitiesDir = join9(OMNI_LOCAL, "capabilities");
|
|
4348
4569
|
const currentMcpIds = new Set;
|
|
4349
4570
|
for (const [id, mcpConfig] of Object.entries(config.mcps)) {
|
|
4350
|
-
const targetPath =
|
|
4571
|
+
const targetPath = join9(mcpCapabilitiesDir, id);
|
|
4351
4572
|
currentMcpIds.add(id);
|
|
4352
4573
|
await mkdir(targetPath, { recursive: true });
|
|
4353
4574
|
await generateMcpCapabilityToml(id, mcpConfig, targetPath);
|
|
@@ -4356,8 +4577,8 @@ async function generateMcpCapabilities(config) {
|
|
|
4356
4577
|
}
|
|
4357
4578
|
async function fetchAllCapabilitySources(config, options) {
|
|
4358
4579
|
await generateMcpCapabilities(config);
|
|
4359
|
-
const tempDir =
|
|
4360
|
-
if (
|
|
4580
|
+
const tempDir = join9(OMNI_LOCAL, "_temp");
|
|
4581
|
+
if (existsSync13(tempDir)) {
|
|
4361
4582
|
await rm(tempDir, { recursive: true });
|
|
4362
4583
|
}
|
|
4363
4584
|
const sources = config.capabilities?.sources;
|
|
@@ -4443,7 +4664,7 @@ async function checkForUpdates(config) {
|
|
|
4443
4664
|
continue;
|
|
4444
4665
|
}
|
|
4445
4666
|
const gitConfig = sourceConfig;
|
|
4446
|
-
if (!
|
|
4667
|
+
if (!existsSync13(join9(targetPath, ".git"))) {
|
|
4447
4668
|
updates.push({
|
|
4448
4669
|
id,
|
|
4449
4670
|
source: gitConfig.source,
|
|
@@ -4486,12 +4707,12 @@ function checkVersionMismatch(lockEntry, currentCommit, currentVersion) {
|
|
|
4486
4707
|
}
|
|
4487
4708
|
async function verifyIntegrity(id, lockEntry) {
|
|
4488
4709
|
const capabilityPath = getSourceCapabilityPath(id);
|
|
4489
|
-
if (!
|
|
4710
|
+
if (!existsSync13(capabilityPath)) {
|
|
4490
4711
|
return "capability directory missing";
|
|
4491
4712
|
}
|
|
4492
4713
|
if (lockEntry.commit) {
|
|
4493
|
-
const gitDir =
|
|
4494
|
-
if (
|
|
4714
|
+
const gitDir = join9(capabilityPath, ".git");
|
|
4715
|
+
if (existsSync13(gitDir)) {
|
|
4495
4716
|
try {
|
|
4496
4717
|
const currentCommit = await getRepoCommit(capabilityPath);
|
|
4497
4718
|
if (currentCommit !== lockEntry.commit) {
|
|
@@ -4510,7 +4731,7 @@ async function verifyIntegrity(id, lockEntry) {
|
|
|
4510
4731
|
}
|
|
4511
4732
|
return null;
|
|
4512
4733
|
}
|
|
4513
|
-
var OMNI_LOCAL = ".omni", SKILL_DIRS, AGENT_DIRS, COMMAND_DIRS, RULE_DIRS, DOC_DIRS, SKILL_FILES, AGENT_FILES, COMMAND_FILES, CONTENT_HASH_EXCLUDES;
|
|
4734
|
+
var OMNI_LOCAL = ".omni", SKILL_DIRS, AGENT_DIRS, COMMAND_DIRS, RULE_DIRS, DOC_DIRS, WRAPPED_CONTENT_DIRS, WRAPPED_ROOT_FILES_EXACT, WRAPPED_ROOT_FILE_PATTERNS, SKILL_FILES, AGENT_FILES, COMMAND_FILES, CONTENT_HASH_EXCLUDES;
|
|
4514
4735
|
var init_sources = __esm(() => {
|
|
4515
4736
|
init_dist();
|
|
4516
4737
|
init_types2();
|
|
@@ -4519,6 +4740,23 @@ var init_sources = __esm(() => {
|
|
|
4519
4740
|
COMMAND_DIRS = ["commands", "command"];
|
|
4520
4741
|
RULE_DIRS = ["rules", "rule"];
|
|
4521
4742
|
DOC_DIRS = ["docs", "doc", "documentation"];
|
|
4743
|
+
WRAPPED_CONTENT_DIRS = new Set([
|
|
4744
|
+
...SKILL_DIRS,
|
|
4745
|
+
...AGENT_DIRS,
|
|
4746
|
+
...COMMAND_DIRS,
|
|
4747
|
+
...RULE_DIRS,
|
|
4748
|
+
...DOC_DIRS,
|
|
4749
|
+
"hooks",
|
|
4750
|
+
".claude-plugin"
|
|
4751
|
+
]);
|
|
4752
|
+
WRAPPED_ROOT_FILES_EXACT = new Set([".gitignore", "hooks.json"]);
|
|
4753
|
+
WRAPPED_ROOT_FILE_PATTERNS = [
|
|
4754
|
+
/^readme(?:\..+)?$/i,
|
|
4755
|
+
/^license(?:\..+)?$/i,
|
|
4756
|
+
/^licence(?:\..+)?$/i,
|
|
4757
|
+
/^notice(?:\..+)?$/i,
|
|
4758
|
+
/^copying(?:\..+)?$/i
|
|
4759
|
+
];
|
|
4522
4760
|
SKILL_FILES = ["SKILL.md", "skill.md", "Skill.md"];
|
|
4523
4761
|
AGENT_FILES = ["AGENT.md", "agent.md", "Agent.md", "SUBAGENT.md", "subagent.md"];
|
|
4524
4762
|
COMMAND_FILES = ["COMMAND.md", "command.md", "Command.md"];
|
|
@@ -4560,13 +4798,13 @@ var init_hooks = __esm(() => {
|
|
|
4560
4798
|
});
|
|
4561
4799
|
|
|
4562
4800
|
// ../core/src/config/provider.ts
|
|
4563
|
-
import { existsSync as
|
|
4564
|
-
import { readFile as
|
|
4801
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
4802
|
+
import { readFile as readFile11, writeFile as writeFile4 } from "node:fs/promises";
|
|
4565
4803
|
async function loadProviderConfig() {
|
|
4566
|
-
if (!
|
|
4804
|
+
if (!existsSync14(PROVIDER_CONFIG_PATH)) {
|
|
4567
4805
|
return { provider: "claude" };
|
|
4568
4806
|
}
|
|
4569
|
-
const content = await
|
|
4807
|
+
const content = await readFile11(PROVIDER_CONFIG_PATH, "utf-8");
|
|
4570
4808
|
const parsed = parse(content);
|
|
4571
4809
|
return parsed;
|
|
4572
4810
|
}
|
|
@@ -4613,13 +4851,13 @@ var init_provider = __esm(() => {
|
|
|
4613
4851
|
});
|
|
4614
4852
|
|
|
4615
4853
|
// ../core/src/config/toml-patcher.ts
|
|
4616
|
-
import { existsSync as
|
|
4617
|
-
import { readFile as
|
|
4854
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
4855
|
+
import { readFile as readFile12, writeFile as writeFile5 } from "node:fs/promises";
|
|
4618
4856
|
async function readConfigFile() {
|
|
4619
|
-
if (!
|
|
4857
|
+
if (!existsSync15(CONFIG_PATH2)) {
|
|
4620
4858
|
return "";
|
|
4621
4859
|
}
|
|
4622
|
-
return
|
|
4860
|
+
return readFile12(CONFIG_PATH2, "utf-8");
|
|
4623
4861
|
}
|
|
4624
4862
|
async function writeConfigFile(content) {
|
|
4625
4863
|
await writeFile5(CONFIG_PATH2, content, "utf-8");
|
|
@@ -4841,14 +5079,14 @@ var init_config2 = __esm(() => {
|
|
|
4841
5079
|
});
|
|
4842
5080
|
|
|
4843
5081
|
// ../core/src/mcp-json/manager.ts
|
|
4844
|
-
import { existsSync as
|
|
4845
|
-
import { readFile as
|
|
5082
|
+
import { existsSync as existsSync16 } from "node:fs";
|
|
5083
|
+
import { readFile as readFile13, writeFile as writeFile6 } from "node:fs/promises";
|
|
4846
5084
|
async function readMcpJson() {
|
|
4847
|
-
if (!
|
|
5085
|
+
if (!existsSync16(MCP_JSON_PATH)) {
|
|
4848
5086
|
return { mcpServers: {} };
|
|
4849
5087
|
}
|
|
4850
5088
|
try {
|
|
4851
|
-
const content = await
|
|
5089
|
+
const content = await readFile13(MCP_JSON_PATH, "utf-8");
|
|
4852
5090
|
const parsed = JSON.parse(content);
|
|
4853
5091
|
return {
|
|
4854
5092
|
mcpServers: parsed.mcpServers || {}
|
|
@@ -4930,17 +5168,17 @@ var init_mcp_json = __esm(() => {
|
|
|
4930
5168
|
});
|
|
4931
5169
|
|
|
4932
5170
|
// ../core/src/state/manifest.ts
|
|
4933
|
-
import { existsSync as
|
|
4934
|
-
import { readFile as
|
|
5171
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync2, rmSync } from "node:fs";
|
|
5172
|
+
import { readFile as readFile14, writeFile as writeFile7 } from "node:fs/promises";
|
|
4935
5173
|
async function loadManifest() {
|
|
4936
|
-
if (!
|
|
5174
|
+
if (!existsSync17(MANIFEST_PATH)) {
|
|
4937
5175
|
return {
|
|
4938
5176
|
version: CURRENT_VERSION,
|
|
4939
5177
|
syncedAt: new Date().toISOString(),
|
|
4940
5178
|
capabilities: {}
|
|
4941
5179
|
};
|
|
4942
5180
|
}
|
|
4943
|
-
const content = await
|
|
5181
|
+
const content = await readFile14(MANIFEST_PATH, "utf-8");
|
|
4944
5182
|
return JSON.parse(content);
|
|
4945
5183
|
}
|
|
4946
5184
|
async function saveManifest(manifest) {
|
|
@@ -4980,14 +5218,14 @@ async function cleanupStaleResources(previousManifest, currentCapabilityIds) {
|
|
|
4980
5218
|
}
|
|
4981
5219
|
for (const skillName of resources.skills) {
|
|
4982
5220
|
const skillDir = `.claude/skills/${skillName}`;
|
|
4983
|
-
if (
|
|
5221
|
+
if (existsSync17(skillDir)) {
|
|
4984
5222
|
rmSync(skillDir, { recursive: true });
|
|
4985
5223
|
result.deletedSkills.push(skillName);
|
|
4986
5224
|
}
|
|
4987
5225
|
}
|
|
4988
5226
|
for (const ruleName of resources.rules) {
|
|
4989
5227
|
const rulePath = `.cursor/rules/omnidev-${ruleName}.mdc`;
|
|
4990
|
-
if (
|
|
5228
|
+
if (existsSync17(rulePath)) {
|
|
4991
5229
|
rmSync(rulePath);
|
|
4992
5230
|
result.deletedRules.push(ruleName);
|
|
4993
5231
|
}
|
|
@@ -4999,14 +5237,14 @@ var MANIFEST_PATH = ".omni/state/manifest.json", CURRENT_VERSION = 1;
|
|
|
4999
5237
|
var init_manifest = () => {};
|
|
5000
5238
|
|
|
5001
5239
|
// ../core/src/state/providers.ts
|
|
5002
|
-
import { existsSync as
|
|
5003
|
-
import { readFile as
|
|
5240
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync3 } from "node:fs";
|
|
5241
|
+
import { readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
|
|
5004
5242
|
async function readEnabledProviders() {
|
|
5005
|
-
if (!
|
|
5243
|
+
if (!existsSync18(PROVIDERS_PATH)) {
|
|
5006
5244
|
return DEFAULT_PROVIDERS;
|
|
5007
5245
|
}
|
|
5008
5246
|
try {
|
|
5009
|
-
const content = await
|
|
5247
|
+
const content = await readFile15(PROVIDERS_PATH, "utf-8");
|
|
5010
5248
|
const state = JSON.parse(content);
|
|
5011
5249
|
return state.enabled.length > 0 ? state.enabled : DEFAULT_PROVIDERS;
|
|
5012
5250
|
} catch {
|
|
@@ -5035,20 +5273,20 @@ async function isProviderEnabled(providerId) {
|
|
|
5035
5273
|
return current.includes(providerId);
|
|
5036
5274
|
}
|
|
5037
5275
|
var STATE_DIR2 = ".omni/state", PROVIDERS_PATH, DEFAULT_PROVIDERS;
|
|
5038
|
-
var
|
|
5276
|
+
var init_providers2 = __esm(() => {
|
|
5039
5277
|
PROVIDERS_PATH = `${STATE_DIR2}/providers.json`;
|
|
5040
5278
|
DEFAULT_PROVIDERS = ["claude-code"];
|
|
5041
5279
|
});
|
|
5042
5280
|
|
|
5043
5281
|
// ../core/src/state/security-allows.ts
|
|
5044
|
-
import { existsSync as
|
|
5045
|
-
import { readFile as
|
|
5282
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync4 } from "node:fs";
|
|
5283
|
+
import { readFile as readFile16, writeFile as writeFile9 } from "node:fs/promises";
|
|
5046
5284
|
async function readSecurityAllows() {
|
|
5047
|
-
if (!
|
|
5285
|
+
if (!existsSync19(SECURITY_PATH)) {
|
|
5048
5286
|
return { ...DEFAULT_STATE };
|
|
5049
5287
|
}
|
|
5050
5288
|
try {
|
|
5051
|
-
const content = await
|
|
5289
|
+
const content = await readFile16(SECURITY_PATH, "utf-8");
|
|
5052
5290
|
const state = JSON.parse(content);
|
|
5053
5291
|
return state;
|
|
5054
5292
|
} catch {
|
|
@@ -5137,19 +5375,45 @@ var init_security_allows = __esm(() => {
|
|
|
5137
5375
|
var init_state = __esm(() => {
|
|
5138
5376
|
init_active_profile();
|
|
5139
5377
|
init_manifest();
|
|
5140
|
-
|
|
5378
|
+
init_providers2();
|
|
5141
5379
|
init_security_allows();
|
|
5142
5380
|
});
|
|
5143
5381
|
|
|
5144
5382
|
// ../core/src/sync.ts
|
|
5145
5383
|
import { spawn as spawn2 } from "node:child_process";
|
|
5146
|
-
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
5384
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
5385
|
+
import { join as join10 } from "node:path";
|
|
5386
|
+
function getDeclaredPackageManager(packageManager) {
|
|
5387
|
+
if (typeof packageManager !== "string" || packageManager.trim().length === 0) {
|
|
5388
|
+
return;
|
|
5389
|
+
}
|
|
5390
|
+
const atIndex = packageManager.indexOf("@");
|
|
5391
|
+
return atIndex === -1 ? packageManager : packageManager.slice(0, atIndex);
|
|
5392
|
+
}
|
|
5393
|
+
function resolveCapabilityInstallCommand(capabilityPath, options) {
|
|
5394
|
+
const packageJsonPath = join10(capabilityPath, "package.json");
|
|
5395
|
+
const packageLockPath = join10(capabilityPath, "package-lock.json");
|
|
5396
|
+
let packageManager;
|
|
5397
|
+
try {
|
|
5398
|
+
const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
5399
|
+
packageManager = getDeclaredPackageManager(pkgJson.packageManager);
|
|
5400
|
+
} catch {}
|
|
5401
|
+
if (!options.hasNpm) {
|
|
5402
|
+
throw new Error("npm is not installed. Install npm to install capability dependencies.");
|
|
5403
|
+
}
|
|
5404
|
+
if (packageManager && packageManager !== "npm") {
|
|
5405
|
+
throw new Error(`Capability at ${capabilityPath} declares packageManager=${packageManager}, but OmniDev only supports npm for capability dependencies.`);
|
|
5406
|
+
}
|
|
5407
|
+
return {
|
|
5408
|
+
cmd: "npm",
|
|
5409
|
+
args: [existsSync20(packageLockPath) ? "ci" : "install"]
|
|
5410
|
+
};
|
|
5411
|
+
}
|
|
5147
5412
|
async function installCapabilityDependencies(silent) {
|
|
5148
|
-
const {
|
|
5149
|
-
const { join: join9 } = await import("node:path");
|
|
5413
|
+
const { readdirSync: readdirSync7 } = await import("node:fs");
|
|
5150
5414
|
const { parse: parse2 } = await Promise.resolve().then(() => (init_dist(), exports_dist));
|
|
5151
5415
|
const capabilitiesDir = ".omni/capabilities";
|
|
5152
|
-
if (!
|
|
5416
|
+
if (!existsSync20(capabilitiesDir)) {
|
|
5153
5417
|
return;
|
|
5154
5418
|
}
|
|
5155
5419
|
const entries = readdirSync7(capabilitiesDir, { withFileTypes: true });
|
|
@@ -5160,22 +5424,21 @@ async function installCapabilityDependencies(silent) {
|
|
|
5160
5424
|
proc.on("close", (code) => resolve2(code === 0));
|
|
5161
5425
|
});
|
|
5162
5426
|
}
|
|
5163
|
-
const
|
|
5164
|
-
|
|
5165
|
-
|
|
5166
|
-
throw new Error("Neither Bun nor npm is installed. Install one of them to install capability dependencies.");
|
|
5427
|
+
const hasNpm = await commandExists("npm");
|
|
5428
|
+
if (!hasNpm) {
|
|
5429
|
+
throw new Error("npm is not installed. Install npm to install capability dependencies.");
|
|
5167
5430
|
}
|
|
5168
5431
|
for (const entry of entries) {
|
|
5169
5432
|
if (!entry.isDirectory()) {
|
|
5170
5433
|
continue;
|
|
5171
5434
|
}
|
|
5172
|
-
const capabilityPath =
|
|
5173
|
-
const packageJsonPath =
|
|
5174
|
-
const capabilityTomlPath =
|
|
5175
|
-
if (!
|
|
5435
|
+
const capabilityPath = join10(capabilitiesDir, entry.name);
|
|
5436
|
+
const packageJsonPath = join10(capabilityPath, "package.json");
|
|
5437
|
+
const capabilityTomlPath = join10(capabilityPath, "capability.toml");
|
|
5438
|
+
if (!existsSync20(packageJsonPath)) {
|
|
5176
5439
|
continue;
|
|
5177
5440
|
}
|
|
5178
|
-
if (
|
|
5441
|
+
if (existsSync20(capabilityTomlPath)) {
|
|
5179
5442
|
try {
|
|
5180
5443
|
const tomlContent = readFileSync3(capabilityTomlPath, "utf-8");
|
|
5181
5444
|
const parsed = parse2(tomlContent);
|
|
@@ -5186,9 +5449,9 @@ async function installCapabilityDependencies(silent) {
|
|
|
5186
5449
|
}
|
|
5187
5450
|
try {
|
|
5188
5451
|
await new Promise((resolve2, reject) => {
|
|
5189
|
-
const
|
|
5190
|
-
|
|
5191
|
-
|
|
5452
|
+
const { cmd, args } = resolveCapabilityInstallCommand(capabilityPath, {
|
|
5453
|
+
hasNpm
|
|
5454
|
+
});
|
|
5192
5455
|
const proc = spawn2(cmd, args, {
|
|
5193
5456
|
cwd: capabilityPath,
|
|
5194
5457
|
stdio: "pipe"
|
|
@@ -5209,7 +5472,7 @@ ${stderr}`));
|
|
|
5209
5472
|
reject(error);
|
|
5210
5473
|
});
|
|
5211
5474
|
});
|
|
5212
|
-
const hasIndexTs =
|
|
5475
|
+
const hasIndexTs = existsSync20(join10(capabilityPath, "index.ts"));
|
|
5213
5476
|
let hasBuildScript = false;
|
|
5214
5477
|
try {
|
|
5215
5478
|
const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
@@ -5217,9 +5480,7 @@ ${stderr}`));
|
|
|
5217
5480
|
} catch {}
|
|
5218
5481
|
if (hasBuildScript) {
|
|
5219
5482
|
await new Promise((resolve2, reject) => {
|
|
5220
|
-
const
|
|
5221
|
-
const args = ["run", "build"];
|
|
5222
|
-
const proc = spawn2(cmd, args, {
|
|
5483
|
+
const proc = spawn2("npm", ["run", "build"], {
|
|
5223
5484
|
cwd: capabilityPath,
|
|
5224
5485
|
stdio: "pipe"
|
|
5225
5486
|
});
|
|
@@ -5240,7 +5501,7 @@ ${stderr}`));
|
|
|
5240
5501
|
});
|
|
5241
5502
|
});
|
|
5242
5503
|
} else if (hasIndexTs && !silent) {
|
|
5243
|
-
const hasBuiltIndex =
|
|
5504
|
+
const hasBuiltIndex = existsSync20(join10(capabilityPath, "dist", "index.js"));
|
|
5244
5505
|
if (!hasBuiltIndex) {
|
|
5245
5506
|
console.warn(`Warning: Capability at ${capabilityPath} has index.ts but no build script.
|
|
5246
5507
|
Add a "build" script to package.json (e.g., "build": "tsc") to compile TypeScript.`);
|
|
@@ -5371,25 +5632,27 @@ var init_types3 = __esm(() => {
|
|
|
5371
5632
|
unicode: true,
|
|
5372
5633
|
symlinks: true,
|
|
5373
5634
|
scripts: true,
|
|
5374
|
-
binaries: false
|
|
5635
|
+
binaries: false,
|
|
5636
|
+
hiddenCommands: true
|
|
5375
5637
|
}
|
|
5376
5638
|
};
|
|
5377
5639
|
DEFAULT_SCAN_SETTINGS = {
|
|
5378
5640
|
unicode: true,
|
|
5379
5641
|
symlinks: true,
|
|
5380
5642
|
scripts: true,
|
|
5381
|
-
binaries: false
|
|
5643
|
+
binaries: false,
|
|
5644
|
+
hiddenCommands: true
|
|
5382
5645
|
};
|
|
5383
5646
|
});
|
|
5384
5647
|
|
|
5385
5648
|
// ../core/src/security/scanner.ts
|
|
5386
|
-
import { existsSync as
|
|
5387
|
-
import { lstat, readdir as readdir2, readFile as
|
|
5388
|
-
import { join as
|
|
5649
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
5650
|
+
import { lstat, readdir as readdir2, readFile as readFile17, readlink, realpath } from "node:fs/promises";
|
|
5651
|
+
import { join as join11, relative, resolve as resolve2 } from "node:path";
|
|
5389
5652
|
async function scanFileForUnicode(filePath, relativePath) {
|
|
5390
5653
|
const findings = [];
|
|
5391
5654
|
try {
|
|
5392
|
-
const content = await
|
|
5655
|
+
const content = await readFile17(filePath, "utf-8");
|
|
5393
5656
|
const lines = content.split(`
|
|
5394
5657
|
`);
|
|
5395
5658
|
for (let lineNum = 0;lineNum < lines.length; lineNum++) {
|
|
@@ -5443,7 +5706,7 @@ async function scanFileForUnicode(filePath, relativePath) {
|
|
|
5443
5706
|
async function scanFileForScripts(filePath, relativePath) {
|
|
5444
5707
|
const findings = [];
|
|
5445
5708
|
try {
|
|
5446
|
-
const content = await
|
|
5709
|
+
const content = await readFile17(filePath, "utf-8");
|
|
5447
5710
|
const lines = content.split(`
|
|
5448
5711
|
`);
|
|
5449
5712
|
for (let lineNum = 0;lineNum < lines.length; lineNum++) {
|
|
@@ -5466,10 +5729,113 @@ async function scanFileForScripts(filePath, relativePath) {
|
|
|
5466
5729
|
} catch {}
|
|
5467
5730
|
return findings;
|
|
5468
5731
|
}
|
|
5732
|
+
function extractHiddenRegions(fileContent) {
|
|
5733
|
+
const regions = [];
|
|
5734
|
+
HTML_COMMENT_RE.lastIndex = 0;
|
|
5735
|
+
for (let match = HTML_COMMENT_RE.exec(fileContent);match !== null; match = HTML_COMMENT_RE.exec(fileContent)) {
|
|
5736
|
+
const captured = match[1];
|
|
5737
|
+
if (captured === undefined)
|
|
5738
|
+
continue;
|
|
5739
|
+
const beforeMatch = fileContent.substring(0, match.index);
|
|
5740
|
+
const startLine = beforeMatch.split(`
|
|
5741
|
+
`).length;
|
|
5742
|
+
regions.push({ content: captured, startLine });
|
|
5743
|
+
}
|
|
5744
|
+
HIDDEN_REFERENCE_RE.lastIndex = 0;
|
|
5745
|
+
for (let match = HIDDEN_REFERENCE_RE.exec(fileContent);match !== null; match = HIDDEN_REFERENCE_RE.exec(fileContent)) {
|
|
5746
|
+
const captured = match[1];
|
|
5747
|
+
if (captured === undefined)
|
|
5748
|
+
continue;
|
|
5749
|
+
const beforeMatch = fileContent.substring(0, match.index);
|
|
5750
|
+
const startLine = beforeMatch.split(`
|
|
5751
|
+
`).length;
|
|
5752
|
+
regions.push({ content: captured, startLine });
|
|
5753
|
+
}
|
|
5754
|
+
return regions;
|
|
5755
|
+
}
|
|
5756
|
+
async function scanFileForHiddenCommands(filePath, relativePath) {
|
|
5757
|
+
const findings = [];
|
|
5758
|
+
try {
|
|
5759
|
+
const content = await readFile17(filePath, "utf-8");
|
|
5760
|
+
const hiddenRegions = extractHiddenRegions(content);
|
|
5761
|
+
for (const region of hiddenRegions) {
|
|
5762
|
+
const regionLines = region.content.split(`
|
|
5763
|
+
`);
|
|
5764
|
+
for (let i = 0;i < regionLines.length; i++) {
|
|
5765
|
+
const line = regionLines[i] ?? "";
|
|
5766
|
+
if (!line.trim())
|
|
5767
|
+
continue;
|
|
5768
|
+
for (const { pattern, message, severity } of HIDDEN_COMMAND_PATTERNS) {
|
|
5769
|
+
if (pattern.test(line)) {
|
|
5770
|
+
findings.push({
|
|
5771
|
+
type: "hidden_command",
|
|
5772
|
+
severity,
|
|
5773
|
+
file: relativePath,
|
|
5774
|
+
line: region.startLine + i,
|
|
5775
|
+
message: `Hidden in comment: ${message}`,
|
|
5776
|
+
details: line.trim().substring(0, 100)
|
|
5777
|
+
});
|
|
5778
|
+
}
|
|
5779
|
+
}
|
|
5780
|
+
for (const { pattern, message, severity } of NETWORK_REQUEST_PATTERNS) {
|
|
5781
|
+
if (pattern.test(line)) {
|
|
5782
|
+
findings.push({
|
|
5783
|
+
type: "network_request",
|
|
5784
|
+
severity: severity === "medium" ? "high" : severity,
|
|
5785
|
+
file: relativePath,
|
|
5786
|
+
line: region.startLine + i,
|
|
5787
|
+
message: `Hidden in comment: ${message}`,
|
|
5788
|
+
details: line.trim().substring(0, 100)
|
|
5789
|
+
});
|
|
5790
|
+
}
|
|
5791
|
+
}
|
|
5792
|
+
for (const { pattern, message, severity } of SUSPICIOUS_SCRIPT_PATTERNS) {
|
|
5793
|
+
if (pattern.test(line)) {
|
|
5794
|
+
findings.push({
|
|
5795
|
+
type: "hidden_command",
|
|
5796
|
+
severity: severity === "medium" ? "high" : severity,
|
|
5797
|
+
file: relativePath,
|
|
5798
|
+
line: region.startLine + i,
|
|
5799
|
+
message: `Hidden in comment: ${message}`,
|
|
5800
|
+
details: line.trim().substring(0, 100)
|
|
5801
|
+
});
|
|
5802
|
+
}
|
|
5803
|
+
}
|
|
5804
|
+
}
|
|
5805
|
+
}
|
|
5806
|
+
} catch {}
|
|
5807
|
+
return findings;
|
|
5808
|
+
}
|
|
5809
|
+
async function scanFileForNetworkRequests(filePath, relativePath) {
|
|
5810
|
+
const findings = [];
|
|
5811
|
+
try {
|
|
5812
|
+
const content = await readFile17(filePath, "utf-8");
|
|
5813
|
+
const lines = content.split(`
|
|
5814
|
+
`);
|
|
5815
|
+
for (let lineNum = 0;lineNum < lines.length; lineNum++) {
|
|
5816
|
+
const line = lines[lineNum];
|
|
5817
|
+
if (!line)
|
|
5818
|
+
continue;
|
|
5819
|
+
for (const { pattern, message, severity } of NETWORK_REQUEST_PATTERNS) {
|
|
5820
|
+
if (pattern.test(line)) {
|
|
5821
|
+
findings.push({
|
|
5822
|
+
type: "network_request",
|
|
5823
|
+
severity,
|
|
5824
|
+
file: relativePath,
|
|
5825
|
+
line: lineNum + 1,
|
|
5826
|
+
message,
|
|
5827
|
+
details: line.trim().substring(0, 100)
|
|
5828
|
+
});
|
|
5829
|
+
}
|
|
5830
|
+
}
|
|
5831
|
+
}
|
|
5832
|
+
} catch {}
|
|
5833
|
+
return findings;
|
|
5834
|
+
}
|
|
5469
5835
|
async function checkSymlink(symlinkPath, relativePath, capabilityRoot) {
|
|
5470
5836
|
try {
|
|
5471
5837
|
const linkTarget = await readlink(symlinkPath);
|
|
5472
|
-
const resolvedTarget = resolve2(
|
|
5838
|
+
const resolvedTarget = resolve2(join11(symlinkPath, "..", linkTarget));
|
|
5473
5839
|
const normalizedRoot = await realpath(capabilityRoot);
|
|
5474
5840
|
if (linkTarget.startsWith("/")) {
|
|
5475
5841
|
return {
|
|
@@ -5504,7 +5870,7 @@ function isTextFile(filePath) {
|
|
|
5504
5870
|
async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_SCAN_SETTINGS) {
|
|
5505
5871
|
const startTime = Date.now();
|
|
5506
5872
|
const findings = [];
|
|
5507
|
-
if (!
|
|
5873
|
+
if (!existsSync21(capabilityPath)) {
|
|
5508
5874
|
return {
|
|
5509
5875
|
capabilityId,
|
|
5510
5876
|
path: capabilityPath,
|
|
@@ -5516,7 +5882,7 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
|
|
|
5516
5882
|
async function scanDirectory(dirPath) {
|
|
5517
5883
|
const entries = await readdir2(dirPath, { withFileTypes: true });
|
|
5518
5884
|
for (const entry of entries) {
|
|
5519
|
-
const fullPath =
|
|
5885
|
+
const fullPath = join11(dirPath, entry.name);
|
|
5520
5886
|
const relativePath = relative(capabilityPath, fullPath);
|
|
5521
5887
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "__pycache__") {
|
|
5522
5888
|
continue;
|
|
@@ -5543,17 +5909,27 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
|
|
|
5543
5909
|
});
|
|
5544
5910
|
}
|
|
5545
5911
|
if (isTextFile(fullPath)) {
|
|
5912
|
+
const ext = fullPath.toLowerCase().substring(fullPath.lastIndexOf("."));
|
|
5546
5913
|
if (settings.unicode) {
|
|
5547
5914
|
const unicodeFindings = await scanFileForUnicode(fullPath, relativePath);
|
|
5548
5915
|
findings.push(...unicodeFindings);
|
|
5549
5916
|
}
|
|
5550
5917
|
if (settings.scripts) {
|
|
5551
|
-
const ext = fullPath.toLowerCase().substring(fullPath.lastIndexOf("."));
|
|
5552
5918
|
if ([".sh", ".bash", ".zsh", ".fish", ".py", ".rb", ".js", ".ts"].includes(ext)) {
|
|
5553
5919
|
const scriptFindings = await scanFileForScripts(fullPath, relativePath);
|
|
5554
5920
|
findings.push(...scriptFindings);
|
|
5555
5921
|
}
|
|
5556
5922
|
}
|
|
5923
|
+
if (settings.hiddenCommands) {
|
|
5924
|
+
if ([".md", ".txt", ".yaml", ".yml", ".toml"].includes(ext)) {
|
|
5925
|
+
const hiddenFindings = await scanFileForHiddenCommands(fullPath, relativePath);
|
|
5926
|
+
findings.push(...hiddenFindings);
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
if (settings.hiddenCommands) {
|
|
5930
|
+
const networkFindings = await scanFileForNetworkRequests(fullPath, relativePath);
|
|
5931
|
+
findings.push(...networkFindings);
|
|
5932
|
+
}
|
|
5557
5933
|
}
|
|
5558
5934
|
}
|
|
5559
5935
|
}
|
|
@@ -5585,7 +5961,9 @@ async function scanCapabilities(capabilities2, config2 = {}) {
|
|
|
5585
5961
|
symlink_escape: 0,
|
|
5586
5962
|
symlink_absolute: 0,
|
|
5587
5963
|
suspicious_script: 0,
|
|
5588
|
-
binary_file: 0
|
|
5964
|
+
binary_file: 0,
|
|
5965
|
+
hidden_command: 0,
|
|
5966
|
+
network_request: 0
|
|
5589
5967
|
};
|
|
5590
5968
|
const findingsBySeverity = {
|
|
5591
5969
|
low: 0,
|
|
@@ -5660,7 +6038,7 @@ function formatScanResults(summary, verbose = false) {
|
|
|
5660
6038
|
return lines.join(`
|
|
5661
6039
|
`);
|
|
5662
6040
|
}
|
|
5663
|
-
var UNICODE_PATTERNS, SUSPICIOUS_SCRIPT_PATTERNS, BINARY_EXTENSIONS, TEXT_EXTENSIONS;
|
|
6041
|
+
var UNICODE_PATTERNS, SUSPICIOUS_SCRIPT_PATTERNS, NETWORK_REQUEST_PATTERNS, HIDDEN_COMMAND_PATTERNS, BINARY_EXTENSIONS, TEXT_EXTENSIONS, HTML_COMMENT_RE, HIDDEN_REFERENCE_RE;
|
|
5664
6042
|
var init_scanner = __esm(() => {
|
|
5665
6043
|
init_types3();
|
|
5666
6044
|
UNICODE_PATTERNS = {
|
|
@@ -5752,6 +6130,75 @@ var init_scanner = __esm(() => {
|
|
|
5752
6130
|
severity: "high"
|
|
5753
6131
|
}
|
|
5754
6132
|
];
|
|
6133
|
+
NETWORK_REQUEST_PATTERNS = [
|
|
6134
|
+
{
|
|
6135
|
+
pattern: /\bcurl\s+.*https?:\/\//i,
|
|
6136
|
+
message: "Outbound curl request detected",
|
|
6137
|
+
severity: "medium"
|
|
6138
|
+
},
|
|
6139
|
+
{
|
|
6140
|
+
pattern: /\bwget\s+.*https?:\/\//i,
|
|
6141
|
+
message: "Outbound wget request detected",
|
|
6142
|
+
severity: "medium"
|
|
6143
|
+
},
|
|
6144
|
+
{
|
|
6145
|
+
pattern: /\bfetch\s*\(\s*["'`]https?:\/\//i,
|
|
6146
|
+
message: "Outbound fetch() request detected",
|
|
6147
|
+
severity: "medium"
|
|
6148
|
+
},
|
|
6149
|
+
{
|
|
6150
|
+
pattern: /\b(?:http|https)\.(?:get|request|post|put)\s*\(/i,
|
|
6151
|
+
message: "Outbound HTTP request via Node.js http module",
|
|
6152
|
+
severity: "medium"
|
|
6153
|
+
},
|
|
6154
|
+
{
|
|
6155
|
+
pattern: /\brequests\.(?:get|post|put|delete|patch)\s*\(/i,
|
|
6156
|
+
message: "Outbound HTTP request via Python requests",
|
|
6157
|
+
severity: "medium"
|
|
6158
|
+
},
|
|
6159
|
+
{
|
|
6160
|
+
pattern: /\bnc\b.*\s\d{2,5}\b/i,
|
|
6161
|
+
message: "Netcat connection detected",
|
|
6162
|
+
severity: "high"
|
|
6163
|
+
},
|
|
6164
|
+
{
|
|
6165
|
+
pattern: /\b(?:Invoke-WebRequest|Invoke-RestMethod|iwr|irm)\b/i,
|
|
6166
|
+
message: "Outbound PowerShell web request detected",
|
|
6167
|
+
severity: "medium"
|
|
6168
|
+
}
|
|
6169
|
+
];
|
|
6170
|
+
HIDDEN_COMMAND_PATTERNS = [
|
|
6171
|
+
{
|
|
6172
|
+
pattern: /`[^`]*(?:curl|wget|bash|sh|python|ruby|node|exec|eval|system)\s[^`]*`/i,
|
|
6173
|
+
message: "Executable command in backtick-wrapped code",
|
|
6174
|
+
severity: "critical"
|
|
6175
|
+
},
|
|
6176
|
+
{
|
|
6177
|
+
pattern: /\|\s*(?:ba)?sh\b/i,
|
|
6178
|
+
message: "Pipe to shell execution",
|
|
6179
|
+
severity: "critical"
|
|
6180
|
+
},
|
|
6181
|
+
{
|
|
6182
|
+
pattern: /(?:^|\s)(?:bash|sh|zsh)\s+-c\s+/i,
|
|
6183
|
+
message: "Shell invocation with -c flag",
|
|
6184
|
+
severity: "high"
|
|
6185
|
+
},
|
|
6186
|
+
{
|
|
6187
|
+
pattern: /\b(?:curl|wget)\s+.*https?:\/\//i,
|
|
6188
|
+
message: "Network fetch command detected",
|
|
6189
|
+
severity: "high"
|
|
6190
|
+
},
|
|
6191
|
+
{
|
|
6192
|
+
pattern: /\b(?:python|ruby|node)\s+-e\s+/i,
|
|
6193
|
+
message: "Inline script execution",
|
|
6194
|
+
severity: "high"
|
|
6195
|
+
},
|
|
6196
|
+
{
|
|
6197
|
+
pattern: /\beval\s*\(.*\)/i,
|
|
6198
|
+
message: "eval() call detected",
|
|
6199
|
+
severity: "high"
|
|
6200
|
+
}
|
|
6201
|
+
];
|
|
5755
6202
|
BINARY_EXTENSIONS = new Set([
|
|
5756
6203
|
".exe",
|
|
5757
6204
|
".dll",
|
|
@@ -5786,6 +6233,8 @@ var init_scanner = __esm(() => {
|
|
|
5786
6233
|
".py",
|
|
5787
6234
|
".rb"
|
|
5788
6235
|
]);
|
|
6236
|
+
HTML_COMMENT_RE = /<!--([\s\S]*?)-->/g;
|
|
6237
|
+
HIDDEN_REFERENCE_RE = /^\[.*?\]:\s*\S+\s+"(.+)"/gm;
|
|
5789
6238
|
});
|
|
5790
6239
|
|
|
5791
6240
|
// ../core/src/security/index.ts
|
|
@@ -5995,6 +6444,7 @@ __export(exports_src, {
|
|
|
5995
6444
|
resolveEnabledCapabilities: () => resolveEnabledCapabilities,
|
|
5996
6445
|
resolveCapabilityRootInConfig: () => resolveCapabilityRootInConfig,
|
|
5997
6446
|
resolveCapabilityRoot: () => resolveCapabilityRoot,
|
|
6447
|
+
resolveCapabilityInstallCommand: () => resolveCapabilityInstallCommand,
|
|
5998
6448
|
removeSecurityAllow: () => removeSecurityAllow,
|
|
5999
6449
|
readSecurityAllows: () => readSecurityAllows,
|
|
6000
6450
|
readMcpJson: () => readMcpJson,
|
|
@@ -6009,6 +6459,8 @@ __export(exports_src, {
|
|
|
6009
6459
|
parseOmniConfig: () => parseOmniConfig,
|
|
6010
6460
|
parseFileSourcePath: () => parseFileSourcePath,
|
|
6011
6461
|
parseCapabilityConfig: () => parseCapabilityConfig,
|
|
6462
|
+
normalizeProviderId: () => normalizeProviderId,
|
|
6463
|
+
normalizeProviderApplicability: () => normalizeProviderApplicability,
|
|
6012
6464
|
mergeHooksConfigs: () => mergeHooksConfigs,
|
|
6013
6465
|
mergeAndDeduplicateHooks: () => mergeAndDeduplicateHooks,
|
|
6014
6466
|
loadSubagents: () => loadSubagents,
|
|
@@ -6116,6 +6568,7 @@ var init_src = __esm(() => {
|
|
|
6116
6568
|
init_state();
|
|
6117
6569
|
init_sync();
|
|
6118
6570
|
init_security();
|
|
6571
|
+
init_providers();
|
|
6119
6572
|
init_types2();
|
|
6120
6573
|
});
|
|
6121
6574
|
|
|
@@ -6123,17 +6576,17 @@ var init_src = __esm(() => {
|
|
|
6123
6576
|
import { run } from "@stricli/core";
|
|
6124
6577
|
|
|
6125
6578
|
// src/lib/dynamic-app.ts
|
|
6126
|
-
import { existsSync as
|
|
6579
|
+
import { existsSync as existsSync31 } from "node:fs";
|
|
6127
6580
|
import { createRequire as createRequire2 } from "node:module";
|
|
6128
|
-
import { join as
|
|
6581
|
+
import { join as join28 } from "node:path";
|
|
6129
6582
|
import { buildApplication, buildRouteMap as buildRouteMap7 } from "@stricli/core";
|
|
6130
6583
|
|
|
6131
6584
|
// src/commands/add.ts
|
|
6132
|
-
import { existsSync as
|
|
6585
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
6133
6586
|
import { basename as basename5, resolve as resolve3 } from "node:path";
|
|
6134
6587
|
|
|
6135
6588
|
// ../adapters/src/writers/generic/executor.ts
|
|
6136
|
-
async function executeWriters(writerConfigs, bundle, projectRoot) {
|
|
6589
|
+
async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
|
|
6137
6590
|
const seen = new Set;
|
|
6138
6591
|
const uniqueConfigs = [];
|
|
6139
6592
|
let deduplicatedCount = 0;
|
|
@@ -6150,7 +6603,8 @@ async function executeWriters(writerConfigs, bundle, projectRoot) {
|
|
|
6150
6603
|
for (const config of uniqueConfigs) {
|
|
6151
6604
|
const result = await config.writer.write(bundle, {
|
|
6152
6605
|
outputPath: config.outputPath,
|
|
6153
|
-
projectRoot
|
|
6606
|
+
projectRoot,
|
|
6607
|
+
...providerId ? { providerId } : {}
|
|
6154
6608
|
});
|
|
6155
6609
|
allFilesWritten.push(...result.filesWritten);
|
|
6156
6610
|
}
|
|
@@ -6161,23 +6615,23 @@ async function executeWriters(writerConfigs, bundle, projectRoot) {
|
|
|
6161
6615
|
}
|
|
6162
6616
|
// ../adapters/src/writers/generic/hooks.ts
|
|
6163
6617
|
init_src();
|
|
6164
|
-
import { existsSync as
|
|
6165
|
-
import { mkdir as mkdir2, readFile as
|
|
6166
|
-
import { dirname, join as
|
|
6618
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
6619
|
+
import { mkdir as mkdir2, readFile as readFile18, writeFile as writeFile10 } from "node:fs/promises";
|
|
6620
|
+
import { dirname, join as join12 } from "node:path";
|
|
6167
6621
|
var HooksWriter = {
|
|
6168
6622
|
id: "hooks",
|
|
6169
6623
|
async write(bundle, ctx) {
|
|
6170
6624
|
if (!bundle.hooks) {
|
|
6171
6625
|
return { filesWritten: [] };
|
|
6172
6626
|
}
|
|
6173
|
-
const settingsPath =
|
|
6627
|
+
const settingsPath = join12(ctx.projectRoot, ctx.outputPath);
|
|
6174
6628
|
const parentDir = dirname(settingsPath);
|
|
6175
6629
|
await mkdir2(parentDir, { recursive: true });
|
|
6176
6630
|
const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
|
|
6177
6631
|
let existingSettings = {};
|
|
6178
|
-
if (
|
|
6632
|
+
if (existsSync22(settingsPath)) {
|
|
6179
6633
|
try {
|
|
6180
|
-
const content = await
|
|
6634
|
+
const content = await readFile18(settingsPath, "utf-8");
|
|
6181
6635
|
existingSettings = JSON.parse(content);
|
|
6182
6636
|
} catch {
|
|
6183
6637
|
existingSettings = {};
|
|
@@ -6195,21 +6649,42 @@ var HooksWriter = {
|
|
|
6195
6649
|
}
|
|
6196
6650
|
};
|
|
6197
6651
|
// ../adapters/src/writers/generic/instructions-md.ts
|
|
6198
|
-
import { existsSync as
|
|
6199
|
-
import { mkdir as mkdir3, readFile as
|
|
6200
|
-
import { dirname as dirname2, join as
|
|
6652
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
6653
|
+
import { mkdir as mkdir3, readFile as readFile19, writeFile as writeFile11 } from "node:fs/promises";
|
|
6654
|
+
import { dirname as dirname2, join as join13 } from "node:path";
|
|
6655
|
+
|
|
6656
|
+
// ../adapters/src/writers/generic/omni-md.ts
|
|
6657
|
+
init_src();
|
|
6658
|
+
var PROVIDER_BLOCK_REGEX = /<provider\.([a-z-]+)>([\s\S]*?)<\/provider\.\1>/g;
|
|
6659
|
+
var PROVIDER_TAG_REGEX = /<\/?provider\.[a-z-]+>/;
|
|
6660
|
+
function renderOmniMdForProvider(content, providerId) {
|
|
6661
|
+
if (!providerId) {
|
|
6662
|
+
return content;
|
|
6663
|
+
}
|
|
6664
|
+
const rendered = content.replace(PROVIDER_BLOCK_REGEX, (_match, rawProvider, providerContent) => {
|
|
6665
|
+
const canonicalProvider = normalizeProviderId(rawProvider);
|
|
6666
|
+
return canonicalProvider === providerId ? providerContent : "";
|
|
6667
|
+
});
|
|
6668
|
+
const strayTag = rendered.match(PROVIDER_TAG_REGEX);
|
|
6669
|
+
if (strayTag) {
|
|
6670
|
+
throw new Error(`Invalid provider block syntax in OMNI.md near ${strayTag[0]}`);
|
|
6671
|
+
}
|
|
6672
|
+
return rendered;
|
|
6673
|
+
}
|
|
6674
|
+
|
|
6675
|
+
// ../adapters/src/writers/generic/instructions-md.ts
|
|
6201
6676
|
var InstructionsMdWriter = {
|
|
6202
6677
|
id: "instructions-md",
|
|
6203
6678
|
async write(bundle, ctx) {
|
|
6204
|
-
const outputFullPath =
|
|
6679
|
+
const outputFullPath = join13(ctx.projectRoot, ctx.outputPath);
|
|
6205
6680
|
const parentDir = dirname2(outputFullPath);
|
|
6206
6681
|
if (parentDir !== ctx.projectRoot) {
|
|
6207
6682
|
await mkdir3(parentDir, { recursive: true });
|
|
6208
6683
|
}
|
|
6209
|
-
const omniMdPath =
|
|
6684
|
+
const omniMdPath = join13(ctx.projectRoot, "OMNI.md");
|
|
6210
6685
|
let omniMdContent = "";
|
|
6211
|
-
if (
|
|
6212
|
-
omniMdContent = await
|
|
6686
|
+
if (existsSync23(omniMdPath)) {
|
|
6687
|
+
omniMdContent = renderOmniMdForProvider(await readFile19(omniMdPath, "utf-8"), ctx.providerId);
|
|
6213
6688
|
}
|
|
6214
6689
|
let content = omniMdContent;
|
|
6215
6690
|
if (bundle.instructionsContent) {
|
|
@@ -6226,17 +6701,17 @@ ${bundle.instructionsContent}
|
|
|
6226
6701
|
};
|
|
6227
6702
|
// ../adapters/src/writers/generic/skills.ts
|
|
6228
6703
|
import { mkdir as mkdir4, writeFile as writeFile12 } from "node:fs/promises";
|
|
6229
|
-
import { join as
|
|
6704
|
+
import { join as join14 } from "node:path";
|
|
6230
6705
|
var SkillsWriter = {
|
|
6231
6706
|
id: "skills",
|
|
6232
6707
|
async write(bundle, ctx) {
|
|
6233
|
-
const skillsDir =
|
|
6708
|
+
const skillsDir = join14(ctx.projectRoot, ctx.outputPath);
|
|
6234
6709
|
await mkdir4(skillsDir, { recursive: true });
|
|
6235
6710
|
const filesWritten = [];
|
|
6236
6711
|
for (const skill of bundle.skills) {
|
|
6237
|
-
const skillDir =
|
|
6712
|
+
const skillDir = join14(skillsDir, skill.name);
|
|
6238
6713
|
await mkdir4(skillDir, { recursive: true });
|
|
6239
|
-
const skillPath =
|
|
6714
|
+
const skillPath = join14(skillDir, "SKILL.md");
|
|
6240
6715
|
const content = `---
|
|
6241
6716
|
name: ${skill.name}
|
|
6242
6717
|
description: "${skill.description}"
|
|
@@ -6244,7 +6719,7 @@ description: "${skill.description}"
|
|
|
6244
6719
|
|
|
6245
6720
|
${skill.instructions}`;
|
|
6246
6721
|
await writeFile12(skillPath, content, "utf-8");
|
|
6247
|
-
filesWritten.push(
|
|
6722
|
+
filesWritten.push(join14(ctx.outputPath, skill.name, "SKILL.md"));
|
|
6248
6723
|
}
|
|
6249
6724
|
return {
|
|
6250
6725
|
filesWritten
|
|
@@ -6253,7 +6728,7 @@ ${skill.instructions}`;
|
|
|
6253
6728
|
};
|
|
6254
6729
|
// ../adapters/src/writers/generic/commands-as-skills.ts
|
|
6255
6730
|
import { mkdir as mkdir5, writeFile as writeFile13 } from "node:fs/promises";
|
|
6256
|
-
import { join as
|
|
6731
|
+
import { join as join15 } from "node:path";
|
|
6257
6732
|
function generateSkillFrontmatter(command) {
|
|
6258
6733
|
const lines = ["---"];
|
|
6259
6734
|
lines.push(`name: ${command.name}`);
|
|
@@ -6268,28 +6743,75 @@ function generateSkillFrontmatter(command) {
|
|
|
6268
6743
|
var CommandsAsSkillsWriter = {
|
|
6269
6744
|
id: "commands-as-skills",
|
|
6270
6745
|
async write(bundle, ctx) {
|
|
6271
|
-
const skillsDir =
|
|
6746
|
+
const skillsDir = join15(ctx.projectRoot, ctx.outputPath);
|
|
6272
6747
|
await mkdir5(skillsDir, { recursive: true });
|
|
6273
6748
|
const filesWritten = [];
|
|
6274
6749
|
for (const command of bundle.commands) {
|
|
6275
|
-
const commandSkillDir =
|
|
6750
|
+
const commandSkillDir = join15(skillsDir, command.name);
|
|
6276
6751
|
await mkdir5(commandSkillDir, { recursive: true });
|
|
6277
6752
|
const frontmatter = generateSkillFrontmatter(command);
|
|
6278
6753
|
const content = `${frontmatter}
|
|
6279
6754
|
|
|
6280
6755
|
${command.prompt}`;
|
|
6281
|
-
const skillPath =
|
|
6756
|
+
const skillPath = join15(commandSkillDir, "SKILL.md");
|
|
6282
6757
|
await writeFile13(skillPath, content, "utf-8");
|
|
6283
|
-
filesWritten.push(
|
|
6758
|
+
filesWritten.push(join15(ctx.outputPath, command.name, "SKILL.md"));
|
|
6284
6759
|
}
|
|
6285
6760
|
return {
|
|
6286
6761
|
filesWritten
|
|
6287
6762
|
};
|
|
6288
6763
|
}
|
|
6289
6764
|
};
|
|
6765
|
+
// ../adapters/src/provider-bundle.ts
|
|
6766
|
+
init_src();
|
|
6767
|
+
function capabilityAppliesToProvider(capability3, providerId) {
|
|
6768
|
+
const providers3 = capability3.config.capability.providers;
|
|
6769
|
+
if (!providers3) {
|
|
6770
|
+
return true;
|
|
6771
|
+
}
|
|
6772
|
+
return providers3[providerId] === true;
|
|
6773
|
+
}
|
|
6774
|
+
function generateInstructionsContent2(rules, _docs) {
|
|
6775
|
+
if (rules.length === 0) {
|
|
6776
|
+
return "";
|
|
6777
|
+
}
|
|
6778
|
+
let content = `## Rules
|
|
6779
|
+
|
|
6780
|
+
`;
|
|
6781
|
+
for (const rule of rules) {
|
|
6782
|
+
content += `${rule.content}
|
|
6783
|
+
|
|
6784
|
+
`;
|
|
6785
|
+
}
|
|
6786
|
+
return content.trimEnd();
|
|
6787
|
+
}
|
|
6788
|
+
function createProviderScopedBundle(bundle, providerId) {
|
|
6789
|
+
const capabilities2 = bundle.capabilities.filter((capability3) => capabilityAppliesToProvider(capability3, providerId));
|
|
6790
|
+
const capabilityIds = new Set(capabilities2.map((capability3) => capability3.id));
|
|
6791
|
+
const skills = bundle.skills.filter((skill) => capabilityIds.has(skill.capabilityId));
|
|
6792
|
+
const rules = bundle.rules.filter((rule) => capabilityIds.has(rule.capabilityId));
|
|
6793
|
+
const docs = bundle.docs.filter((doc) => capabilityIds.has(doc.capabilityId));
|
|
6794
|
+
const commands = bundle.commands.filter((command) => capabilityIds.has(command.capabilityId));
|
|
6795
|
+
const subagents = bundle.subagents.filter((subagent) => capabilityIds.has(subagent.capabilityId));
|
|
6796
|
+
const scopedBundle = {
|
|
6797
|
+
capabilities: capabilities2,
|
|
6798
|
+
skills,
|
|
6799
|
+
rules,
|
|
6800
|
+
docs,
|
|
6801
|
+
commands,
|
|
6802
|
+
subagents,
|
|
6803
|
+
instructionsContent: generateInstructionsContent2(rules, docs)
|
|
6804
|
+
};
|
|
6805
|
+
const mergedHooks = mergeHooksConfigs(capabilities2.flatMap((capability3) => capability3.hooks ? [capability3.hooks] : []));
|
|
6806
|
+
if (hasAnyHooks(mergedHooks)) {
|
|
6807
|
+
scopedBundle.hooks = mergedHooks;
|
|
6808
|
+
}
|
|
6809
|
+
return scopedBundle;
|
|
6810
|
+
}
|
|
6811
|
+
|
|
6290
6812
|
// ../adapters/src/writers/claude/agents.ts
|
|
6291
6813
|
import { mkdir as mkdir6, writeFile as writeFile14 } from "node:fs/promises";
|
|
6292
|
-
import { join as
|
|
6814
|
+
import { join as join16 } from "node:path";
|
|
6293
6815
|
function generateFrontmatter(agent) {
|
|
6294
6816
|
const lines = ["---"];
|
|
6295
6817
|
lines.push(`name: ${agent.name}`);
|
|
@@ -6316,7 +6838,7 @@ function generateFrontmatter(agent) {
|
|
|
6316
6838
|
var ClaudeAgentsWriter = {
|
|
6317
6839
|
id: "claude-agents",
|
|
6318
6840
|
async write(bundle, ctx) {
|
|
6319
|
-
const agentsDir =
|
|
6841
|
+
const agentsDir = join16(ctx.projectRoot, ctx.outputPath);
|
|
6320
6842
|
await mkdir6(agentsDir, { recursive: true });
|
|
6321
6843
|
const filesWritten = [];
|
|
6322
6844
|
for (const agent of bundle.subagents) {
|
|
@@ -6324,9 +6846,9 @@ var ClaudeAgentsWriter = {
|
|
|
6324
6846
|
const content = `${frontmatter}
|
|
6325
6847
|
|
|
6326
6848
|
${agent.systemPrompt}`;
|
|
6327
|
-
const agentPath =
|
|
6849
|
+
const agentPath = join16(agentsDir, `${agent.name}.md`);
|
|
6328
6850
|
await writeFile14(agentPath, content, "utf-8");
|
|
6329
|
-
filesWritten.push(
|
|
6851
|
+
filesWritten.push(join16(ctx.outputPath, `${agent.name}.md`));
|
|
6330
6852
|
}
|
|
6331
6853
|
return {
|
|
6332
6854
|
filesWritten
|
|
@@ -6351,7 +6873,9 @@ var claudeCodeAdapter = {
|
|
|
6351
6873
|
};
|
|
6352
6874
|
},
|
|
6353
6875
|
async sync(bundle, ctx) {
|
|
6354
|
-
const
|
|
6876
|
+
const providerId = "claude-code";
|
|
6877
|
+
const providerBundle = createProviderScopedBundle(bundle, providerId);
|
|
6878
|
+
const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
|
|
6355
6879
|
return {
|
|
6356
6880
|
filesWritten: result.filesWritten,
|
|
6357
6881
|
filesDeleted: []
|
|
@@ -6360,12 +6884,12 @@ var claudeCodeAdapter = {
|
|
|
6360
6884
|
};
|
|
6361
6885
|
// ../adapters/src/codex/index.ts
|
|
6362
6886
|
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
6363
|
-
import { join as
|
|
6887
|
+
import { join as join18 } from "node:path";
|
|
6364
6888
|
|
|
6365
6889
|
// ../adapters/src/writers/codex/toml.ts
|
|
6366
6890
|
init_dist();
|
|
6367
6891
|
import { mkdir as mkdir7, writeFile as writeFile15 } from "node:fs/promises";
|
|
6368
|
-
import { dirname as dirname3, join as
|
|
6892
|
+
import { dirname as dirname3, join as join17 } from "node:path";
|
|
6369
6893
|
var FILE_HEADER = `# Generated by OmniDev - DO NOT EDIT
|
|
6370
6894
|
# Run \`omnidev sync\` to regenerate
|
|
6371
6895
|
|
|
@@ -6416,7 +6940,7 @@ var CodexTomlWriter = {
|
|
|
6416
6940
|
if (mcps.size === 0) {
|
|
6417
6941
|
return { filesWritten: [] };
|
|
6418
6942
|
}
|
|
6419
|
-
const configPath =
|
|
6943
|
+
const configPath = join17(ctx.projectRoot, ctx.outputPath);
|
|
6420
6944
|
const parentDir = dirname3(configPath);
|
|
6421
6945
|
await mkdir7(parentDir, { recursive: true });
|
|
6422
6946
|
const mcpServers = {};
|
|
@@ -6450,7 +6974,7 @@ var codexAdapter = {
|
|
|
6450
6974
|
{ writer: CodexTomlWriter, outputPath: ".codex/config.toml" }
|
|
6451
6975
|
],
|
|
6452
6976
|
async init(ctx) {
|
|
6453
|
-
const codexDir =
|
|
6977
|
+
const codexDir = join18(ctx.projectRoot, ".codex");
|
|
6454
6978
|
mkdirSync6(codexDir, { recursive: true });
|
|
6455
6979
|
return {
|
|
6456
6980
|
filesCreated: [".codex/"],
|
|
@@ -6458,7 +6982,9 @@ var codexAdapter = {
|
|
|
6458
6982
|
};
|
|
6459
6983
|
},
|
|
6460
6984
|
async sync(bundle, ctx) {
|
|
6461
|
-
const
|
|
6985
|
+
const providerId = "codex";
|
|
6986
|
+
const providerBundle = createProviderScopedBundle(bundle, providerId);
|
|
6987
|
+
const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
|
|
6462
6988
|
return {
|
|
6463
6989
|
filesWritten: result.filesWritten,
|
|
6464
6990
|
filesDeleted: []
|
|
@@ -6467,11 +6993,11 @@ var codexAdapter = {
|
|
|
6467
6993
|
};
|
|
6468
6994
|
// ../adapters/src/cursor/index.ts
|
|
6469
6995
|
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
6470
|
-
import { join as
|
|
6996
|
+
import { join as join23 } from "node:path";
|
|
6471
6997
|
|
|
6472
6998
|
// ../adapters/src/writers/cursor/agents.ts
|
|
6473
6999
|
import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
|
|
6474
|
-
import { join as
|
|
7000
|
+
import { join as join19 } from "node:path";
|
|
6475
7001
|
function mapModelToCursor(model) {
|
|
6476
7002
|
if (!model || model === "inherit")
|
|
6477
7003
|
return "inherit";
|
|
@@ -6503,7 +7029,7 @@ function generateFrontmatter2(agent) {
|
|
|
6503
7029
|
var CursorAgentsWriter = {
|
|
6504
7030
|
id: "cursor-agents",
|
|
6505
7031
|
async write(bundle, ctx) {
|
|
6506
|
-
const agentsDir =
|
|
7032
|
+
const agentsDir = join19(ctx.projectRoot, ctx.outputPath);
|
|
6507
7033
|
await mkdir8(agentsDir, { recursive: true });
|
|
6508
7034
|
const filesWritten = [];
|
|
6509
7035
|
for (const agent of bundle.subagents) {
|
|
@@ -6511,9 +7037,9 @@ var CursorAgentsWriter = {
|
|
|
6511
7037
|
const content = `${frontmatter}
|
|
6512
7038
|
|
|
6513
7039
|
${agent.systemPrompt}`;
|
|
6514
|
-
const agentPath =
|
|
7040
|
+
const agentPath = join19(agentsDir, `${agent.name}.md`);
|
|
6515
7041
|
await writeFile16(agentPath, content, "utf-8");
|
|
6516
|
-
filesWritten.push(
|
|
7042
|
+
filesWritten.push(join19(ctx.outputPath, `${agent.name}.md`));
|
|
6517
7043
|
}
|
|
6518
7044
|
return {
|
|
6519
7045
|
filesWritten
|
|
@@ -6522,11 +7048,11 @@ ${agent.systemPrompt}`;
|
|
|
6522
7048
|
};
|
|
6523
7049
|
// ../adapters/src/writers/cursor/commands.ts
|
|
6524
7050
|
import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
|
|
6525
|
-
import { join as
|
|
7051
|
+
import { join as join20 } from "node:path";
|
|
6526
7052
|
var CursorCommandsWriter = {
|
|
6527
7053
|
id: "cursor-commands",
|
|
6528
7054
|
async write(bundle, ctx) {
|
|
6529
|
-
const commandsDir =
|
|
7055
|
+
const commandsDir = join20(ctx.projectRoot, ctx.outputPath);
|
|
6530
7056
|
await mkdir9(commandsDir, { recursive: true });
|
|
6531
7057
|
const filesWritten = [];
|
|
6532
7058
|
for (const command of bundle.commands) {
|
|
@@ -6535,9 +7061,9 @@ var CursorCommandsWriter = {
|
|
|
6535
7061
|
${command.description}
|
|
6536
7062
|
|
|
6537
7063
|
${command.prompt}`;
|
|
6538
|
-
const commandPath =
|
|
7064
|
+
const commandPath = join20(commandsDir, `${command.name}.md`);
|
|
6539
7065
|
await writeFile17(commandPath, content, "utf-8");
|
|
6540
|
-
filesWritten.push(
|
|
7066
|
+
filesWritten.push(join20(ctx.outputPath, `${command.name}.md`));
|
|
6541
7067
|
}
|
|
6542
7068
|
return {
|
|
6543
7069
|
filesWritten
|
|
@@ -6546,7 +7072,7 @@ ${command.prompt}`;
|
|
|
6546
7072
|
};
|
|
6547
7073
|
// ../adapters/src/writers/cursor/mcp-json.ts
|
|
6548
7074
|
import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
|
|
6549
|
-
import { dirname as dirname4, join as
|
|
7075
|
+
import { dirname as dirname4, join as join21 } from "node:path";
|
|
6550
7076
|
function buildCursorMcpConfig(mcp) {
|
|
6551
7077
|
const transport = mcp.transport ?? "stdio";
|
|
6552
7078
|
if (transport === "http" || transport === "sse") {
|
|
@@ -6591,7 +7117,7 @@ var CursorMcpJsonWriter = {
|
|
|
6591
7117
|
if (mcps.size === 0) {
|
|
6592
7118
|
return { filesWritten: [] };
|
|
6593
7119
|
}
|
|
6594
|
-
const configPath =
|
|
7120
|
+
const configPath = join21(ctx.projectRoot, ctx.outputPath);
|
|
6595
7121
|
const parentDir = dirname4(configPath);
|
|
6596
7122
|
await mkdir10(parentDir, { recursive: true });
|
|
6597
7123
|
const mcpServers = {};
|
|
@@ -6616,17 +7142,17 @@ var CursorMcpJsonWriter = {
|
|
|
6616
7142
|
};
|
|
6617
7143
|
// ../adapters/src/writers/cursor/rules.ts
|
|
6618
7144
|
import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
|
|
6619
|
-
import { join as
|
|
7145
|
+
import { join as join22 } from "node:path";
|
|
6620
7146
|
var CursorRulesWriter = {
|
|
6621
7147
|
id: "cursor-rules",
|
|
6622
7148
|
async write(bundle, ctx) {
|
|
6623
|
-
const rulesDir =
|
|
7149
|
+
const rulesDir = join22(ctx.projectRoot, ctx.outputPath);
|
|
6624
7150
|
await mkdir11(rulesDir, { recursive: true });
|
|
6625
7151
|
const filesWritten = [];
|
|
6626
7152
|
for (const rule of bundle.rules) {
|
|
6627
|
-
const rulePath =
|
|
7153
|
+
const rulePath = join22(rulesDir, `omnidev-${rule.name}.mdc`);
|
|
6628
7154
|
await writeFile19(rulePath, rule.content, "utf-8");
|
|
6629
|
-
filesWritten.push(
|
|
7155
|
+
filesWritten.push(join22(ctx.outputPath, `omnidev-${rule.name}.mdc`));
|
|
6630
7156
|
}
|
|
6631
7157
|
return {
|
|
6632
7158
|
filesWritten
|
|
@@ -6646,7 +7172,7 @@ var cursorAdapter = {
|
|
|
6646
7172
|
{ writer: CursorMcpJsonWriter, outputPath: ".cursor/mcp.json" }
|
|
6647
7173
|
],
|
|
6648
7174
|
async init(ctx) {
|
|
6649
|
-
const rulesDir =
|
|
7175
|
+
const rulesDir = join23(ctx.projectRoot, ".cursor", "rules");
|
|
6650
7176
|
mkdirSync7(rulesDir, { recursive: true });
|
|
6651
7177
|
return {
|
|
6652
7178
|
filesCreated: [".cursor/rules/"],
|
|
@@ -6654,20 +7180,29 @@ var cursorAdapter = {
|
|
|
6654
7180
|
};
|
|
6655
7181
|
},
|
|
6656
7182
|
async sync(bundle, ctx) {
|
|
6657
|
-
const
|
|
7183
|
+
const cursorProviderId = "cursor";
|
|
7184
|
+
const instructionsProviderId = "claude-code";
|
|
7185
|
+
const instructionsWriters = this.writers.filter((config3) => config3.writer.id === "instructions-md");
|
|
7186
|
+
const cursorWriters = this.writers.filter((config3) => config3.writer.id !== "instructions-md");
|
|
7187
|
+
const instructionsBundle = createProviderScopedBundle(bundle, instructionsProviderId);
|
|
7188
|
+
const cursorBundle = createProviderScopedBundle(bundle, cursorProviderId);
|
|
7189
|
+
const instructionsResult = await executeWriters(instructionsWriters, instructionsBundle, ctx.projectRoot, instructionsProviderId);
|
|
7190
|
+
const cursorResult = await executeWriters(cursorWriters, cursorBundle, ctx.projectRoot, cursorProviderId);
|
|
6658
7191
|
return {
|
|
6659
|
-
filesWritten:
|
|
7192
|
+
filesWritten: [
|
|
7193
|
+
...new Set([...instructionsResult.filesWritten, ...cursorResult.filesWritten])
|
|
7194
|
+
],
|
|
6660
7195
|
filesDeleted: []
|
|
6661
7196
|
};
|
|
6662
7197
|
}
|
|
6663
7198
|
};
|
|
6664
7199
|
// ../adapters/src/opencode/index.ts
|
|
6665
7200
|
import { mkdirSync as mkdirSync8 } from "node:fs";
|
|
6666
|
-
import { join as
|
|
7201
|
+
import { join as join26 } from "node:path";
|
|
6667
7202
|
|
|
6668
7203
|
// ../adapters/src/writers/opencode/agents.ts
|
|
6669
7204
|
import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
|
|
6670
|
-
import { join as
|
|
7205
|
+
import { join as join24 } from "node:path";
|
|
6671
7206
|
function mapModelToOpenCode(model) {
|
|
6672
7207
|
if (!model || model === "inherit")
|
|
6673
7208
|
return;
|
|
@@ -6745,7 +7280,7 @@ function generateFrontmatter3(agent) {
|
|
|
6745
7280
|
var OpenCodeAgentsWriter = {
|
|
6746
7281
|
id: "opencode-agents",
|
|
6747
7282
|
async write(bundle, ctx) {
|
|
6748
|
-
const agentsDir =
|
|
7283
|
+
const agentsDir = join24(ctx.projectRoot, ctx.outputPath);
|
|
6749
7284
|
await mkdir12(agentsDir, { recursive: true });
|
|
6750
7285
|
const filesWritten = [];
|
|
6751
7286
|
for (const agent of bundle.subagents) {
|
|
@@ -6753,9 +7288,9 @@ var OpenCodeAgentsWriter = {
|
|
|
6753
7288
|
const content = `${frontmatter}
|
|
6754
7289
|
|
|
6755
7290
|
${agent.systemPrompt}`;
|
|
6756
|
-
const agentPath =
|
|
7291
|
+
const agentPath = join24(agentsDir, `${agent.name}.md`);
|
|
6757
7292
|
await writeFile20(agentPath, content, "utf-8");
|
|
6758
|
-
filesWritten.push(
|
|
7293
|
+
filesWritten.push(join24(ctx.outputPath, `${agent.name}.md`));
|
|
6759
7294
|
}
|
|
6760
7295
|
return {
|
|
6761
7296
|
filesWritten
|
|
@@ -6764,7 +7299,7 @@ ${agent.systemPrompt}`;
|
|
|
6764
7299
|
};
|
|
6765
7300
|
// ../adapters/src/writers/opencode/commands.ts
|
|
6766
7301
|
import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
|
|
6767
|
-
import { join as
|
|
7302
|
+
import { join as join25 } from "node:path";
|
|
6768
7303
|
function generateFrontmatter4(command) {
|
|
6769
7304
|
const lines = ["---"];
|
|
6770
7305
|
lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
|
|
@@ -6781,7 +7316,7 @@ function generateFrontmatter4(command) {
|
|
|
6781
7316
|
var OpenCodeCommandsWriter = {
|
|
6782
7317
|
id: "opencode-commands",
|
|
6783
7318
|
async write(bundle, ctx) {
|
|
6784
|
-
const commandsDir =
|
|
7319
|
+
const commandsDir = join25(ctx.projectRoot, ctx.outputPath);
|
|
6785
7320
|
await mkdir13(commandsDir, { recursive: true });
|
|
6786
7321
|
const filesWritten = [];
|
|
6787
7322
|
for (const command of bundle.commands) {
|
|
@@ -6789,9 +7324,9 @@ var OpenCodeCommandsWriter = {
|
|
|
6789
7324
|
const content = `${frontmatter}
|
|
6790
7325
|
|
|
6791
7326
|
${command.prompt}`;
|
|
6792
|
-
const commandPath =
|
|
7327
|
+
const commandPath = join25(commandsDir, `${command.name}.md`);
|
|
6793
7328
|
await writeFile21(commandPath, content, "utf-8");
|
|
6794
|
-
filesWritten.push(
|
|
7329
|
+
filesWritten.push(join25(ctx.outputPath, `${command.name}.md`));
|
|
6795
7330
|
}
|
|
6796
7331
|
return {
|
|
6797
7332
|
filesWritten
|
|
@@ -6809,7 +7344,7 @@ var opencodeAdapter = {
|
|
|
6809
7344
|
{ writer: OpenCodeCommandsWriter, outputPath: ".opencode/commands/" }
|
|
6810
7345
|
],
|
|
6811
7346
|
async init(ctx) {
|
|
6812
|
-
const opencodeDir =
|
|
7347
|
+
const opencodeDir = join26(ctx.projectRoot, ".opencode");
|
|
6813
7348
|
mkdirSync8(opencodeDir, { recursive: true });
|
|
6814
7349
|
return {
|
|
6815
7350
|
filesCreated: [".opencode/"],
|
|
@@ -6817,7 +7352,9 @@ var opencodeAdapter = {
|
|
|
6817
7352
|
};
|
|
6818
7353
|
},
|
|
6819
7354
|
async sync(bundle, ctx) {
|
|
6820
|
-
const
|
|
7355
|
+
const providerId = "opencode";
|
|
7356
|
+
const providerBundle = createProviderScopedBundle(bundle, providerId);
|
|
7357
|
+
const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
|
|
6821
7358
|
return {
|
|
6822
7359
|
filesWritten: result.filesWritten,
|
|
6823
7360
|
filesDeleted: []
|
|
@@ -6861,7 +7398,7 @@ async function inferCapabilityId(source, sourceType) {
|
|
|
6861
7398
|
}
|
|
6862
7399
|
async function runAddCap(flags, name) {
|
|
6863
7400
|
try {
|
|
6864
|
-
if (!
|
|
7401
|
+
if (!existsSync24("omni.toml")) {
|
|
6865
7402
|
console.log("✗ No config file found");
|
|
6866
7403
|
console.log(" Run: omnidev init");
|
|
6867
7404
|
process.exit(1);
|
|
@@ -6884,7 +7421,7 @@ async function runAddCap(flags, name) {
|
|
|
6884
7421
|
sourceType = "local";
|
|
6885
7422
|
const localPath = flags.local.startsWith("file://") ? flags.local.slice(7) : flags.local;
|
|
6886
7423
|
source = `file://${localPath}`;
|
|
6887
|
-
if (!
|
|
7424
|
+
if (!existsSync24(localPath)) {
|
|
6888
7425
|
console.error(`✗ Local path not found: ${localPath}`);
|
|
6889
7426
|
process.exit(1);
|
|
6890
7427
|
}
|
|
@@ -6976,7 +7513,7 @@ async function runAddCap(flags, name) {
|
|
|
6976
7513
|
}
|
|
6977
7514
|
async function runAddMcp(flags, name) {
|
|
6978
7515
|
try {
|
|
6979
|
-
if (!
|
|
7516
|
+
if (!existsSync24("omni.toml")) {
|
|
6980
7517
|
console.log("✗ No config file found");
|
|
6981
7518
|
console.log(" Run: omnidev init");
|
|
6982
7519
|
process.exit(1);
|
|
@@ -7263,9 +7800,9 @@ var addRoutes = buildRouteMap({
|
|
|
7263
7800
|
});
|
|
7264
7801
|
|
|
7265
7802
|
// src/commands/capability.ts
|
|
7266
|
-
import { existsSync as
|
|
7803
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync9 } from "node:fs";
|
|
7267
7804
|
import { writeFile as writeFile22 } from "node:fs/promises";
|
|
7268
|
-
import { join as
|
|
7805
|
+
import { join as join27 } from "node:path";
|
|
7269
7806
|
import { input } from "@inquirer/prompts";
|
|
7270
7807
|
init_src();
|
|
7271
7808
|
import { buildCommand as buildCommand2, buildRouteMap as buildRouteMap2 } from "@stricli/core";
|
|
@@ -7443,14 +7980,18 @@ export default {
|
|
|
7443
7980
|
} satisfies CapabilityExport;
|
|
7444
7981
|
`;
|
|
7445
7982
|
}
|
|
7446
|
-
function generateGitignore() {
|
|
7447
|
-
|
|
7448
|
-
|
|
7983
|
+
function generateGitignore(programmatic) {
|
|
7984
|
+
const lines = [".env"];
|
|
7985
|
+
if (programmatic) {
|
|
7986
|
+
lines.push("dist/", "node_modules/");
|
|
7987
|
+
}
|
|
7988
|
+
return `${lines.join(`
|
|
7989
|
+
`)}
|
|
7449
7990
|
`;
|
|
7450
7991
|
}
|
|
7451
7992
|
async function runCapabilityNew(flags, capabilityId) {
|
|
7452
7993
|
try {
|
|
7453
|
-
if (!
|
|
7994
|
+
if (!existsSync25(".omni")) {
|
|
7454
7995
|
console.error("✗ OmniDev is not initialized in this directory.");
|
|
7455
7996
|
console.log("");
|
|
7456
7997
|
console.log(" Run: omnidev init");
|
|
@@ -7474,28 +8015,28 @@ async function runCapabilityNew(flags, capabilityId) {
|
|
|
7474
8015
|
default: defaultPath
|
|
7475
8016
|
});
|
|
7476
8017
|
}
|
|
7477
|
-
if (
|
|
8018
|
+
if (existsSync25(capabilityDir)) {
|
|
7478
8019
|
console.error(`✗ Directory already exists at ${capabilityDir}`);
|
|
7479
8020
|
process.exit(1);
|
|
7480
8021
|
}
|
|
7481
8022
|
const name = toTitleCase(id);
|
|
7482
8023
|
mkdirSync9(capabilityDir, { recursive: true });
|
|
7483
8024
|
const capabilityToml = generateCapabilityToml2({ id, name });
|
|
7484
|
-
await writeFile22(
|
|
7485
|
-
const skillDir =
|
|
8025
|
+
await writeFile22(join27(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
|
|
8026
|
+
const skillDir = join27(capabilityDir, "skills", "getting-started");
|
|
7486
8027
|
mkdirSync9(skillDir, { recursive: true });
|
|
7487
|
-
await writeFile22(
|
|
7488
|
-
const rulesDir =
|
|
8028
|
+
await writeFile22(join27(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
|
|
8029
|
+
const rulesDir = join27(capabilityDir, "rules");
|
|
7489
8030
|
mkdirSync9(rulesDir, { recursive: true });
|
|
7490
|
-
await writeFile22(
|
|
7491
|
-
const hooksDir =
|
|
8031
|
+
await writeFile22(join27(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
|
|
8032
|
+
const hooksDir = join27(capabilityDir, "hooks");
|
|
7492
8033
|
mkdirSync9(hooksDir, { recursive: true });
|
|
7493
|
-
await writeFile22(
|
|
7494
|
-
await writeFile22(
|
|
8034
|
+
await writeFile22(join27(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
|
|
8035
|
+
await writeFile22(join27(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
|
|
8036
|
+
await writeFile22(join27(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
|
|
7495
8037
|
if (flags.programmatic) {
|
|
7496
|
-
await writeFile22(
|
|
7497
|
-
await writeFile22(
|
|
7498
|
-
await writeFile22(join25(capabilityDir, ".gitignore"), generateGitignore(), "utf-8");
|
|
8038
|
+
await writeFile22(join27(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
|
|
8039
|
+
await writeFile22(join27(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
|
|
7499
8040
|
}
|
|
7500
8041
|
console.log(`✓ Created capability: ${name}`);
|
|
7501
8042
|
console.log(` Location: ${capabilityDir}`);
|
|
@@ -7506,10 +8047,10 @@ async function runCapabilityNew(flags, capabilityId) {
|
|
|
7506
8047
|
console.log(" - rules/coding-standards.md");
|
|
7507
8048
|
console.log(" - hooks/hooks.toml");
|
|
7508
8049
|
console.log(" - hooks/example-hook.sh");
|
|
8050
|
+
console.log(" - .gitignore");
|
|
7509
8051
|
if (flags.programmatic) {
|
|
7510
8052
|
console.log(" - package.json");
|
|
7511
8053
|
console.log(" - index.ts");
|
|
7512
|
-
console.log(" - .gitignore");
|
|
7513
8054
|
}
|
|
7514
8055
|
console.log("");
|
|
7515
8056
|
if (flags.programmatic) {
|
|
@@ -7651,9 +8192,9 @@ var capabilityRoutes = buildRouteMap2({
|
|
|
7651
8192
|
});
|
|
7652
8193
|
|
|
7653
8194
|
// src/commands/doctor.ts
|
|
7654
|
-
import { existsSync as
|
|
8195
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
7655
8196
|
import { execFile } from "node:child_process";
|
|
7656
|
-
import { readFile as
|
|
8197
|
+
import { readFile as readFile20 } from "node:fs/promises";
|
|
7657
8198
|
import { promisify } from "node:util";
|
|
7658
8199
|
import { buildCommand as buildCommand3 } from "@stricli/core";
|
|
7659
8200
|
var doctorCommand = buildCommand3({
|
|
@@ -7698,50 +8239,52 @@ async function runDoctor() {
|
|
|
7698
8239
|
async function checkPackageManager() {
|
|
7699
8240
|
const execFileAsync = promisify(execFile);
|
|
7700
8241
|
try {
|
|
7701
|
-
const { stdout } = await execFileAsync("
|
|
7702
|
-
const
|
|
7703
|
-
|
|
7704
|
-
|
|
8242
|
+
const { stdout: npmStdout } = await execFileAsync("npm", ["--version"]);
|
|
8243
|
+
const npmVersion = npmStdout.trim();
|
|
8244
|
+
try {
|
|
8245
|
+
const { stdout: bunStdout } = await execFileAsync("bun", ["--version"]);
|
|
8246
|
+
const bunVersion = bunStdout.trim();
|
|
8247
|
+
const firstPart = bunVersion.split(".")[0];
|
|
8248
|
+
if (!firstPart) {
|
|
8249
|
+
return {
|
|
8250
|
+
name: "Package Manager",
|
|
8251
|
+
passed: false,
|
|
8252
|
+
message: `Invalid Bun version format: ${bunVersion}`,
|
|
8253
|
+
fix: "Reinstall Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8254
|
+
};
|
|
8255
|
+
}
|
|
8256
|
+
const major = Number.parseInt(firstPart, 10);
|
|
8257
|
+
if (major < 1) {
|
|
8258
|
+
return {
|
|
8259
|
+
name: "Package Manager",
|
|
8260
|
+
passed: false,
|
|
8261
|
+
message: `npm v${npmVersion}; bun v${bunVersion}`,
|
|
8262
|
+
fix: "Upgrade Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8263
|
+
};
|
|
8264
|
+
}
|
|
7705
8265
|
return {
|
|
7706
8266
|
name: "Package Manager",
|
|
7707
|
-
passed:
|
|
7708
|
-
message: `
|
|
7709
|
-
fix: "Reinstall Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8267
|
+
passed: true,
|
|
8268
|
+
message: `npm v${npmVersion}; bun v${bunVersion}`
|
|
7710
8269
|
};
|
|
7711
|
-
}
|
|
7712
|
-
const major = Number.parseInt(firstPart, 10);
|
|
7713
|
-
if (major < 1) {
|
|
8270
|
+
} catch {
|
|
7714
8271
|
return {
|
|
7715
8272
|
name: "Package Manager",
|
|
7716
|
-
passed:
|
|
7717
|
-
message: `
|
|
7718
|
-
fix: "Upgrade Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8273
|
+
passed: true,
|
|
8274
|
+
message: `npm v${npmVersion}`
|
|
7719
8275
|
};
|
|
7720
8276
|
}
|
|
7721
|
-
return {
|
|
7722
|
-
name: "Package Manager",
|
|
7723
|
-
passed: true,
|
|
7724
|
-
message: `bun v${version2}`
|
|
7725
|
-
};
|
|
7726
|
-
} catch {}
|
|
7727
|
-
try {
|
|
7728
|
-
const { stdout } = await execFileAsync("npm", ["--version"]);
|
|
7729
|
-
return {
|
|
7730
|
-
name: "Package Manager",
|
|
7731
|
-
passed: true,
|
|
7732
|
-
message: `npm v${stdout.trim()}`
|
|
7733
|
-
};
|
|
7734
8277
|
} catch {
|
|
7735
8278
|
return {
|
|
7736
8279
|
name: "Package Manager",
|
|
7737
8280
|
passed: false,
|
|
7738
|
-
message: "
|
|
7739
|
-
fix: "Install
|
|
8281
|
+
message: "npm is not installed",
|
|
8282
|
+
fix: "Install Node.js and npm: https://nodejs.org/"
|
|
7740
8283
|
};
|
|
7741
8284
|
}
|
|
7742
8285
|
}
|
|
7743
8286
|
async function checkOmniLocalDir() {
|
|
7744
|
-
const exists =
|
|
8287
|
+
const exists = existsSync26(".omni");
|
|
7745
8288
|
if (!exists) {
|
|
7746
8289
|
return {
|
|
7747
8290
|
name: ".omni/ directory",
|
|
@@ -7758,7 +8301,7 @@ async function checkOmniLocalDir() {
|
|
|
7758
8301
|
}
|
|
7759
8302
|
async function checkConfig() {
|
|
7760
8303
|
const configPath = "omni.toml";
|
|
7761
|
-
if (!
|
|
8304
|
+
if (!existsSync26(configPath)) {
|
|
7762
8305
|
return {
|
|
7763
8306
|
name: "Configuration",
|
|
7764
8307
|
passed: false,
|
|
@@ -7785,7 +8328,7 @@ async function checkConfig() {
|
|
|
7785
8328
|
}
|
|
7786
8329
|
async function checkRootGitignore() {
|
|
7787
8330
|
const gitignorePath = ".gitignore";
|
|
7788
|
-
if (!
|
|
8331
|
+
if (!existsSync26(gitignorePath)) {
|
|
7789
8332
|
return {
|
|
7790
8333
|
name: "Root .gitignore",
|
|
7791
8334
|
passed: false,
|
|
@@ -7793,7 +8336,7 @@ async function checkRootGitignore() {
|
|
|
7793
8336
|
fix: "Run: omnidev init"
|
|
7794
8337
|
};
|
|
7795
8338
|
}
|
|
7796
|
-
const content = await
|
|
8339
|
+
const content = await readFile20(gitignorePath, "utf-8");
|
|
7797
8340
|
const lines = content.split(`
|
|
7798
8341
|
`).map((line) => line.trim());
|
|
7799
8342
|
const hasOmniDir = lines.includes(".omni/");
|
|
@@ -7819,7 +8362,7 @@ async function checkRootGitignore() {
|
|
|
7819
8362
|
}
|
|
7820
8363
|
async function checkCapabilitiesDir() {
|
|
7821
8364
|
const capabilitiesDirPath = ".omni/capabilities";
|
|
7822
|
-
if (!
|
|
8365
|
+
if (!existsSync26(capabilitiesDirPath)) {
|
|
7823
8366
|
return {
|
|
7824
8367
|
name: "Capabilities Directory",
|
|
7825
8368
|
passed: true,
|
|
@@ -7835,8 +8378,8 @@ async function checkCapabilitiesDir() {
|
|
|
7835
8378
|
|
|
7836
8379
|
// src/commands/init.ts
|
|
7837
8380
|
import { exec } from "node:child_process";
|
|
7838
|
-
import { existsSync as
|
|
7839
|
-
import { readFile as
|
|
8381
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync10 } from "node:fs";
|
|
8382
|
+
import { readFile as readFile21, writeFile as writeFile23 } from "node:fs/promises";
|
|
7840
8383
|
import { promisify as promisify2 } from "node:util";
|
|
7841
8384
|
init_src();
|
|
7842
8385
|
import { buildCommand as buildCommand4 } from "@stricli/core";
|
|
@@ -7849,8 +8392,8 @@ var PROVIDER_GITIGNORE_FILES = {
|
|
|
7849
8392
|
codex: ["AGENTS.md", ".codex/"],
|
|
7850
8393
|
opencode: [".opencode/"]
|
|
7851
8394
|
};
|
|
7852
|
-
function getProviderGitignoreFiles(
|
|
7853
|
-
return
|
|
8395
|
+
function getProviderGitignoreFiles(providers3) {
|
|
8396
|
+
return providers3.flatMap((p) => PROVIDER_GITIGNORE_FILES[p] ?? []);
|
|
7854
8397
|
}
|
|
7855
8398
|
async function promptForProviders() {
|
|
7856
8399
|
const answers = await checkbox({
|
|
@@ -7905,7 +8448,7 @@ async function runInit(_flags, providerArg) {
|
|
|
7905
8448
|
}
|
|
7906
8449
|
}
|
|
7907
8450
|
await writeEnabledProviders(providerIds);
|
|
7908
|
-
if (!
|
|
8451
|
+
if (!existsSync27("omni.toml")) {
|
|
7909
8452
|
await writeConfig({
|
|
7910
8453
|
profiles: {
|
|
7911
8454
|
default: {
|
|
@@ -7921,7 +8464,7 @@ async function runInit(_flags, providerArg) {
|
|
|
7921
8464
|
});
|
|
7922
8465
|
await setActiveProfile("default");
|
|
7923
8466
|
}
|
|
7924
|
-
if (!
|
|
8467
|
+
if (!existsSync27("OMNI.md")) {
|
|
7925
8468
|
await writeFile23("OMNI.md", generateOmniMdTemplate(), "utf-8");
|
|
7926
8469
|
}
|
|
7927
8470
|
const config3 = await loadConfig();
|
|
@@ -7999,8 +8542,8 @@ async function addProviderFilesToGitignore(entries) {
|
|
|
7999
8542
|
async function addToGitignore(entriesToAdd, sectionHeader) {
|
|
8000
8543
|
const gitignorePath = ".gitignore";
|
|
8001
8544
|
let content = "";
|
|
8002
|
-
if (
|
|
8003
|
-
content = await
|
|
8545
|
+
if (existsSync27(gitignorePath)) {
|
|
8546
|
+
content = await readFile21(gitignorePath, "utf-8");
|
|
8004
8547
|
}
|
|
8005
8548
|
const lines = content.split(`
|
|
8006
8549
|
`);
|
|
@@ -8031,7 +8574,7 @@ async function getTrackedProviderFiles(files) {
|
|
|
8031
8574
|
}
|
|
8032
8575
|
|
|
8033
8576
|
// src/commands/profile.ts
|
|
8034
|
-
import { existsSync as
|
|
8577
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
8035
8578
|
init_src();
|
|
8036
8579
|
import { buildCommand as buildCommand5, buildRouteMap as buildRouteMap3 } from "@stricli/core";
|
|
8037
8580
|
var listCommand2 = buildCommand5({
|
|
@@ -8075,7 +8618,7 @@ var profileRoutes = buildRouteMap3({
|
|
|
8075
8618
|
});
|
|
8076
8619
|
async function runProfileList() {
|
|
8077
8620
|
try {
|
|
8078
|
-
if (!
|
|
8621
|
+
if (!existsSync28("omni.toml")) {
|
|
8079
8622
|
console.log("✗ No config file found");
|
|
8080
8623
|
console.log(" Run: omnidev init");
|
|
8081
8624
|
process.exit(1);
|
|
@@ -8115,7 +8658,7 @@ async function runProfileList() {
|
|
|
8115
8658
|
}
|
|
8116
8659
|
async function runProfileSet(profileName) {
|
|
8117
8660
|
try {
|
|
8118
|
-
if (!
|
|
8661
|
+
if (!existsSync28("omni.toml")) {
|
|
8119
8662
|
console.log("✗ No config file found");
|
|
8120
8663
|
console.log(" Run: omnidev init");
|
|
8121
8664
|
process.exit(1);
|
|
@@ -8264,7 +8807,7 @@ var providerRoutes = buildRouteMap4({
|
|
|
8264
8807
|
|
|
8265
8808
|
// src/commands/security.ts
|
|
8266
8809
|
init_src();
|
|
8267
|
-
import { existsSync as
|
|
8810
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
8268
8811
|
import { buildCommand as buildCommand7, buildRouteMap as buildRouteMap5 } from "@stricli/core";
|
|
8269
8812
|
var VALID_FINDING_TYPES = [
|
|
8270
8813
|
"unicode_bidi",
|
|
@@ -8303,7 +8846,9 @@ async function filterAllowedFindings(summary, options = {}) {
|
|
|
8303
8846
|
symlink_escape: 0,
|
|
8304
8847
|
symlink_absolute: 0,
|
|
8305
8848
|
suspicious_script: 0,
|
|
8306
|
-
binary_file: 0
|
|
8849
|
+
binary_file: 0,
|
|
8850
|
+
hidden_command: 0,
|
|
8851
|
+
network_request: 0
|
|
8307
8852
|
};
|
|
8308
8853
|
const findingsBySeverity = {
|
|
8309
8854
|
low: 0,
|
|
@@ -8381,7 +8926,7 @@ function formatFindingsWithHints(summary) {
|
|
|
8381
8926
|
}
|
|
8382
8927
|
async function runSecurityIssues(flags = {}) {
|
|
8383
8928
|
try {
|
|
8384
|
-
if (!
|
|
8929
|
+
if (!existsSync29("omni.toml")) {
|
|
8385
8930
|
console.log("No config file found");
|
|
8386
8931
|
console.log(" Run: omnidev init");
|
|
8387
8932
|
process.exit(1);
|
|
@@ -8636,7 +9181,7 @@ var securityRoutes = buildRouteMap5({
|
|
|
8636
9181
|
});
|
|
8637
9182
|
|
|
8638
9183
|
// src/commands/sync.ts
|
|
8639
|
-
import { existsSync as
|
|
9184
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
8640
9185
|
init_src();
|
|
8641
9186
|
import { buildCommand as buildCommand8 } from "@stricli/core";
|
|
8642
9187
|
var PROVIDERS_STATE_PATH = ".omni/state/providers.json";
|
|
@@ -8654,7 +9199,7 @@ async function runSync() {
|
|
|
8654
9199
|
const config3 = await loadConfig();
|
|
8655
9200
|
const activeProfile = await getActiveProfile() ?? "default";
|
|
8656
9201
|
let adapters = await getEnabledAdapters();
|
|
8657
|
-
if (!
|
|
9202
|
+
if (!existsSync30(PROVIDERS_STATE_PATH) || adapters.length === 0) {
|
|
8658
9203
|
console.log("No providers configured yet. Select your provider(s):");
|
|
8659
9204
|
const providerIds = await promptForProviders();
|
|
8660
9205
|
await writeEnabledProviders(providerIds);
|
|
@@ -8864,9 +9409,9 @@ async function buildDynamicApp() {
|
|
|
8864
9409
|
security: securityRoutes
|
|
8865
9410
|
};
|
|
8866
9411
|
debug("Core routes registered", Object.keys(routes));
|
|
8867
|
-
const configPath =
|
|
8868
|
-
debug("Checking for config", { configPath, exists:
|
|
8869
|
-
if (
|
|
9412
|
+
const configPath = join28(process.cwd(), "omni.toml");
|
|
9413
|
+
debug("Checking for config", { configPath, exists: existsSync31(configPath), cwd: process.cwd() });
|
|
9414
|
+
if (existsSync31(configPath)) {
|
|
8870
9415
|
try {
|
|
8871
9416
|
debug("Loading capability commands...");
|
|
8872
9417
|
const capabilityCommands = await loadCapabilityCommands();
|
|
@@ -8941,25 +9486,25 @@ async function loadCapabilityCommands() {
|
|
|
8941
9486
|
return commands;
|
|
8942
9487
|
}
|
|
8943
9488
|
async function loadCapabilityExport(capability3) {
|
|
8944
|
-
const capabilityPath =
|
|
8945
|
-
const builtIndexPath =
|
|
8946
|
-
const jsIndexPath =
|
|
8947
|
-
const tsIndexPath =
|
|
9489
|
+
const capabilityPath = join28(process.cwd(), capability3.path);
|
|
9490
|
+
const builtIndexPath = join28(capabilityPath, "dist", "index.js");
|
|
9491
|
+
const jsIndexPath = join28(capabilityPath, "index.js");
|
|
9492
|
+
const tsIndexPath = join28(capabilityPath, "index.ts");
|
|
8948
9493
|
debug(`Checking entry points for '${capability3.id}'`, {
|
|
8949
9494
|
capabilityPath,
|
|
8950
9495
|
builtIndexPath,
|
|
8951
|
-
builtExists:
|
|
9496
|
+
builtExists: existsSync31(builtIndexPath),
|
|
8952
9497
|
jsIndexPath,
|
|
8953
|
-
jsExists:
|
|
9498
|
+
jsExists: existsSync31(jsIndexPath),
|
|
8954
9499
|
tsIndexPath,
|
|
8955
|
-
tsExists:
|
|
9500
|
+
tsExists: existsSync31(tsIndexPath)
|
|
8956
9501
|
});
|
|
8957
9502
|
let indexPath = null;
|
|
8958
|
-
if (
|
|
9503
|
+
if (existsSync31(builtIndexPath)) {
|
|
8959
9504
|
indexPath = builtIndexPath;
|
|
8960
|
-
} else if (
|
|
9505
|
+
} else if (existsSync31(jsIndexPath)) {
|
|
8961
9506
|
indexPath = jsIndexPath;
|
|
8962
|
-
} else if (
|
|
9507
|
+
} else if (existsSync31(tsIndexPath)) {
|
|
8963
9508
|
indexPath = tsIndexPath;
|
|
8964
9509
|
}
|
|
8965
9510
|
if (!indexPath) {
|