@omnidev-ai/cli 0.17.0 → 0.18.1
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 +864 -371
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1287,85 +1287,6 @@ var init_dist = __esm(() => {
|
|
|
1287
1287
|
dist_default = { parse, stringify, TomlDate, TomlError };
|
|
1288
1288
|
});
|
|
1289
1289
|
|
|
1290
|
-
// ../core/src/providers.ts
|
|
1291
|
-
function normalizeProviderId(provider) {
|
|
1292
|
-
if (provider in PROVIDER_ALIAS_MAP) {
|
|
1293
|
-
return PROVIDER_ALIAS_MAP[provider];
|
|
1294
|
-
}
|
|
1295
|
-
throw new Error(`Unknown provider: ${provider}`);
|
|
1296
|
-
}
|
|
1297
|
-
function normalizeProviderApplicability(value, fieldName) {
|
|
1298
|
-
if (typeof value !== "object" || value === null || Array.isArray(value)) {
|
|
1299
|
-
throw new Error(`${fieldName} must be a table of provider = boolean entries`);
|
|
1300
|
-
}
|
|
1301
|
-
const normalized = {};
|
|
1302
|
-
for (const [rawProvider, rawEnabled] of Object.entries(value)) {
|
|
1303
|
-
if (typeof rawEnabled !== "boolean") {
|
|
1304
|
-
throw new Error(`${fieldName}.${rawProvider} must be a boolean`);
|
|
1305
|
-
}
|
|
1306
|
-
const canonicalProvider = normalizeProviderId(rawProvider);
|
|
1307
|
-
const existing = normalized[canonicalProvider];
|
|
1308
|
-
if (existing !== undefined && existing !== rawEnabled) {
|
|
1309
|
-
throw new Error(`Conflicting provider entries in ${fieldName}: ${rawProvider} maps to ${canonicalProvider}`);
|
|
1310
|
-
}
|
|
1311
|
-
normalized[canonicalProvider] = rawEnabled;
|
|
1312
|
-
}
|
|
1313
|
-
return normalized;
|
|
1314
|
-
}
|
|
1315
|
-
var PROVIDER_ALIAS_MAP;
|
|
1316
|
-
var init_providers = __esm(() => {
|
|
1317
|
-
PROVIDER_ALIAS_MAP = {
|
|
1318
|
-
claude: "claude-code",
|
|
1319
|
-
"claude-code": "claude-code",
|
|
1320
|
-
codex: "codex",
|
|
1321
|
-
cursor: "cursor",
|
|
1322
|
-
opencode: "opencode"
|
|
1323
|
-
};
|
|
1324
|
-
});
|
|
1325
|
-
|
|
1326
|
-
// ../core/src/config/parser.ts
|
|
1327
|
-
function parseOmniConfig(tomlContent) {
|
|
1328
|
-
try {
|
|
1329
|
-
return parse(tomlContent);
|
|
1330
|
-
} catch (error) {
|
|
1331
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1332
|
-
throw new Error(`Invalid TOML in config: ${message}`);
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1335
|
-
function validateCapabilityConfig(parsed) {
|
|
1336
|
-
const cap = parsed["capability"];
|
|
1337
|
-
if (typeof cap !== "object" || cap === null) {
|
|
1338
|
-
throw new Error("capability.id is required in capability.toml");
|
|
1339
|
-
}
|
|
1340
|
-
const capability = cap;
|
|
1341
|
-
if (typeof capability["id"] !== "string") {
|
|
1342
|
-
throw new Error("capability.id is required in capability.toml");
|
|
1343
|
-
}
|
|
1344
|
-
if (typeof capability["name"] !== "string") {
|
|
1345
|
-
throw new Error("capability.name is required in capability.toml");
|
|
1346
|
-
}
|
|
1347
|
-
if (typeof capability["version"] !== "string") {
|
|
1348
|
-
throw new Error("capability.version is required in capability.toml");
|
|
1349
|
-
}
|
|
1350
|
-
if (capability["providers"] !== undefined) {
|
|
1351
|
-
capability["providers"] = normalizeProviderApplicability(capability["providers"], "capability.providers");
|
|
1352
|
-
}
|
|
1353
|
-
}
|
|
1354
|
-
function parseCapabilityConfig(tomlContent) {
|
|
1355
|
-
try {
|
|
1356
|
-
const parsed = parse(tomlContent);
|
|
1357
|
-
validateCapabilityConfig(parsed);
|
|
1358
|
-
return parsed;
|
|
1359
|
-
} catch (error) {
|
|
1360
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
1361
|
-
throw new Error(`Invalid capability.toml: ${message}`);
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
var init_parser = __esm(() => {
|
|
1365
|
-
init_dist();
|
|
1366
|
-
init_providers();
|
|
1367
|
-
});
|
|
1368
|
-
|
|
1369
1290
|
// ../core/src/hooks/constants.ts
|
|
1370
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";
|
|
1371
1292
|
var init_constants = __esm(() => {
|
|
@@ -2451,14 +2372,90 @@ var init_loader = __esm(() => {
|
|
|
2451
2372
|
init_constants();
|
|
2452
2373
|
});
|
|
2453
2374
|
|
|
2454
|
-
// ../core/src/
|
|
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
2455
|
import { existsSync as existsSync6 } from "node:fs";
|
|
2456
2456
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
2457
2457
|
import { join as join4 } from "node:path";
|
|
2458
2458
|
import { parseEnv } from "node:util";
|
|
2459
|
-
function hasEnvPlaceholder(value) {
|
|
2460
|
-
return ENV_PLACEHOLDER_DETECTOR.test(value);
|
|
2461
|
-
}
|
|
2462
2459
|
function mergeEnvSources(capabilityEnv) {
|
|
2463
2460
|
const merged = { ...capabilityEnv };
|
|
2464
2461
|
for (const [key, value] of Object.entries(process.env)) {
|
|
@@ -2468,13 +2465,21 @@ function mergeEnvSources(capabilityEnv) {
|
|
|
2468
2465
|
}
|
|
2469
2466
|
return merged;
|
|
2470
2467
|
}
|
|
2471
|
-
async function
|
|
2468
|
+
async function loadCapabilityEnvVariables(capabilityPath) {
|
|
2472
2469
|
const envPath = join4(capabilityPath, CAPABILITY_ENV_FILE);
|
|
2473
2470
|
if (!existsSync6(envPath)) {
|
|
2474
|
-
return {};
|
|
2471
|
+
return mergeEnvSources({});
|
|
2475
2472
|
}
|
|
2476
2473
|
const envContent = await readFile3(envPath, "utf-8");
|
|
2477
|
-
|
|
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);
|
|
2478
2483
|
}
|
|
2479
2484
|
function resolveString(value, variables, capabilityId, fieldPath) {
|
|
2480
2485
|
if (!hasEnvPlaceholder(value)) {
|
|
@@ -2510,35 +2515,35 @@ function mcpHasPlaceholders(mcp) {
|
|
|
2510
2515
|
}
|
|
2511
2516
|
return strings.some((value) => hasEnvPlaceholder(value));
|
|
2512
2517
|
}
|
|
2513
|
-
async function resolveCapabilityMcpEnv(config, capabilityPath) {
|
|
2518
|
+
async function resolveCapabilityMcpEnv(config, capabilityPath, variables) {
|
|
2514
2519
|
if (!config.mcp || !mcpHasPlaceholders(config.mcp)) {
|
|
2515
2520
|
return config;
|
|
2516
2521
|
}
|
|
2517
|
-
const
|
|
2522
|
+
const resolvedVariables = variables ?? await loadCapabilityEnvVariables(capabilityPath);
|
|
2518
2523
|
const resolvedMcp = { ...config.mcp };
|
|
2519
2524
|
const capabilityId = config.capability.id;
|
|
2520
2525
|
if (resolvedMcp.command) {
|
|
2521
|
-
resolvedMcp.command = resolveString(resolvedMcp.command,
|
|
2526
|
+
resolvedMcp.command = resolveString(resolvedMcp.command, resolvedVariables, capabilityId, "mcp.command");
|
|
2522
2527
|
}
|
|
2523
2528
|
if (resolvedMcp.cwd) {
|
|
2524
|
-
resolvedMcp.cwd = resolveString(resolvedMcp.cwd,
|
|
2529
|
+
resolvedMcp.cwd = resolveString(resolvedMcp.cwd, resolvedVariables, capabilityId, "mcp.cwd");
|
|
2525
2530
|
}
|
|
2526
2531
|
if (resolvedMcp.url) {
|
|
2527
|
-
resolvedMcp.url = resolveString(resolvedMcp.url,
|
|
2532
|
+
resolvedMcp.url = resolveString(resolvedMcp.url, resolvedVariables, capabilityId, "mcp.url");
|
|
2528
2533
|
}
|
|
2529
2534
|
if (resolvedMcp.args) {
|
|
2530
|
-
resolvedMcp.args = resolvedMcp.args.map((arg, index) => resolveString(arg,
|
|
2535
|
+
resolvedMcp.args = resolvedMcp.args.map((arg, index) => resolveString(arg, resolvedVariables, capabilityId, `mcp.args[${index}]`));
|
|
2531
2536
|
}
|
|
2532
2537
|
if (resolvedMcp.env) {
|
|
2533
2538
|
resolvedMcp.env = Object.fromEntries(Object.entries(resolvedMcp.env).map(([key, value]) => [
|
|
2534
2539
|
key,
|
|
2535
|
-
resolveString(value,
|
|
2540
|
+
resolveString(value, resolvedVariables, capabilityId, `mcp.env.${key}`)
|
|
2536
2541
|
]));
|
|
2537
2542
|
}
|
|
2538
2543
|
if (resolvedMcp.headers) {
|
|
2539
2544
|
resolvedMcp.headers = Object.fromEntries(Object.entries(resolvedMcp.headers).map(([key, value]) => [
|
|
2540
2545
|
key,
|
|
2541
|
-
resolveString(value,
|
|
2546
|
+
resolveString(value, resolvedVariables, capabilityId, `mcp.headers.${key}`)
|
|
2542
2547
|
]));
|
|
2543
2548
|
}
|
|
2544
2549
|
return {
|
|
@@ -2546,8 +2551,9 @@ async function resolveCapabilityMcpEnv(config, capabilityPath) {
|
|
|
2546
2551
|
mcp: resolvedMcp
|
|
2547
2552
|
};
|
|
2548
2553
|
}
|
|
2549
|
-
var
|
|
2554
|
+
var ENV_PLACEHOLDER, ENV_PLACEHOLDER_DETECTOR;
|
|
2550
2555
|
var init_mcp_env = __esm(() => {
|
|
2556
|
+
init_env();
|
|
2551
2557
|
ENV_PLACEHOLDER = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
2552
2558
|
ENV_PLACEHOLDER_DETECTOR = /\$\{([A-Za-z_][A-Za-z0-9_]*)\}/;
|
|
2553
2559
|
});
|
|
@@ -2582,9 +2588,45 @@ var init_rules = () => {};
|
|
|
2582
2588
|
import { existsSync as existsSync8, readdirSync as readdirSync4 } from "node:fs";
|
|
2583
2589
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
2584
2590
|
import { join as join6 } from "node:path";
|
|
2585
|
-
|
|
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) {
|
|
2586
2627
|
const skills = [];
|
|
2587
2628
|
const possibleDirNames = ["skills", "skill"];
|
|
2629
|
+
const resolvedVariables = variables ?? await loadCapabilityEnvVariables(capabilityPath);
|
|
2588
2630
|
for (const dirName of possibleDirNames) {
|
|
2589
2631
|
const dir = join6(capabilityPath, dirName);
|
|
2590
2632
|
if (!existsSync8(dir)) {
|
|
@@ -2595,33 +2637,30 @@ async function loadSkills(capabilityPath, capabilityId) {
|
|
|
2595
2637
|
if (entry.isDirectory()) {
|
|
2596
2638
|
const skillPath = join6(dir, entry.name, "SKILL.md");
|
|
2597
2639
|
if (existsSync8(skillPath)) {
|
|
2598
|
-
const skill = await parseSkillFile(skillPath, capabilityId);
|
|
2599
|
-
skills.push(
|
|
2640
|
+
const skill = await parseSkillFile(skillPath, capabilityId, resolvedVariables, `skill file ${skillPath}`);
|
|
2641
|
+
skills.push({
|
|
2642
|
+
...skill,
|
|
2643
|
+
sourcePath: join6(dir, entry.name)
|
|
2644
|
+
});
|
|
2600
2645
|
}
|
|
2601
2646
|
}
|
|
2602
2647
|
}
|
|
2603
2648
|
}
|
|
2604
2649
|
return skills;
|
|
2605
2650
|
}
|
|
2606
|
-
async function parseSkillFile(filePath, capabilityId) {
|
|
2651
|
+
async function parseSkillFile(filePath, capabilityId, variables, sourceLabel) {
|
|
2607
2652
|
const content = await readFile5(filePath, "utf-8");
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
}
|
|
2612
|
-
const frontmatter = parsed.frontmatter;
|
|
2613
|
-
const instructions = parsed.markdown;
|
|
2614
|
-
if (!frontmatter.name || !frontmatter.description) {
|
|
2615
|
-
throw new Error(`Invalid SKILL.md at ${filePath}: name and description required in frontmatter`);
|
|
2616
|
-
}
|
|
2617
|
-
return {
|
|
2618
|
-
name: frontmatter.name,
|
|
2619
|
-
description: frontmatter.description,
|
|
2620
|
-
instructions: instructions.trim(),
|
|
2621
|
-
capabilityId
|
|
2622
|
-
};
|
|
2653
|
+
return parseSkillMarkdown(content, capabilityId, {
|
|
2654
|
+
variables,
|
|
2655
|
+
sourceLabel
|
|
2656
|
+
});
|
|
2623
2657
|
}
|
|
2624
|
-
var
|
|
2658
|
+
var SKILL_PLACEHOLDER, SKILL_PLACEHOLDER_DETECTOR;
|
|
2659
|
+
var init_skills = __esm(() => {
|
|
2660
|
+
init_env();
|
|
2661
|
+
SKILL_PLACEHOLDER = /\{OMNIDEV_([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
2662
|
+
SKILL_PLACEHOLDER_DETECTOR = /\{OMNIDEV_([A-Za-z_][A-Za-z0-9_]*)\}/;
|
|
2663
|
+
});
|
|
2625
2664
|
|
|
2626
2665
|
// ../core/src/capability/subagents.ts
|
|
2627
2666
|
import { existsSync as existsSync9, readdirSync as readdirSync5 } from "node:fs";
|
|
@@ -2767,40 +2806,13 @@ async function loadTypeDefinitions(capabilityPath) {
|
|
|
2767
2806
|
}
|
|
2768
2807
|
return readFile7(typesPath, "utf-8");
|
|
2769
2808
|
}
|
|
2770
|
-
function convertSkillExports(skillExports, capabilityId) {
|
|
2771
|
-
return skillExports.map((skillExport) => {
|
|
2809
|
+
function convertSkillExports(skillExports, capabilityId, variables) {
|
|
2810
|
+
return skillExports.map((skillExport, index) => {
|
|
2772
2811
|
const exportObj = skillExport;
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
let instructions = exportObj.skillMd;
|
|
2778
|
-
if (lines[0]?.trim() === "---") {
|
|
2779
|
-
const endIndex = lines.findIndex((line, i) => i > 0 && line.trim() === "---");
|
|
2780
|
-
if (endIndex > 0) {
|
|
2781
|
-
const frontmatter = lines.slice(1, endIndex);
|
|
2782
|
-
instructions = lines.slice(endIndex + 1).join(`
|
|
2783
|
-
`).trim();
|
|
2784
|
-
for (const line of frontmatter) {
|
|
2785
|
-
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
2786
|
-
if (match?.[1] && match[2]) {
|
|
2787
|
-
const key = match[1];
|
|
2788
|
-
const value = match[2];
|
|
2789
|
-
if (key === "name") {
|
|
2790
|
-
name = value.replace(/^["']|["']$/g, "");
|
|
2791
|
-
} else if (key === "description") {
|
|
2792
|
-
description = value.replace(/^["']|["']$/g, "");
|
|
2793
|
-
}
|
|
2794
|
-
}
|
|
2795
|
-
}
|
|
2796
|
-
}
|
|
2797
|
-
}
|
|
2798
|
-
return {
|
|
2799
|
-
name,
|
|
2800
|
-
description,
|
|
2801
|
-
instructions,
|
|
2802
|
-
capabilityId
|
|
2803
|
-
};
|
|
2812
|
+
return parseSkillMarkdown(exportObj.skillMd, capabilityId, {
|
|
2813
|
+
variables,
|
|
2814
|
+
sourceLabel: `programmatic skill export[${index}]`
|
|
2815
|
+
});
|
|
2804
2816
|
});
|
|
2805
2817
|
}
|
|
2806
2818
|
function convertRuleExports(ruleExports, capabilityId) {
|
|
@@ -2953,8 +2965,9 @@ function mergeByName(fileBased, programmatic) {
|
|
|
2953
2965
|
return Array.from(byName.values());
|
|
2954
2966
|
}
|
|
2955
2967
|
async function loadCapability(capabilityPath) {
|
|
2968
|
+
const capabilityEnvVariables = await loadCapabilityEnvVariables(capabilityPath);
|
|
2956
2969
|
const rawConfig = await loadCapabilityConfig(capabilityPath);
|
|
2957
|
-
const config = await resolveCapabilityMcpEnv(rawConfig, capabilityPath);
|
|
2970
|
+
const config = await resolveCapabilityMcpEnv(rawConfig, capabilityPath, capabilityEnvVariables);
|
|
2958
2971
|
const id = config.capability.id;
|
|
2959
2972
|
const exports = await importCapabilityExports(capabilityPath);
|
|
2960
2973
|
const exportsAny = exports;
|
|
@@ -2969,8 +2982,8 @@ async function loadCapability(capabilityPath) {
|
|
|
2969
2982
|
return;
|
|
2970
2983
|
};
|
|
2971
2984
|
const skillsExport = getExportValue("skills");
|
|
2972
|
-
const programmaticSkills = Array.isArray(skillsExport) ? convertSkillExports(skillsExport, id) : [];
|
|
2973
|
-
const fileSkills = await loadSkills(capabilityPath, id);
|
|
2985
|
+
const programmaticSkills = Array.isArray(skillsExport) ? convertSkillExports(skillsExport, id, capabilityEnvVariables) : [];
|
|
2986
|
+
const fileSkills = await loadSkills(capabilityPath, id, capabilityEnvVariables);
|
|
2974
2987
|
const skills = mergeByName(fileSkills, programmaticSkills);
|
|
2975
2988
|
const rulesExport = getExportValue("rules");
|
|
2976
2989
|
const programmaticRules = Array.isArray(rulesExport) ? convertRuleExports(rulesExport, id) : [];
|
|
@@ -3018,11 +3031,12 @@ async function loadCapability(capabilityPath) {
|
|
|
3018
3031
|
}
|
|
3019
3032
|
var CAPABILITIES_DIR = ".omni/capabilities";
|
|
3020
3033
|
var init_loader2 = __esm(() => {
|
|
3021
|
-
init_parser();
|
|
3022
3034
|
init_loader();
|
|
3023
|
-
|
|
3035
|
+
init_parser();
|
|
3024
3036
|
init_commands();
|
|
3025
3037
|
init_docs();
|
|
3038
|
+
init_env();
|
|
3039
|
+
init_mcp_env();
|
|
3026
3040
|
init_rules();
|
|
3027
3041
|
init_skills();
|
|
3028
3042
|
init_subagents();
|
|
@@ -3513,7 +3527,7 @@ import { existsSync as existsSync13 } from "node:fs";
|
|
|
3513
3527
|
import { spawn } from "node:child_process";
|
|
3514
3528
|
import { cp, mkdir, readdir, readFile as readFile10, rename, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
|
|
3515
3529
|
import { join as join9 } from "node:path";
|
|
3516
|
-
import { createHash } from "node:crypto";
|
|
3530
|
+
import { createHash as createHash2 } from "node:crypto";
|
|
3517
3531
|
async function spawnCapture(command, args, options) {
|
|
3518
3532
|
const timeout = options?.timeout ?? 60000;
|
|
3519
3533
|
return await new Promise((resolve2, reject) => {
|
|
@@ -3722,7 +3736,7 @@ function escapeTomlString(value) {
|
|
|
3722
3736
|
return value.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
3723
3737
|
}
|
|
3724
3738
|
async function computeContentHash(dirPath, excludePatterns = CONTENT_HASH_EXCLUDES) {
|
|
3725
|
-
const hash =
|
|
3739
|
+
const hash = createHash2("sha256");
|
|
3726
3740
|
const files = [];
|
|
3727
3741
|
async function collectFiles(currentPath, relativeTo) {
|
|
3728
3742
|
const entries = await readdir(currentPath, { withFileTypes: true });
|
|
@@ -5157,29 +5171,107 @@ var init_mcp_json = __esm(() => {
|
|
|
5157
5171
|
});
|
|
5158
5172
|
|
|
5159
5173
|
// ../core/src/state/manifest.ts
|
|
5160
|
-
import {
|
|
5174
|
+
import { createHash as createHash3 } from "node:crypto";
|
|
5175
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync2, readdirSync as readdirSync7, rmSync } from "node:fs";
|
|
5176
|
+
import { dirname, join as join10 } from "node:path";
|
|
5161
5177
|
import { readFile as readFile14, writeFile as writeFile7 } from "node:fs/promises";
|
|
5162
|
-
|
|
5163
|
-
|
|
5178
|
+
function createEmptyManifest() {
|
|
5179
|
+
return {
|
|
5180
|
+
version: CURRENT_VERSION,
|
|
5181
|
+
syncedAt: new Date().toISOString(),
|
|
5182
|
+
capabilities: {},
|
|
5183
|
+
providers: {}
|
|
5184
|
+
};
|
|
5185
|
+
}
|
|
5186
|
+
function normalizeManifest(parsed) {
|
|
5187
|
+
if (parsed.version === CURRENT_VERSION && "providers" in parsed) {
|
|
5164
5188
|
return {
|
|
5165
5189
|
version: CURRENT_VERSION,
|
|
5166
|
-
syncedAt:
|
|
5167
|
-
capabilities:
|
|
5190
|
+
syncedAt: parsed.syncedAt,
|
|
5191
|
+
capabilities: parsed.capabilities,
|
|
5192
|
+
providers: parsed.providers ?? {}
|
|
5168
5193
|
};
|
|
5169
5194
|
}
|
|
5195
|
+
return {
|
|
5196
|
+
version: CURRENT_VERSION,
|
|
5197
|
+
syncedAt: parsed.syncedAt,
|
|
5198
|
+
capabilities: parsed.capabilities,
|
|
5199
|
+
providers: {}
|
|
5200
|
+
};
|
|
5201
|
+
}
|
|
5202
|
+
function hashContent2(content) {
|
|
5203
|
+
return createHash3("sha256").update(content).digest("hex");
|
|
5204
|
+
}
|
|
5205
|
+
function normalizePath(path) {
|
|
5206
|
+
return path.replace(/\\/g, "/");
|
|
5207
|
+
}
|
|
5208
|
+
function isDirectoryEmpty(path) {
|
|
5209
|
+
return readdirSync7(path).length === 0;
|
|
5210
|
+
}
|
|
5211
|
+
async function cleanupManagedOutput(output) {
|
|
5212
|
+
const outputPath = join10(process.cwd(), output.path);
|
|
5213
|
+
if (!existsSync17(outputPath)) {
|
|
5214
|
+
return { deleted: false };
|
|
5215
|
+
}
|
|
5216
|
+
if (output.cleanupStrategy === "remove-json-key") {
|
|
5217
|
+
if (!output.jsonKey) {
|
|
5218
|
+
return { deleted: false, reason: `missing jsonKey metadata for ${output.path}` };
|
|
5219
|
+
}
|
|
5220
|
+
let parsed;
|
|
5221
|
+
try {
|
|
5222
|
+
parsed = JSON.parse(await readFile14(outputPath, "utf-8"));
|
|
5223
|
+
} catch {
|
|
5224
|
+
return { deleted: false, reason: `could not parse JSON at ${output.path}` };
|
|
5225
|
+
}
|
|
5226
|
+
const currentValue = parsed[output.jsonKey];
|
|
5227
|
+
if (currentValue === undefined) {
|
|
5228
|
+
return { deleted: false };
|
|
5229
|
+
}
|
|
5230
|
+
if (hashContent2(JSON.stringify(currentValue)) !== output.hash) {
|
|
5231
|
+
return { deleted: false, reason: `managed section changed at ${output.path}` };
|
|
5232
|
+
}
|
|
5233
|
+
delete parsed[output.jsonKey];
|
|
5234
|
+
if (Object.keys(parsed).length === 0) {
|
|
5235
|
+
rmSync(outputPath);
|
|
5236
|
+
} else {
|
|
5237
|
+
await writeFile7(outputPath, `${JSON.stringify(parsed, null, 2)}
|
|
5238
|
+
`, "utf-8");
|
|
5239
|
+
}
|
|
5240
|
+
return { deleted: true };
|
|
5241
|
+
}
|
|
5242
|
+
const currentContent = await readFile14(outputPath, "utf-8");
|
|
5243
|
+
if (hashContent2(currentContent) !== output.hash) {
|
|
5244
|
+
return { deleted: false, reason: `managed file changed at ${output.path}` };
|
|
5245
|
+
}
|
|
5246
|
+
rmSync(outputPath);
|
|
5247
|
+
if (output.cleanupStrategy === "delete-file-and-prune-empty-parents" && output.pruneRoot) {
|
|
5248
|
+
const pruneRoot = join10(process.cwd(), output.pruneRoot);
|
|
5249
|
+
let currentDir = dirname(outputPath);
|
|
5250
|
+
while (normalizePath(currentDir).startsWith(normalizePath(pruneRoot)) && normalizePath(currentDir) !== normalizePath(pruneRoot) && existsSync17(currentDir) && isDirectoryEmpty(currentDir)) {
|
|
5251
|
+
rmSync(currentDir, { recursive: true });
|
|
5252
|
+
currentDir = dirname(currentDir);
|
|
5253
|
+
}
|
|
5254
|
+
}
|
|
5255
|
+
return { deleted: true };
|
|
5256
|
+
}
|
|
5257
|
+
async function loadManifest() {
|
|
5258
|
+
if (!existsSync17(MANIFEST_PATH)) {
|
|
5259
|
+
return createEmptyManifest();
|
|
5260
|
+
}
|
|
5170
5261
|
const content = await readFile14(MANIFEST_PATH, "utf-8");
|
|
5171
|
-
return JSON.parse(content);
|
|
5262
|
+
return normalizeManifest(JSON.parse(content));
|
|
5172
5263
|
}
|
|
5173
5264
|
async function saveManifest(manifest) {
|
|
5174
5265
|
mkdirSync2(".omni/state", { recursive: true });
|
|
5175
5266
|
await writeFile7(MANIFEST_PATH, `${JSON.stringify(manifest, null, 2)}
|
|
5176
5267
|
`, "utf-8");
|
|
5177
5268
|
}
|
|
5178
|
-
function buildManifestFromCapabilities(capabilities2) {
|
|
5269
|
+
function buildManifestFromCapabilities(capabilities2, providerOutputs = new Map) {
|
|
5179
5270
|
const manifest = {
|
|
5180
5271
|
version: CURRENT_VERSION,
|
|
5181
5272
|
syncedAt: new Date().toISOString(),
|
|
5182
|
-
capabilities: {}
|
|
5273
|
+
capabilities: {},
|
|
5274
|
+
providers: {}
|
|
5183
5275
|
};
|
|
5184
5276
|
for (const cap of capabilities2) {
|
|
5185
5277
|
const resources = {
|
|
@@ -5191,38 +5283,59 @@ function buildManifestFromCapabilities(capabilities2) {
|
|
|
5191
5283
|
};
|
|
5192
5284
|
manifest.capabilities[cap.id] = resources;
|
|
5193
5285
|
}
|
|
5286
|
+
for (const [providerId, outputs] of providerOutputs) {
|
|
5287
|
+
manifest.providers[providerId] = {
|
|
5288
|
+
outputs: Object.fromEntries(outputs.map((output) => [output.path, output]))
|
|
5289
|
+
};
|
|
5290
|
+
}
|
|
5194
5291
|
return manifest;
|
|
5195
5292
|
}
|
|
5196
|
-
async function cleanupStaleResources(
|
|
5197
|
-
|
|
5293
|
+
async function cleanupStaleResources(_previousManifest, _currentCapabilityIds) {
|
|
5294
|
+
return {
|
|
5198
5295
|
deletedSkills: [],
|
|
5199
5296
|
deletedRules: [],
|
|
5200
5297
|
deletedCommands: [],
|
|
5201
5298
|
deletedSubagents: [],
|
|
5202
5299
|
deletedMcps: []
|
|
5203
5300
|
};
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5301
|
+
}
|
|
5302
|
+
async function cleanupStaleManagedOutputs(previousManifest, nextProviders) {
|
|
5303
|
+
const result = {
|
|
5304
|
+
deletedPaths: [],
|
|
5305
|
+
skippedPaths: []
|
|
5306
|
+
};
|
|
5307
|
+
const claimedPaths = new Set;
|
|
5308
|
+
for (const outputs of nextProviders.values()) {
|
|
5309
|
+
for (const output of outputs) {
|
|
5310
|
+
claimedPaths.add(output.path);
|
|
5207
5311
|
}
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5312
|
+
}
|
|
5313
|
+
for (const [providerId, providerState] of Object.entries(previousManifest.providers)) {
|
|
5314
|
+
const nextPaths = new Set((nextProviders.get(providerId) ?? []).map((output) => output.path));
|
|
5315
|
+
for (const output of Object.values(providerState.outputs)) {
|
|
5316
|
+
if (nextPaths.has(output.path)) {
|
|
5317
|
+
continue;
|
|
5213
5318
|
}
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
result.
|
|
5319
|
+
if (claimedPaths.has(output.path)) {
|
|
5320
|
+
continue;
|
|
5321
|
+
}
|
|
5322
|
+
const cleanup = await cleanupManagedOutput(output);
|
|
5323
|
+
if (cleanup.deleted) {
|
|
5324
|
+
result.deletedPaths.push(output.path);
|
|
5325
|
+
} else if (cleanup.reason) {
|
|
5326
|
+
result.skippedPaths.push({
|
|
5327
|
+
path: output.path,
|
|
5328
|
+
reason: cleanup.reason
|
|
5329
|
+
});
|
|
5220
5330
|
}
|
|
5221
5331
|
}
|
|
5222
5332
|
}
|
|
5223
5333
|
return result;
|
|
5224
5334
|
}
|
|
5225
|
-
|
|
5335
|
+
function getProviderManagedOutputs(manifest, providerId) {
|
|
5336
|
+
return Object.values(manifest.providers[providerId]?.outputs ?? {});
|
|
5337
|
+
}
|
|
5338
|
+
var MANIFEST_PATH = ".omni/state/manifest.json", CURRENT_VERSION = 2;
|
|
5226
5339
|
var init_manifest = () => {};
|
|
5227
5340
|
|
|
5228
5341
|
// ../core/src/state/providers.ts
|
|
@@ -5370,16 +5483,42 @@ var init_state = __esm(() => {
|
|
|
5370
5483
|
|
|
5371
5484
|
// ../core/src/sync.ts
|
|
5372
5485
|
import { spawn as spawn2 } from "node:child_process";
|
|
5373
|
-
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
5486
|
+
import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync3 } from "node:fs";
|
|
5487
|
+
import { join as join11 } from "node:path";
|
|
5488
|
+
function getDeclaredPackageManager(packageManager) {
|
|
5489
|
+
if (typeof packageManager !== "string" || packageManager.trim().length === 0) {
|
|
5490
|
+
return;
|
|
5491
|
+
}
|
|
5492
|
+
const atIndex = packageManager.indexOf("@");
|
|
5493
|
+
return atIndex === -1 ? packageManager : packageManager.slice(0, atIndex);
|
|
5494
|
+
}
|
|
5495
|
+
function resolveCapabilityInstallCommand(capabilityPath, options) {
|
|
5496
|
+
const packageJsonPath = join11(capabilityPath, "package.json");
|
|
5497
|
+
const packageLockPath = join11(capabilityPath, "package-lock.json");
|
|
5498
|
+
let packageManager;
|
|
5499
|
+
try {
|
|
5500
|
+
const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
5501
|
+
packageManager = getDeclaredPackageManager(pkgJson.packageManager);
|
|
5502
|
+
} catch {}
|
|
5503
|
+
if (!options.hasNpm) {
|
|
5504
|
+
throw new Error("npm is not installed. Install npm to install capability dependencies.");
|
|
5505
|
+
}
|
|
5506
|
+
if (packageManager && packageManager !== "npm") {
|
|
5507
|
+
throw new Error(`Capability at ${capabilityPath} declares packageManager=${packageManager}, but OmniDev only supports npm for capability dependencies.`);
|
|
5508
|
+
}
|
|
5509
|
+
return {
|
|
5510
|
+
cmd: "npm",
|
|
5511
|
+
args: [existsSync20(packageLockPath) ? "ci" : "install"]
|
|
5512
|
+
};
|
|
5513
|
+
}
|
|
5374
5514
|
async function installCapabilityDependencies(silent) {
|
|
5375
|
-
const {
|
|
5376
|
-
const { join: join10 } = await import("node:path");
|
|
5515
|
+
const { readdirSync: readdirSync8 } = await import("node:fs");
|
|
5377
5516
|
const { parse: parse2 } = await Promise.resolve().then(() => (init_dist(), exports_dist));
|
|
5378
5517
|
const capabilitiesDir = ".omni/capabilities";
|
|
5379
5518
|
if (!existsSync20(capabilitiesDir)) {
|
|
5380
5519
|
return;
|
|
5381
5520
|
}
|
|
5382
|
-
const entries =
|
|
5521
|
+
const entries = readdirSync8(capabilitiesDir, { withFileTypes: true });
|
|
5383
5522
|
async function commandExists(cmd) {
|
|
5384
5523
|
return await new Promise((resolve2) => {
|
|
5385
5524
|
const proc = spawn2(cmd, ["--version"], { stdio: "ignore" });
|
|
@@ -5387,18 +5526,17 @@ async function installCapabilityDependencies(silent) {
|
|
|
5387
5526
|
proc.on("close", (code) => resolve2(code === 0));
|
|
5388
5527
|
});
|
|
5389
5528
|
}
|
|
5390
|
-
const
|
|
5391
|
-
|
|
5392
|
-
|
|
5393
|
-
throw new Error("Neither Bun nor npm is installed. Install one of them to install capability dependencies.");
|
|
5529
|
+
const hasNpm = await commandExists("npm");
|
|
5530
|
+
if (!hasNpm) {
|
|
5531
|
+
throw new Error("npm is not installed. Install npm to install capability dependencies.");
|
|
5394
5532
|
}
|
|
5395
5533
|
for (const entry of entries) {
|
|
5396
5534
|
if (!entry.isDirectory()) {
|
|
5397
5535
|
continue;
|
|
5398
5536
|
}
|
|
5399
|
-
const capabilityPath =
|
|
5400
|
-
const packageJsonPath =
|
|
5401
|
-
const capabilityTomlPath =
|
|
5537
|
+
const capabilityPath = join11(capabilitiesDir, entry.name);
|
|
5538
|
+
const packageJsonPath = join11(capabilityPath, "package.json");
|
|
5539
|
+
const capabilityTomlPath = join11(capabilityPath, "capability.toml");
|
|
5402
5540
|
if (!existsSync20(packageJsonPath)) {
|
|
5403
5541
|
continue;
|
|
5404
5542
|
}
|
|
@@ -5413,9 +5551,9 @@ async function installCapabilityDependencies(silent) {
|
|
|
5413
5551
|
}
|
|
5414
5552
|
try {
|
|
5415
5553
|
await new Promise((resolve2, reject) => {
|
|
5416
|
-
const
|
|
5417
|
-
|
|
5418
|
-
|
|
5554
|
+
const { cmd, args } = resolveCapabilityInstallCommand(capabilityPath, {
|
|
5555
|
+
hasNpm
|
|
5556
|
+
});
|
|
5419
5557
|
const proc = spawn2(cmd, args, {
|
|
5420
5558
|
cwd: capabilityPath,
|
|
5421
5559
|
stdio: "pipe"
|
|
@@ -5436,7 +5574,7 @@ ${stderr}`));
|
|
|
5436
5574
|
reject(error);
|
|
5437
5575
|
});
|
|
5438
5576
|
});
|
|
5439
|
-
const hasIndexTs = existsSync20(
|
|
5577
|
+
const hasIndexTs = existsSync20(join11(capabilityPath, "index.ts"));
|
|
5440
5578
|
let hasBuildScript = false;
|
|
5441
5579
|
try {
|
|
5442
5580
|
const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
@@ -5444,9 +5582,7 @@ ${stderr}`));
|
|
|
5444
5582
|
} catch {}
|
|
5445
5583
|
if (hasBuildScript) {
|
|
5446
5584
|
await new Promise((resolve2, reject) => {
|
|
5447
|
-
const
|
|
5448
|
-
const args = ["run", "build"];
|
|
5449
|
-
const proc = spawn2(cmd, args, {
|
|
5585
|
+
const proc = spawn2("npm", ["run", "build"], {
|
|
5450
5586
|
cwd: capabilityPath,
|
|
5451
5587
|
stdio: "pipe"
|
|
5452
5588
|
});
|
|
@@ -5467,7 +5603,7 @@ ${stderr}`));
|
|
|
5467
5603
|
});
|
|
5468
5604
|
});
|
|
5469
5605
|
} else if (hasIndexTs && !silent) {
|
|
5470
|
-
const hasBuiltIndex = existsSync20(
|
|
5606
|
+
const hasBuiltIndex = existsSync20(join11(capabilityPath, "dist", "index.js"));
|
|
5471
5607
|
if (!hasBuiltIndex) {
|
|
5472
5608
|
console.warn(`Warning: Capability at ${capabilityPath} has index.ts but no build script.
|
|
5473
5609
|
Add a "build" script to package.json (e.g., "build": "tsc") to compile TypeScript.`);
|
|
@@ -5538,8 +5674,8 @@ async function syncAgentConfiguration(options) {
|
|
|
5538
5674
|
}
|
|
5539
5675
|
mkdirSync5(".omni", { recursive: true });
|
|
5540
5676
|
await syncMcpJson(capabilities2, previousManifest);
|
|
5541
|
-
const
|
|
5542
|
-
|
|
5677
|
+
const enabledProviderIds = new Set(adapters.map((adapter) => String(adapter.id)));
|
|
5678
|
+
const successfulProviderOutputs = new Map;
|
|
5543
5679
|
if (adapters.length > 0) {
|
|
5544
5680
|
const config2 = await loadConfig();
|
|
5545
5681
|
const ctx = {
|
|
@@ -5548,12 +5684,33 @@ async function syncAgentConfiguration(options) {
|
|
|
5548
5684
|
};
|
|
5549
5685
|
for (const adapter of adapters) {
|
|
5550
5686
|
try {
|
|
5551
|
-
await adapter.sync(bundle, ctx);
|
|
5687
|
+
const adapterResult = await adapter.sync(bundle, ctx);
|
|
5688
|
+
successfulProviderOutputs.set(String(adapter.id), adapterResult.managedOutputs ?? []);
|
|
5552
5689
|
} catch (error) {
|
|
5553
5690
|
console.error(`Error running ${adapter.displayName} adapter:`, error);
|
|
5554
5691
|
}
|
|
5555
5692
|
}
|
|
5556
5693
|
}
|
|
5694
|
+
const nextProviderOutputs = new Map;
|
|
5695
|
+
if (adapters.length === 0) {
|
|
5696
|
+
for (const providerId of Object.keys(previousManifest.providers)) {
|
|
5697
|
+
nextProviderOutputs.set(providerId, getProviderManagedOutputs(previousManifest, providerId));
|
|
5698
|
+
}
|
|
5699
|
+
} else {
|
|
5700
|
+
for (const providerId of enabledProviderIds) {
|
|
5701
|
+
if (successfulProviderOutputs.has(providerId)) {
|
|
5702
|
+
nextProviderOutputs.set(providerId, successfulProviderOutputs.get(providerId) ?? []);
|
|
5703
|
+
continue;
|
|
5704
|
+
}
|
|
5705
|
+
nextProviderOutputs.set(providerId, getProviderManagedOutputs(previousManifest, providerId));
|
|
5706
|
+
}
|
|
5707
|
+
}
|
|
5708
|
+
const cleanupResult = await cleanupStaleManagedOutputs(previousManifest, nextProviderOutputs);
|
|
5709
|
+
for (const skipped of cleanupResult.skippedPaths) {
|
|
5710
|
+
console.warn(`Warning: skipped cleanup for ${skipped.path} (${skipped.reason})`);
|
|
5711
|
+
}
|
|
5712
|
+
const newManifest = buildManifestFromCapabilities(capabilities2, nextProviderOutputs);
|
|
5713
|
+
await saveManifest(newManifest);
|
|
5557
5714
|
const result = {
|
|
5558
5715
|
capabilities: capabilities2.map((c) => c.id),
|
|
5559
5716
|
skillCount: bundle.skills.length,
|
|
@@ -5598,21 +5755,23 @@ var init_types3 = __esm(() => {
|
|
|
5598
5755
|
unicode: true,
|
|
5599
5756
|
symlinks: true,
|
|
5600
5757
|
scripts: true,
|
|
5601
|
-
binaries: false
|
|
5758
|
+
binaries: false,
|
|
5759
|
+
hiddenCommands: true
|
|
5602
5760
|
}
|
|
5603
5761
|
};
|
|
5604
5762
|
DEFAULT_SCAN_SETTINGS = {
|
|
5605
5763
|
unicode: true,
|
|
5606
5764
|
symlinks: true,
|
|
5607
5765
|
scripts: true,
|
|
5608
|
-
binaries: false
|
|
5766
|
+
binaries: false,
|
|
5767
|
+
hiddenCommands: true
|
|
5609
5768
|
};
|
|
5610
5769
|
});
|
|
5611
5770
|
|
|
5612
5771
|
// ../core/src/security/scanner.ts
|
|
5613
|
-
import { existsSync as
|
|
5772
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
5614
5773
|
import { lstat, readdir as readdir2, readFile as readFile17, readlink, realpath } from "node:fs/promises";
|
|
5615
|
-
import { join as
|
|
5774
|
+
import { join as join12, relative, resolve as resolve2 } from "node:path";
|
|
5616
5775
|
async function scanFileForUnicode(filePath, relativePath) {
|
|
5617
5776
|
const findings = [];
|
|
5618
5777
|
try {
|
|
@@ -5693,10 +5852,113 @@ async function scanFileForScripts(filePath, relativePath) {
|
|
|
5693
5852
|
} catch {}
|
|
5694
5853
|
return findings;
|
|
5695
5854
|
}
|
|
5855
|
+
function extractHiddenRegions(fileContent) {
|
|
5856
|
+
const regions = [];
|
|
5857
|
+
HTML_COMMENT_RE.lastIndex = 0;
|
|
5858
|
+
for (let match = HTML_COMMENT_RE.exec(fileContent);match !== null; match = HTML_COMMENT_RE.exec(fileContent)) {
|
|
5859
|
+
const captured = match[1];
|
|
5860
|
+
if (captured === undefined)
|
|
5861
|
+
continue;
|
|
5862
|
+
const beforeMatch = fileContent.substring(0, match.index);
|
|
5863
|
+
const startLine = beforeMatch.split(`
|
|
5864
|
+
`).length;
|
|
5865
|
+
regions.push({ content: captured, startLine });
|
|
5866
|
+
}
|
|
5867
|
+
HIDDEN_REFERENCE_RE.lastIndex = 0;
|
|
5868
|
+
for (let match = HIDDEN_REFERENCE_RE.exec(fileContent);match !== null; match = HIDDEN_REFERENCE_RE.exec(fileContent)) {
|
|
5869
|
+
const captured = match[1];
|
|
5870
|
+
if (captured === undefined)
|
|
5871
|
+
continue;
|
|
5872
|
+
const beforeMatch = fileContent.substring(0, match.index);
|
|
5873
|
+
const startLine = beforeMatch.split(`
|
|
5874
|
+
`).length;
|
|
5875
|
+
regions.push({ content: captured, startLine });
|
|
5876
|
+
}
|
|
5877
|
+
return regions;
|
|
5878
|
+
}
|
|
5879
|
+
async function scanFileForHiddenCommands(filePath, relativePath) {
|
|
5880
|
+
const findings = [];
|
|
5881
|
+
try {
|
|
5882
|
+
const content = await readFile17(filePath, "utf-8");
|
|
5883
|
+
const hiddenRegions = extractHiddenRegions(content);
|
|
5884
|
+
for (const region of hiddenRegions) {
|
|
5885
|
+
const regionLines = region.content.split(`
|
|
5886
|
+
`);
|
|
5887
|
+
for (let i = 0;i < regionLines.length; i++) {
|
|
5888
|
+
const line = regionLines[i] ?? "";
|
|
5889
|
+
if (!line.trim())
|
|
5890
|
+
continue;
|
|
5891
|
+
for (const { pattern, message, severity } of HIDDEN_COMMAND_PATTERNS) {
|
|
5892
|
+
if (pattern.test(line)) {
|
|
5893
|
+
findings.push({
|
|
5894
|
+
type: "hidden_command",
|
|
5895
|
+
severity,
|
|
5896
|
+
file: relativePath,
|
|
5897
|
+
line: region.startLine + i,
|
|
5898
|
+
message: `Hidden in comment: ${message}`,
|
|
5899
|
+
details: line.trim().substring(0, 100)
|
|
5900
|
+
});
|
|
5901
|
+
}
|
|
5902
|
+
}
|
|
5903
|
+
for (const { pattern, message, severity } of NETWORK_REQUEST_PATTERNS) {
|
|
5904
|
+
if (pattern.test(line)) {
|
|
5905
|
+
findings.push({
|
|
5906
|
+
type: "network_request",
|
|
5907
|
+
severity: severity === "medium" ? "high" : severity,
|
|
5908
|
+
file: relativePath,
|
|
5909
|
+
line: region.startLine + i,
|
|
5910
|
+
message: `Hidden in comment: ${message}`,
|
|
5911
|
+
details: line.trim().substring(0, 100)
|
|
5912
|
+
});
|
|
5913
|
+
}
|
|
5914
|
+
}
|
|
5915
|
+
for (const { pattern, message, severity } of SUSPICIOUS_SCRIPT_PATTERNS) {
|
|
5916
|
+
if (pattern.test(line)) {
|
|
5917
|
+
findings.push({
|
|
5918
|
+
type: "hidden_command",
|
|
5919
|
+
severity: severity === "medium" ? "high" : severity,
|
|
5920
|
+
file: relativePath,
|
|
5921
|
+
line: region.startLine + i,
|
|
5922
|
+
message: `Hidden in comment: ${message}`,
|
|
5923
|
+
details: line.trim().substring(0, 100)
|
|
5924
|
+
});
|
|
5925
|
+
}
|
|
5926
|
+
}
|
|
5927
|
+
}
|
|
5928
|
+
}
|
|
5929
|
+
} catch {}
|
|
5930
|
+
return findings;
|
|
5931
|
+
}
|
|
5932
|
+
async function scanFileForNetworkRequests(filePath, relativePath) {
|
|
5933
|
+
const findings = [];
|
|
5934
|
+
try {
|
|
5935
|
+
const content = await readFile17(filePath, "utf-8");
|
|
5936
|
+
const lines = content.split(`
|
|
5937
|
+
`);
|
|
5938
|
+
for (let lineNum = 0;lineNum < lines.length; lineNum++) {
|
|
5939
|
+
const line = lines[lineNum];
|
|
5940
|
+
if (!line)
|
|
5941
|
+
continue;
|
|
5942
|
+
for (const { pattern, message, severity } of NETWORK_REQUEST_PATTERNS) {
|
|
5943
|
+
if (pattern.test(line)) {
|
|
5944
|
+
findings.push({
|
|
5945
|
+
type: "network_request",
|
|
5946
|
+
severity,
|
|
5947
|
+
file: relativePath,
|
|
5948
|
+
line: lineNum + 1,
|
|
5949
|
+
message,
|
|
5950
|
+
details: line.trim().substring(0, 100)
|
|
5951
|
+
});
|
|
5952
|
+
}
|
|
5953
|
+
}
|
|
5954
|
+
}
|
|
5955
|
+
} catch {}
|
|
5956
|
+
return findings;
|
|
5957
|
+
}
|
|
5696
5958
|
async function checkSymlink(symlinkPath, relativePath, capabilityRoot) {
|
|
5697
5959
|
try {
|
|
5698
5960
|
const linkTarget = await readlink(symlinkPath);
|
|
5699
|
-
const resolvedTarget = resolve2(
|
|
5961
|
+
const resolvedTarget = resolve2(join12(symlinkPath, "..", linkTarget));
|
|
5700
5962
|
const normalizedRoot = await realpath(capabilityRoot);
|
|
5701
5963
|
if (linkTarget.startsWith("/")) {
|
|
5702
5964
|
return {
|
|
@@ -5731,7 +5993,7 @@ function isTextFile(filePath) {
|
|
|
5731
5993
|
async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_SCAN_SETTINGS) {
|
|
5732
5994
|
const startTime = Date.now();
|
|
5733
5995
|
const findings = [];
|
|
5734
|
-
if (!
|
|
5996
|
+
if (!existsSync21(capabilityPath)) {
|
|
5735
5997
|
return {
|
|
5736
5998
|
capabilityId,
|
|
5737
5999
|
path: capabilityPath,
|
|
@@ -5743,7 +6005,7 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
|
|
|
5743
6005
|
async function scanDirectory(dirPath) {
|
|
5744
6006
|
const entries = await readdir2(dirPath, { withFileTypes: true });
|
|
5745
6007
|
for (const entry of entries) {
|
|
5746
|
-
const fullPath =
|
|
6008
|
+
const fullPath = join12(dirPath, entry.name);
|
|
5747
6009
|
const relativePath = relative(capabilityPath, fullPath);
|
|
5748
6010
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "__pycache__") {
|
|
5749
6011
|
continue;
|
|
@@ -5770,17 +6032,27 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
|
|
|
5770
6032
|
});
|
|
5771
6033
|
}
|
|
5772
6034
|
if (isTextFile(fullPath)) {
|
|
6035
|
+
const ext = fullPath.toLowerCase().substring(fullPath.lastIndexOf("."));
|
|
5773
6036
|
if (settings.unicode) {
|
|
5774
6037
|
const unicodeFindings = await scanFileForUnicode(fullPath, relativePath);
|
|
5775
6038
|
findings.push(...unicodeFindings);
|
|
5776
6039
|
}
|
|
5777
6040
|
if (settings.scripts) {
|
|
5778
|
-
const ext = fullPath.toLowerCase().substring(fullPath.lastIndexOf("."));
|
|
5779
6041
|
if ([".sh", ".bash", ".zsh", ".fish", ".py", ".rb", ".js", ".ts"].includes(ext)) {
|
|
5780
6042
|
const scriptFindings = await scanFileForScripts(fullPath, relativePath);
|
|
5781
6043
|
findings.push(...scriptFindings);
|
|
5782
6044
|
}
|
|
5783
6045
|
}
|
|
6046
|
+
if (settings.hiddenCommands) {
|
|
6047
|
+
if ([".md", ".txt", ".yaml", ".yml", ".toml"].includes(ext)) {
|
|
6048
|
+
const hiddenFindings = await scanFileForHiddenCommands(fullPath, relativePath);
|
|
6049
|
+
findings.push(...hiddenFindings);
|
|
6050
|
+
}
|
|
6051
|
+
}
|
|
6052
|
+
if (settings.hiddenCommands) {
|
|
6053
|
+
const networkFindings = await scanFileForNetworkRequests(fullPath, relativePath);
|
|
6054
|
+
findings.push(...networkFindings);
|
|
6055
|
+
}
|
|
5784
6056
|
}
|
|
5785
6057
|
}
|
|
5786
6058
|
}
|
|
@@ -5812,7 +6084,9 @@ async function scanCapabilities(capabilities2, config2 = {}) {
|
|
|
5812
6084
|
symlink_escape: 0,
|
|
5813
6085
|
symlink_absolute: 0,
|
|
5814
6086
|
suspicious_script: 0,
|
|
5815
|
-
binary_file: 0
|
|
6087
|
+
binary_file: 0,
|
|
6088
|
+
hidden_command: 0,
|
|
6089
|
+
network_request: 0
|
|
5816
6090
|
};
|
|
5817
6091
|
const findingsBySeverity = {
|
|
5818
6092
|
low: 0,
|
|
@@ -5887,7 +6161,7 @@ function formatScanResults(summary, verbose = false) {
|
|
|
5887
6161
|
return lines.join(`
|
|
5888
6162
|
`);
|
|
5889
6163
|
}
|
|
5890
|
-
var UNICODE_PATTERNS, SUSPICIOUS_SCRIPT_PATTERNS, BINARY_EXTENSIONS, TEXT_EXTENSIONS;
|
|
6164
|
+
var UNICODE_PATTERNS, SUSPICIOUS_SCRIPT_PATTERNS, NETWORK_REQUEST_PATTERNS, HIDDEN_COMMAND_PATTERNS, BINARY_EXTENSIONS, TEXT_EXTENSIONS, HTML_COMMENT_RE, HIDDEN_REFERENCE_RE;
|
|
5891
6165
|
var init_scanner = __esm(() => {
|
|
5892
6166
|
init_types3();
|
|
5893
6167
|
UNICODE_PATTERNS = {
|
|
@@ -5979,6 +6253,75 @@ var init_scanner = __esm(() => {
|
|
|
5979
6253
|
severity: "high"
|
|
5980
6254
|
}
|
|
5981
6255
|
];
|
|
6256
|
+
NETWORK_REQUEST_PATTERNS = [
|
|
6257
|
+
{
|
|
6258
|
+
pattern: /\bcurl\s+.*https?:\/\//i,
|
|
6259
|
+
message: "Outbound curl request detected",
|
|
6260
|
+
severity: "medium"
|
|
6261
|
+
},
|
|
6262
|
+
{
|
|
6263
|
+
pattern: /\bwget\s+.*https?:\/\//i,
|
|
6264
|
+
message: "Outbound wget request detected",
|
|
6265
|
+
severity: "medium"
|
|
6266
|
+
},
|
|
6267
|
+
{
|
|
6268
|
+
pattern: /\bfetch\s*\(\s*["'`]https?:\/\//i,
|
|
6269
|
+
message: "Outbound fetch() request detected",
|
|
6270
|
+
severity: "medium"
|
|
6271
|
+
},
|
|
6272
|
+
{
|
|
6273
|
+
pattern: /\b(?:http|https)\.(?:get|request|post|put)\s*\(/i,
|
|
6274
|
+
message: "Outbound HTTP request via Node.js http module",
|
|
6275
|
+
severity: "medium"
|
|
6276
|
+
},
|
|
6277
|
+
{
|
|
6278
|
+
pattern: /\brequests\.(?:get|post|put|delete|patch)\s*\(/i,
|
|
6279
|
+
message: "Outbound HTTP request via Python requests",
|
|
6280
|
+
severity: "medium"
|
|
6281
|
+
},
|
|
6282
|
+
{
|
|
6283
|
+
pattern: /\bnc\b.*\s\d{2,5}\b/i,
|
|
6284
|
+
message: "Netcat connection detected",
|
|
6285
|
+
severity: "high"
|
|
6286
|
+
},
|
|
6287
|
+
{
|
|
6288
|
+
pattern: /\b(?:Invoke-WebRequest|Invoke-RestMethod|iwr|irm)\b/i,
|
|
6289
|
+
message: "Outbound PowerShell web request detected",
|
|
6290
|
+
severity: "medium"
|
|
6291
|
+
}
|
|
6292
|
+
];
|
|
6293
|
+
HIDDEN_COMMAND_PATTERNS = [
|
|
6294
|
+
{
|
|
6295
|
+
pattern: /`[^`]*(?:curl|wget|bash|sh|python|ruby|node|exec|eval|system)\s[^`]*`/i,
|
|
6296
|
+
message: "Executable command in backtick-wrapped code",
|
|
6297
|
+
severity: "critical"
|
|
6298
|
+
},
|
|
6299
|
+
{
|
|
6300
|
+
pattern: /\|\s*(?:ba)?sh\b/i,
|
|
6301
|
+
message: "Pipe to shell execution",
|
|
6302
|
+
severity: "critical"
|
|
6303
|
+
},
|
|
6304
|
+
{
|
|
6305
|
+
pattern: /(?:^|\s)(?:bash|sh|zsh)\s+-c\s+/i,
|
|
6306
|
+
message: "Shell invocation with -c flag",
|
|
6307
|
+
severity: "high"
|
|
6308
|
+
},
|
|
6309
|
+
{
|
|
6310
|
+
pattern: /\b(?:curl|wget)\s+.*https?:\/\//i,
|
|
6311
|
+
message: "Network fetch command detected",
|
|
6312
|
+
severity: "high"
|
|
6313
|
+
},
|
|
6314
|
+
{
|
|
6315
|
+
pattern: /\b(?:python|ruby|node)\s+-e\s+/i,
|
|
6316
|
+
message: "Inline script execution",
|
|
6317
|
+
severity: "high"
|
|
6318
|
+
},
|
|
6319
|
+
{
|
|
6320
|
+
pattern: /\beval\s*\(.*\)/i,
|
|
6321
|
+
message: "eval() call detected",
|
|
6322
|
+
severity: "high"
|
|
6323
|
+
}
|
|
6324
|
+
];
|
|
5982
6325
|
BINARY_EXTENSIONS = new Set([
|
|
5983
6326
|
".exe",
|
|
5984
6327
|
".dll",
|
|
@@ -6013,6 +6356,8 @@ var init_scanner = __esm(() => {
|
|
|
6013
6356
|
".py",
|
|
6014
6357
|
".rb"
|
|
6015
6358
|
]);
|
|
6359
|
+
HTML_COMMENT_RE = /<!--([\s\S]*?)-->/g;
|
|
6360
|
+
HIDDEN_REFERENCE_RE = /^\[.*?\]:\s*\S+\s+"(.+)"/gm;
|
|
6016
6361
|
});
|
|
6017
6362
|
|
|
6018
6363
|
// ../core/src/security/index.ts
|
|
@@ -6023,7 +6368,9 @@ var init_security = __esm(() => {
|
|
|
6023
6368
|
|
|
6024
6369
|
// ../core/src/templates/agents.ts
|
|
6025
6370
|
function generateAgentsTemplate() {
|
|
6026
|
-
return
|
|
6371
|
+
return `> IMPORTANT: Do not edit this file directly. Edit \`OMNI.md\` instead. This file is a generated copy of \`OMNI.md\` and is ephemeral. Any persistent change must be made in \`OMNI.md\`.
|
|
6372
|
+
|
|
6373
|
+
# Project Instructions
|
|
6027
6374
|
|
|
6028
6375
|
<!-- Add your project-specific instructions here -->
|
|
6029
6376
|
|
|
@@ -6150,7 +6497,9 @@ function formatDisplayName(kebabCase) {
|
|
|
6150
6497
|
|
|
6151
6498
|
// ../core/src/templates/claude.ts
|
|
6152
6499
|
function generateClaudeTemplate() {
|
|
6153
|
-
return
|
|
6500
|
+
return `> IMPORTANT: Do not edit this file directly. Edit \`OMNI.md\` instead. This file is a generated copy of \`OMNI.md\` and is ephemeral. Any persistent change must be made in \`OMNI.md\`.
|
|
6501
|
+
|
|
6502
|
+
# Project Instructions
|
|
6154
6503
|
|
|
6155
6504
|
<!-- Add your project-specific instructions here -->
|
|
6156
6505
|
`;
|
|
@@ -6222,6 +6571,7 @@ __export(exports_src, {
|
|
|
6222
6571
|
resolveEnabledCapabilities: () => resolveEnabledCapabilities,
|
|
6223
6572
|
resolveCapabilityRootInConfig: () => resolveCapabilityRootInConfig,
|
|
6224
6573
|
resolveCapabilityRoot: () => resolveCapabilityRoot,
|
|
6574
|
+
resolveCapabilityInstallCommand: () => resolveCapabilityInstallCommand,
|
|
6225
6575
|
removeSecurityAllow: () => removeSecurityAllow,
|
|
6226
6576
|
readSecurityAllows: () => readSecurityAllows,
|
|
6227
6577
|
readMcpJson: () => readMcpJson,
|
|
@@ -6273,6 +6623,7 @@ __export(exports_src, {
|
|
|
6273
6623
|
hasAnyHooks: () => hasAnyHooks,
|
|
6274
6624
|
getVersion: () => getVersion,
|
|
6275
6625
|
getSourceCapabilityPath: () => getSourceCapabilityPath,
|
|
6626
|
+
getProviderManagedOutputs: () => getProviderManagedOutputs,
|
|
6276
6627
|
getLockFilePath: () => getLockFilePath,
|
|
6277
6628
|
getHooksDirectory: () => getHooksDirectory,
|
|
6278
6629
|
getHooksConfigPath: () => getHooksConfigPath,
|
|
@@ -6310,6 +6661,7 @@ __export(exports_src, {
|
|
|
6310
6661
|
clearAllSecurityAllows: () => clearAllSecurityAllows,
|
|
6311
6662
|
clearActiveProfileState: () => clearActiveProfileState,
|
|
6312
6663
|
cleanupStaleResources: () => cleanupStaleResources,
|
|
6664
|
+
cleanupStaleManagedOutputs: () => cleanupStaleManagedOutputs,
|
|
6313
6665
|
checkVersionMismatch: () => checkVersionMismatch,
|
|
6314
6666
|
checkForUpdates: () => checkForUpdates,
|
|
6315
6667
|
buildSyncBundle: () => buildSyncBundle,
|
|
@@ -6353,15 +6705,33 @@ var init_src = __esm(() => {
|
|
|
6353
6705
|
import { run } from "@stricli/core";
|
|
6354
6706
|
|
|
6355
6707
|
// src/lib/dynamic-app.ts
|
|
6356
|
-
import { existsSync as
|
|
6708
|
+
import { existsSync as existsSync32 } from "node:fs";
|
|
6357
6709
|
import { createRequire as createRequire2 } from "node:module";
|
|
6358
|
-
import { join as
|
|
6710
|
+
import { join as join29 } from "node:path";
|
|
6359
6711
|
import { buildApplication, buildRouteMap as buildRouteMap7 } from "@stricli/core";
|
|
6360
6712
|
|
|
6361
6713
|
// src/commands/add.ts
|
|
6362
|
-
import { existsSync as
|
|
6714
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
6363
6715
|
import { basename as basename5, resolve as resolve3 } from "node:path";
|
|
6364
6716
|
|
|
6717
|
+
// ../adapters/src/writers/generic/managed-outputs.ts
|
|
6718
|
+
import { createHash } from "node:crypto";
|
|
6719
|
+
function hashContent(content) {
|
|
6720
|
+
return createHash("sha256").update(content).digest("hex");
|
|
6721
|
+
}
|
|
6722
|
+
function trimTrailingSlash(path) {
|
|
6723
|
+
return path.endsWith("/") ? path.slice(0, -1) : path;
|
|
6724
|
+
}
|
|
6725
|
+
function createManagedOutput(path, writerId, content, options) {
|
|
6726
|
+
return {
|
|
6727
|
+
path,
|
|
6728
|
+
writerId,
|
|
6729
|
+
hash: hashContent(content),
|
|
6730
|
+
cleanupStrategy: options?.cleanupStrategy ?? "delete-file",
|
|
6731
|
+
...options?.pruneRoot ? { pruneRoot: trimTrailingSlash(options.pruneRoot) } : {},
|
|
6732
|
+
...options?.jsonKey ? { jsonKey: options.jsonKey } : {}
|
|
6733
|
+
};
|
|
6734
|
+
}
|
|
6365
6735
|
// ../adapters/src/writers/generic/executor.ts
|
|
6366
6736
|
async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
|
|
6367
6737
|
const seen = new Set;
|
|
@@ -6377,6 +6747,7 @@ async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
|
|
|
6377
6747
|
uniqueConfigs.push(config);
|
|
6378
6748
|
}
|
|
6379
6749
|
const allFilesWritten = [];
|
|
6750
|
+
const allManagedOutputs = [];
|
|
6380
6751
|
for (const config of uniqueConfigs) {
|
|
6381
6752
|
const result = await config.writer.write(bundle, {
|
|
6382
6753
|
outputPath: config.outputPath,
|
|
@@ -6384,29 +6755,31 @@ async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
|
|
|
6384
6755
|
...providerId ? { providerId } : {}
|
|
6385
6756
|
});
|
|
6386
6757
|
allFilesWritten.push(...result.filesWritten);
|
|
6758
|
+
allManagedOutputs.push(...result.managedOutputs ?? []);
|
|
6387
6759
|
}
|
|
6388
6760
|
return {
|
|
6389
6761
|
filesWritten: allFilesWritten,
|
|
6390
|
-
deduplicatedCount
|
|
6762
|
+
deduplicatedCount,
|
|
6763
|
+
managedOutputs: allManagedOutputs
|
|
6391
6764
|
};
|
|
6392
6765
|
}
|
|
6393
6766
|
// ../adapters/src/writers/generic/hooks.ts
|
|
6394
6767
|
init_src();
|
|
6395
|
-
import { existsSync as
|
|
6768
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
6396
6769
|
import { mkdir as mkdir2, readFile as readFile18, writeFile as writeFile10 } from "node:fs/promises";
|
|
6397
|
-
import { dirname, join as
|
|
6770
|
+
import { dirname as dirname2, join as join13 } from "node:path";
|
|
6398
6771
|
var HooksWriter = {
|
|
6399
6772
|
id: "hooks",
|
|
6400
6773
|
async write(bundle, ctx) {
|
|
6401
6774
|
if (!bundle.hooks) {
|
|
6402
6775
|
return { filesWritten: [] };
|
|
6403
6776
|
}
|
|
6404
|
-
const settingsPath =
|
|
6405
|
-
const parentDir =
|
|
6777
|
+
const settingsPath = join13(ctx.projectRoot, ctx.outputPath);
|
|
6778
|
+
const parentDir = dirname2(settingsPath);
|
|
6406
6779
|
await mkdir2(parentDir, { recursive: true });
|
|
6407
6780
|
const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
|
|
6408
6781
|
let existingSettings = {};
|
|
6409
|
-
if (
|
|
6782
|
+
if (existsSync22(settingsPath)) {
|
|
6410
6783
|
try {
|
|
6411
6784
|
const content = await readFile18(settingsPath, "utf-8");
|
|
6412
6785
|
existingSettings = JSON.parse(content);
|
|
@@ -6421,14 +6794,20 @@ var HooksWriter = {
|
|
|
6421
6794
|
await writeFile10(settingsPath, `${JSON.stringify(newSettings, null, 2)}
|
|
6422
6795
|
`, "utf-8");
|
|
6423
6796
|
return {
|
|
6424
|
-
filesWritten: [ctx.outputPath]
|
|
6797
|
+
filesWritten: [ctx.outputPath],
|
|
6798
|
+
managedOutputs: [
|
|
6799
|
+
createManagedOutput(ctx.outputPath, this.id, JSON.stringify(claudeHooks), {
|
|
6800
|
+
cleanupStrategy: "remove-json-key",
|
|
6801
|
+
jsonKey: "hooks"
|
|
6802
|
+
})
|
|
6803
|
+
]
|
|
6425
6804
|
};
|
|
6426
6805
|
}
|
|
6427
6806
|
};
|
|
6428
6807
|
// ../adapters/src/writers/generic/instructions-md.ts
|
|
6429
|
-
import { existsSync as
|
|
6808
|
+
import { existsSync as existsSync23 } from "node:fs";
|
|
6430
6809
|
import { mkdir as mkdir3, readFile as readFile19, writeFile as writeFile11 } from "node:fs/promises";
|
|
6431
|
-
import { dirname as
|
|
6810
|
+
import { dirname as dirname3, join as join14 } from "node:path";
|
|
6432
6811
|
|
|
6433
6812
|
// ../adapters/src/writers/generic/omni-md.ts
|
|
6434
6813
|
init_src();
|
|
@@ -6450,20 +6829,32 @@ function renderOmniMdForProvider(content, providerId) {
|
|
|
6450
6829
|
}
|
|
6451
6830
|
|
|
6452
6831
|
// ../adapters/src/writers/generic/instructions-md.ts
|
|
6832
|
+
function getGeneratedCopyNotice(outputPath) {
|
|
6833
|
+
if (outputPath !== "AGENTS.md" && outputPath !== "CLAUDE.md") {
|
|
6834
|
+
return "";
|
|
6835
|
+
}
|
|
6836
|
+
return "> IMPORTANT: Do not edit this file directly. Edit `OMNI.md` instead. This file is a generated copy of `OMNI.md` and is ephemeral. Any persistent change must be made in `OMNI.md`.";
|
|
6837
|
+
}
|
|
6453
6838
|
var InstructionsMdWriter = {
|
|
6454
6839
|
id: "instructions-md",
|
|
6455
6840
|
async write(bundle, ctx) {
|
|
6456
|
-
const outputFullPath =
|
|
6457
|
-
const parentDir =
|
|
6841
|
+
const outputFullPath = join14(ctx.projectRoot, ctx.outputPath);
|
|
6842
|
+
const parentDir = dirname3(outputFullPath);
|
|
6458
6843
|
if (parentDir !== ctx.projectRoot) {
|
|
6459
6844
|
await mkdir3(parentDir, { recursive: true });
|
|
6460
6845
|
}
|
|
6461
|
-
const omniMdPath =
|
|
6846
|
+
const omniMdPath = join14(ctx.projectRoot, "OMNI.md");
|
|
6462
6847
|
let omniMdContent = "";
|
|
6463
|
-
if (
|
|
6848
|
+
if (existsSync23(omniMdPath)) {
|
|
6464
6849
|
omniMdContent = renderOmniMdForProvider(await readFile19(omniMdPath, "utf-8"), ctx.providerId);
|
|
6465
6850
|
}
|
|
6466
6851
|
let content = omniMdContent;
|
|
6852
|
+
const generatedCopyNotice = getGeneratedCopyNotice(ctx.outputPath);
|
|
6853
|
+
if (generatedCopyNotice) {
|
|
6854
|
+
content = content ? `${generatedCopyNotice}
|
|
6855
|
+
|
|
6856
|
+
${content}` : generatedCopyNotice;
|
|
6857
|
+
}
|
|
6467
6858
|
if (bundle.instructionsContent) {
|
|
6468
6859
|
content += `
|
|
6469
6860
|
|
|
@@ -6472,23 +6863,30 @@ ${bundle.instructionsContent}
|
|
|
6472
6863
|
}
|
|
6473
6864
|
await writeFile11(outputFullPath, content, "utf-8");
|
|
6474
6865
|
return {
|
|
6475
|
-
filesWritten: [ctx.outputPath]
|
|
6866
|
+
filesWritten: [ctx.outputPath],
|
|
6867
|
+
managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
|
|
6476
6868
|
};
|
|
6477
6869
|
}
|
|
6478
6870
|
};
|
|
6479
6871
|
// ../adapters/src/writers/generic/skills.ts
|
|
6480
|
-
import { mkdir as mkdir4, writeFile as writeFile12 } from "node:fs/promises";
|
|
6481
|
-
import { join as
|
|
6872
|
+
import { cp as cp2, mkdir as mkdir4, readdir as readdir3, rm as rm2, writeFile as writeFile12 } from "node:fs/promises";
|
|
6873
|
+
import { join as join15, relative as relative2 } from "node:path";
|
|
6482
6874
|
var SkillsWriter = {
|
|
6483
6875
|
id: "skills",
|
|
6484
6876
|
async write(bundle, ctx) {
|
|
6485
|
-
const skillsDir =
|
|
6877
|
+
const skillsDir = join15(ctx.projectRoot, ctx.outputPath);
|
|
6486
6878
|
await mkdir4(skillsDir, { recursive: true });
|
|
6487
6879
|
const filesWritten = [];
|
|
6880
|
+
const managedOutputs = [];
|
|
6488
6881
|
for (const skill of bundle.skills) {
|
|
6489
|
-
const skillDir =
|
|
6490
|
-
await
|
|
6491
|
-
|
|
6882
|
+
const skillDir = join15(skillsDir, skill.name);
|
|
6883
|
+
await rm2(skillDir, { recursive: true, force: true });
|
|
6884
|
+
if (skill.sourcePath) {
|
|
6885
|
+
await cp2(skill.sourcePath, skillDir, { recursive: true });
|
|
6886
|
+
} else {
|
|
6887
|
+
await mkdir4(skillDir, { recursive: true });
|
|
6888
|
+
}
|
|
6889
|
+
const skillPath = join15(skillDir, "SKILL.md");
|
|
6492
6890
|
const content = `---
|
|
6493
6891
|
name: ${skill.name}
|
|
6494
6892
|
description: "${skill.description}"
|
|
@@ -6496,16 +6894,43 @@ description: "${skill.description}"
|
|
|
6496
6894
|
|
|
6497
6895
|
${skill.instructions}`;
|
|
6498
6896
|
await writeFile12(skillPath, content, "utf-8");
|
|
6499
|
-
|
|
6897
|
+
const relativePaths = skill.sourcePath ? await listRelativeFiles(skillDir) : ["SKILL.md"];
|
|
6898
|
+
for (const relativeFile of relativePaths) {
|
|
6899
|
+
filesWritten.push(join15(ctx.outputPath, skill.name, relativeFile));
|
|
6900
|
+
}
|
|
6901
|
+
const relativePath = join15(ctx.outputPath, skill.name, "SKILL.md");
|
|
6902
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content, {
|
|
6903
|
+
cleanupStrategy: "delete-file-and-prune-empty-parents",
|
|
6904
|
+
pruneRoot: ctx.outputPath
|
|
6905
|
+
}));
|
|
6500
6906
|
}
|
|
6501
6907
|
return {
|
|
6502
|
-
filesWritten
|
|
6908
|
+
filesWritten,
|
|
6909
|
+
managedOutputs
|
|
6503
6910
|
};
|
|
6504
6911
|
}
|
|
6505
6912
|
};
|
|
6913
|
+
async function listRelativeFiles(basePath) {
|
|
6914
|
+
const files = [];
|
|
6915
|
+
const entries = await readdir3(basePath, { withFileTypes: true });
|
|
6916
|
+
for (const entry of entries) {
|
|
6917
|
+
const entryPath = join15(basePath, entry.name);
|
|
6918
|
+
if (entry.isDirectory()) {
|
|
6919
|
+
const nestedFiles = await listRelativeFiles(entryPath);
|
|
6920
|
+
for (const nestedFile of nestedFiles) {
|
|
6921
|
+
files.push(relative2(basePath, join15(entryPath, nestedFile)));
|
|
6922
|
+
}
|
|
6923
|
+
continue;
|
|
6924
|
+
}
|
|
6925
|
+
if (entry.isFile()) {
|
|
6926
|
+
files.push(entry.name);
|
|
6927
|
+
}
|
|
6928
|
+
}
|
|
6929
|
+
return files.sort((a, b) => a.localeCompare(b));
|
|
6930
|
+
}
|
|
6506
6931
|
// ../adapters/src/writers/generic/commands-as-skills.ts
|
|
6507
6932
|
import { mkdir as mkdir5, writeFile as writeFile13 } from "node:fs/promises";
|
|
6508
|
-
import { join as
|
|
6933
|
+
import { join as join16 } from "node:path";
|
|
6509
6934
|
function generateSkillFrontmatter(command) {
|
|
6510
6935
|
const lines = ["---"];
|
|
6511
6936
|
lines.push(`name: ${command.name}`);
|
|
@@ -6520,22 +6945,29 @@ function generateSkillFrontmatter(command) {
|
|
|
6520
6945
|
var CommandsAsSkillsWriter = {
|
|
6521
6946
|
id: "commands-as-skills",
|
|
6522
6947
|
async write(bundle, ctx) {
|
|
6523
|
-
const skillsDir =
|
|
6948
|
+
const skillsDir = join16(ctx.projectRoot, ctx.outputPath);
|
|
6524
6949
|
await mkdir5(skillsDir, { recursive: true });
|
|
6525
6950
|
const filesWritten = [];
|
|
6951
|
+
const managedOutputs = [];
|
|
6526
6952
|
for (const command of bundle.commands) {
|
|
6527
|
-
const commandSkillDir =
|
|
6953
|
+
const commandSkillDir = join16(skillsDir, command.name);
|
|
6528
6954
|
await mkdir5(commandSkillDir, { recursive: true });
|
|
6529
6955
|
const frontmatter = generateSkillFrontmatter(command);
|
|
6530
6956
|
const content = `${frontmatter}
|
|
6531
6957
|
|
|
6532
6958
|
${command.prompt}`;
|
|
6533
|
-
const skillPath =
|
|
6959
|
+
const skillPath = join16(commandSkillDir, "SKILL.md");
|
|
6534
6960
|
await writeFile13(skillPath, content, "utf-8");
|
|
6535
|
-
|
|
6961
|
+
const relativePath = join16(ctx.outputPath, command.name, "SKILL.md");
|
|
6962
|
+
filesWritten.push(relativePath);
|
|
6963
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content, {
|
|
6964
|
+
cleanupStrategy: "delete-file-and-prune-empty-parents",
|
|
6965
|
+
pruneRoot: ctx.outputPath
|
|
6966
|
+
}));
|
|
6536
6967
|
}
|
|
6537
6968
|
return {
|
|
6538
|
-
filesWritten
|
|
6969
|
+
filesWritten,
|
|
6970
|
+
managedOutputs
|
|
6539
6971
|
};
|
|
6540
6972
|
}
|
|
6541
6973
|
};
|
|
@@ -6588,7 +7020,7 @@ function createProviderScopedBundle(bundle, providerId) {
|
|
|
6588
7020
|
|
|
6589
7021
|
// ../adapters/src/writers/claude/agents.ts
|
|
6590
7022
|
import { mkdir as mkdir6, writeFile as writeFile14 } from "node:fs/promises";
|
|
6591
|
-
import { join as
|
|
7023
|
+
import { join as join17 } from "node:path";
|
|
6592
7024
|
function generateFrontmatter(agent) {
|
|
6593
7025
|
const lines = ["---"];
|
|
6594
7026
|
lines.push(`name: ${agent.name}`);
|
|
@@ -6615,20 +7047,24 @@ function generateFrontmatter(agent) {
|
|
|
6615
7047
|
var ClaudeAgentsWriter = {
|
|
6616
7048
|
id: "claude-agents",
|
|
6617
7049
|
async write(bundle, ctx) {
|
|
6618
|
-
const agentsDir =
|
|
7050
|
+
const agentsDir = join17(ctx.projectRoot, ctx.outputPath);
|
|
6619
7051
|
await mkdir6(agentsDir, { recursive: true });
|
|
6620
7052
|
const filesWritten = [];
|
|
7053
|
+
const managedOutputs = [];
|
|
6621
7054
|
for (const agent of bundle.subagents) {
|
|
6622
7055
|
const frontmatter = generateFrontmatter(agent);
|
|
6623
7056
|
const content = `${frontmatter}
|
|
6624
7057
|
|
|
6625
7058
|
${agent.systemPrompt}`;
|
|
6626
|
-
const agentPath =
|
|
7059
|
+
const agentPath = join17(agentsDir, `${agent.name}.md`);
|
|
6627
7060
|
await writeFile14(agentPath, content, "utf-8");
|
|
6628
|
-
|
|
7061
|
+
const relativePath = join17(ctx.outputPath, `${agent.name}.md`);
|
|
7062
|
+
filesWritten.push(relativePath);
|
|
7063
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
6629
7064
|
}
|
|
6630
7065
|
return {
|
|
6631
|
-
filesWritten
|
|
7066
|
+
filesWritten,
|
|
7067
|
+
managedOutputs
|
|
6632
7068
|
};
|
|
6633
7069
|
}
|
|
6634
7070
|
};
|
|
@@ -6655,18 +7091,19 @@ var claudeCodeAdapter = {
|
|
|
6655
7091
|
const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
|
|
6656
7092
|
return {
|
|
6657
7093
|
filesWritten: result.filesWritten,
|
|
6658
|
-
filesDeleted: []
|
|
7094
|
+
filesDeleted: [],
|
|
7095
|
+
managedOutputs: result.managedOutputs
|
|
6659
7096
|
};
|
|
6660
7097
|
}
|
|
6661
7098
|
};
|
|
6662
7099
|
// ../adapters/src/codex/index.ts
|
|
6663
7100
|
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
6664
|
-
import { join as
|
|
7101
|
+
import { join as join19 } from "node:path";
|
|
6665
7102
|
|
|
6666
7103
|
// ../adapters/src/writers/codex/toml.ts
|
|
6667
7104
|
init_dist();
|
|
6668
7105
|
import { mkdir as mkdir7, writeFile as writeFile15 } from "node:fs/promises";
|
|
6669
|
-
import { dirname as
|
|
7106
|
+
import { dirname as dirname4, join as join18 } from "node:path";
|
|
6670
7107
|
var FILE_HEADER = `# Generated by OmniDev - DO NOT EDIT
|
|
6671
7108
|
# Run \`omnidev sync\` to regenerate
|
|
6672
7109
|
|
|
@@ -6717,8 +7154,8 @@ var CodexTomlWriter = {
|
|
|
6717
7154
|
if (mcps.size === 0) {
|
|
6718
7155
|
return { filesWritten: [] };
|
|
6719
7156
|
}
|
|
6720
|
-
const configPath =
|
|
6721
|
-
const parentDir =
|
|
7157
|
+
const configPath = join18(ctx.projectRoot, ctx.outputPath);
|
|
7158
|
+
const parentDir = dirname4(configPath);
|
|
6722
7159
|
await mkdir7(parentDir, { recursive: true });
|
|
6723
7160
|
const mcpServers = {};
|
|
6724
7161
|
for (const [id, mcp] of mcps) {
|
|
@@ -6736,7 +7173,8 @@ var CodexTomlWriter = {
|
|
|
6736
7173
|
const tomlContent = FILE_HEADER + stringify(codexConfig);
|
|
6737
7174
|
await writeFile15(configPath, tomlContent, "utf-8");
|
|
6738
7175
|
return {
|
|
6739
|
-
filesWritten: [ctx.outputPath]
|
|
7176
|
+
filesWritten: [ctx.outputPath],
|
|
7177
|
+
managedOutputs: [createManagedOutput(ctx.outputPath, this.id, tomlContent)]
|
|
6740
7178
|
};
|
|
6741
7179
|
}
|
|
6742
7180
|
};
|
|
@@ -6751,7 +7189,7 @@ var codexAdapter = {
|
|
|
6751
7189
|
{ writer: CodexTomlWriter, outputPath: ".codex/config.toml" }
|
|
6752
7190
|
],
|
|
6753
7191
|
async init(ctx) {
|
|
6754
|
-
const codexDir =
|
|
7192
|
+
const codexDir = join19(ctx.projectRoot, ".codex");
|
|
6755
7193
|
mkdirSync6(codexDir, { recursive: true });
|
|
6756
7194
|
return {
|
|
6757
7195
|
filesCreated: [".codex/"],
|
|
@@ -6764,17 +7202,18 @@ var codexAdapter = {
|
|
|
6764
7202
|
const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
|
|
6765
7203
|
return {
|
|
6766
7204
|
filesWritten: result.filesWritten,
|
|
6767
|
-
filesDeleted: []
|
|
7205
|
+
filesDeleted: [],
|
|
7206
|
+
managedOutputs: result.managedOutputs
|
|
6768
7207
|
};
|
|
6769
7208
|
}
|
|
6770
7209
|
};
|
|
6771
7210
|
// ../adapters/src/cursor/index.ts
|
|
6772
7211
|
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
6773
|
-
import { join as
|
|
7212
|
+
import { join as join24 } from "node:path";
|
|
6774
7213
|
|
|
6775
7214
|
// ../adapters/src/writers/cursor/agents.ts
|
|
6776
7215
|
import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
|
|
6777
|
-
import { join as
|
|
7216
|
+
import { join as join20 } from "node:path";
|
|
6778
7217
|
function mapModelToCursor(model) {
|
|
6779
7218
|
if (!model || model === "inherit")
|
|
6780
7219
|
return "inherit";
|
|
@@ -6806,50 +7245,58 @@ function generateFrontmatter2(agent) {
|
|
|
6806
7245
|
var CursorAgentsWriter = {
|
|
6807
7246
|
id: "cursor-agents",
|
|
6808
7247
|
async write(bundle, ctx) {
|
|
6809
|
-
const agentsDir =
|
|
7248
|
+
const agentsDir = join20(ctx.projectRoot, ctx.outputPath);
|
|
6810
7249
|
await mkdir8(agentsDir, { recursive: true });
|
|
6811
7250
|
const filesWritten = [];
|
|
7251
|
+
const managedOutputs = [];
|
|
6812
7252
|
for (const agent of bundle.subagents) {
|
|
6813
7253
|
const frontmatter = generateFrontmatter2(agent);
|
|
6814
7254
|
const content = `${frontmatter}
|
|
6815
7255
|
|
|
6816
7256
|
${agent.systemPrompt}`;
|
|
6817
|
-
const agentPath =
|
|
7257
|
+
const agentPath = join20(agentsDir, `${agent.name}.md`);
|
|
6818
7258
|
await writeFile16(agentPath, content, "utf-8");
|
|
6819
|
-
|
|
7259
|
+
const relativePath = join20(ctx.outputPath, `${agent.name}.md`);
|
|
7260
|
+
filesWritten.push(relativePath);
|
|
7261
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
6820
7262
|
}
|
|
6821
7263
|
return {
|
|
6822
|
-
filesWritten
|
|
7264
|
+
filesWritten,
|
|
7265
|
+
managedOutputs
|
|
6823
7266
|
};
|
|
6824
7267
|
}
|
|
6825
7268
|
};
|
|
6826
7269
|
// ../adapters/src/writers/cursor/commands.ts
|
|
6827
7270
|
import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
|
|
6828
|
-
import { join as
|
|
7271
|
+
import { join as join21 } from "node:path";
|
|
6829
7272
|
var CursorCommandsWriter = {
|
|
6830
7273
|
id: "cursor-commands",
|
|
6831
7274
|
async write(bundle, ctx) {
|
|
6832
|
-
const commandsDir =
|
|
7275
|
+
const commandsDir = join21(ctx.projectRoot, ctx.outputPath);
|
|
6833
7276
|
await mkdir9(commandsDir, { recursive: true });
|
|
6834
7277
|
const filesWritten = [];
|
|
7278
|
+
const managedOutputs = [];
|
|
6835
7279
|
for (const command of bundle.commands) {
|
|
6836
7280
|
const content = `# ${command.name}
|
|
6837
7281
|
|
|
6838
7282
|
${command.description}
|
|
6839
7283
|
|
|
6840
7284
|
${command.prompt}`;
|
|
6841
|
-
const commandPath =
|
|
7285
|
+
const commandPath = join21(commandsDir, `${command.name}.md`);
|
|
6842
7286
|
await writeFile17(commandPath, content, "utf-8");
|
|
6843
|
-
|
|
7287
|
+
const relativePath = join21(ctx.outputPath, `${command.name}.md`);
|
|
7288
|
+
filesWritten.push(relativePath);
|
|
7289
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
6844
7290
|
}
|
|
6845
7291
|
return {
|
|
6846
|
-
filesWritten
|
|
7292
|
+
filesWritten,
|
|
7293
|
+
managedOutputs
|
|
6847
7294
|
};
|
|
6848
7295
|
}
|
|
6849
7296
|
};
|
|
6850
7297
|
// ../adapters/src/writers/cursor/mcp-json.ts
|
|
6851
7298
|
import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
|
|
6852
|
-
import { dirname as
|
|
7299
|
+
import { dirname as dirname5, join as join22 } from "node:path";
|
|
6853
7300
|
function buildCursorMcpConfig(mcp) {
|
|
6854
7301
|
const transport = mcp.transport ?? "stdio";
|
|
6855
7302
|
if (transport === "http" || transport === "sse") {
|
|
@@ -6894,8 +7341,8 @@ var CursorMcpJsonWriter = {
|
|
|
6894
7341
|
if (mcps.size === 0) {
|
|
6895
7342
|
return { filesWritten: [] };
|
|
6896
7343
|
}
|
|
6897
|
-
const configPath =
|
|
6898
|
-
const parentDir =
|
|
7344
|
+
const configPath = join22(ctx.projectRoot, ctx.outputPath);
|
|
7345
|
+
const parentDir = dirname5(configPath);
|
|
6899
7346
|
await mkdir10(parentDir, { recursive: true });
|
|
6900
7347
|
const mcpServers = {};
|
|
6901
7348
|
for (const [id, mcp] of mcps) {
|
|
@@ -6910,29 +7357,35 @@ var CursorMcpJsonWriter = {
|
|
|
6910
7357
|
const cursorMcpJson = {
|
|
6911
7358
|
mcpServers
|
|
6912
7359
|
};
|
|
6913
|
-
|
|
6914
|
-
|
|
7360
|
+
const content = `${JSON.stringify(cursorMcpJson, null, 2)}
|
|
7361
|
+
`;
|
|
7362
|
+
await writeFile18(configPath, content, "utf-8");
|
|
6915
7363
|
return {
|
|
6916
|
-
filesWritten: [ctx.outputPath]
|
|
7364
|
+
filesWritten: [ctx.outputPath],
|
|
7365
|
+
managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
|
|
6917
7366
|
};
|
|
6918
7367
|
}
|
|
6919
7368
|
};
|
|
6920
7369
|
// ../adapters/src/writers/cursor/rules.ts
|
|
6921
7370
|
import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
|
|
6922
|
-
import { join as
|
|
7371
|
+
import { join as join23 } from "node:path";
|
|
6923
7372
|
var CursorRulesWriter = {
|
|
6924
7373
|
id: "cursor-rules",
|
|
6925
7374
|
async write(bundle, ctx) {
|
|
6926
|
-
const rulesDir =
|
|
7375
|
+
const rulesDir = join23(ctx.projectRoot, ctx.outputPath);
|
|
6927
7376
|
await mkdir11(rulesDir, { recursive: true });
|
|
6928
7377
|
const filesWritten = [];
|
|
7378
|
+
const managedOutputs = [];
|
|
6929
7379
|
for (const rule of bundle.rules) {
|
|
6930
|
-
const rulePath =
|
|
7380
|
+
const rulePath = join23(rulesDir, `omnidev-${rule.name}.mdc`);
|
|
6931
7381
|
await writeFile19(rulePath, rule.content, "utf-8");
|
|
6932
|
-
|
|
7382
|
+
const relativePath = join23(ctx.outputPath, `omnidev-${rule.name}.mdc`);
|
|
7383
|
+
filesWritten.push(relativePath);
|
|
7384
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, rule.content));
|
|
6933
7385
|
}
|
|
6934
7386
|
return {
|
|
6935
|
-
filesWritten
|
|
7387
|
+
filesWritten,
|
|
7388
|
+
managedOutputs
|
|
6936
7389
|
};
|
|
6937
7390
|
}
|
|
6938
7391
|
};
|
|
@@ -6949,7 +7402,7 @@ var cursorAdapter = {
|
|
|
6949
7402
|
{ writer: CursorMcpJsonWriter, outputPath: ".cursor/mcp.json" }
|
|
6950
7403
|
],
|
|
6951
7404
|
async init(ctx) {
|
|
6952
|
-
const rulesDir =
|
|
7405
|
+
const rulesDir = join24(ctx.projectRoot, ".cursor", "rules");
|
|
6953
7406
|
mkdirSync7(rulesDir, { recursive: true });
|
|
6954
7407
|
return {
|
|
6955
7408
|
filesCreated: [".cursor/rules/"],
|
|
@@ -6969,17 +7422,18 @@ var cursorAdapter = {
|
|
|
6969
7422
|
filesWritten: [
|
|
6970
7423
|
...new Set([...instructionsResult.filesWritten, ...cursorResult.filesWritten])
|
|
6971
7424
|
],
|
|
6972
|
-
filesDeleted: []
|
|
7425
|
+
filesDeleted: [],
|
|
7426
|
+
managedOutputs: [...instructionsResult.managedOutputs, ...cursorResult.managedOutputs]
|
|
6973
7427
|
};
|
|
6974
7428
|
}
|
|
6975
7429
|
};
|
|
6976
7430
|
// ../adapters/src/opencode/index.ts
|
|
6977
7431
|
import { mkdirSync as mkdirSync8 } from "node:fs";
|
|
6978
|
-
import { join as
|
|
7432
|
+
import { join as join27 } from "node:path";
|
|
6979
7433
|
|
|
6980
7434
|
// ../adapters/src/writers/opencode/agents.ts
|
|
6981
7435
|
import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
|
|
6982
|
-
import { join as
|
|
7436
|
+
import { join as join25 } from "node:path";
|
|
6983
7437
|
function mapModelToOpenCode(model) {
|
|
6984
7438
|
if (!model || model === "inherit")
|
|
6985
7439
|
return;
|
|
@@ -7057,26 +7511,30 @@ function generateFrontmatter3(agent) {
|
|
|
7057
7511
|
var OpenCodeAgentsWriter = {
|
|
7058
7512
|
id: "opencode-agents",
|
|
7059
7513
|
async write(bundle, ctx) {
|
|
7060
|
-
const agentsDir =
|
|
7514
|
+
const agentsDir = join25(ctx.projectRoot, ctx.outputPath);
|
|
7061
7515
|
await mkdir12(agentsDir, { recursive: true });
|
|
7062
7516
|
const filesWritten = [];
|
|
7517
|
+
const managedOutputs = [];
|
|
7063
7518
|
for (const agent of bundle.subagents) {
|
|
7064
7519
|
const frontmatter = generateFrontmatter3(agent);
|
|
7065
7520
|
const content = `${frontmatter}
|
|
7066
7521
|
|
|
7067
7522
|
${agent.systemPrompt}`;
|
|
7068
|
-
const agentPath =
|
|
7523
|
+
const agentPath = join25(agentsDir, `${agent.name}.md`);
|
|
7069
7524
|
await writeFile20(agentPath, content, "utf-8");
|
|
7070
|
-
|
|
7525
|
+
const relativePath = join25(ctx.outputPath, `${agent.name}.md`);
|
|
7526
|
+
filesWritten.push(relativePath);
|
|
7527
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
7071
7528
|
}
|
|
7072
7529
|
return {
|
|
7073
|
-
filesWritten
|
|
7530
|
+
filesWritten,
|
|
7531
|
+
managedOutputs
|
|
7074
7532
|
};
|
|
7075
7533
|
}
|
|
7076
7534
|
};
|
|
7077
7535
|
// ../adapters/src/writers/opencode/commands.ts
|
|
7078
7536
|
import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
|
|
7079
|
-
import { join as
|
|
7537
|
+
import { join as join26 } from "node:path";
|
|
7080
7538
|
function generateFrontmatter4(command) {
|
|
7081
7539
|
const lines = ["---"];
|
|
7082
7540
|
lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
|
|
@@ -7093,20 +7551,24 @@ function generateFrontmatter4(command) {
|
|
|
7093
7551
|
var OpenCodeCommandsWriter = {
|
|
7094
7552
|
id: "opencode-commands",
|
|
7095
7553
|
async write(bundle, ctx) {
|
|
7096
|
-
const commandsDir =
|
|
7554
|
+
const commandsDir = join26(ctx.projectRoot, ctx.outputPath);
|
|
7097
7555
|
await mkdir13(commandsDir, { recursive: true });
|
|
7098
7556
|
const filesWritten = [];
|
|
7557
|
+
const managedOutputs = [];
|
|
7099
7558
|
for (const command of bundle.commands) {
|
|
7100
7559
|
const frontmatter = generateFrontmatter4(command);
|
|
7101
7560
|
const content = `${frontmatter}
|
|
7102
7561
|
|
|
7103
7562
|
${command.prompt}`;
|
|
7104
|
-
const commandPath =
|
|
7563
|
+
const commandPath = join26(commandsDir, `${command.name}.md`);
|
|
7105
7564
|
await writeFile21(commandPath, content, "utf-8");
|
|
7106
|
-
|
|
7565
|
+
const relativePath = join26(ctx.outputPath, `${command.name}.md`);
|
|
7566
|
+
filesWritten.push(relativePath);
|
|
7567
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
7107
7568
|
}
|
|
7108
7569
|
return {
|
|
7109
|
-
filesWritten
|
|
7570
|
+
filesWritten,
|
|
7571
|
+
managedOutputs
|
|
7110
7572
|
};
|
|
7111
7573
|
}
|
|
7112
7574
|
};
|
|
@@ -7121,7 +7583,7 @@ var opencodeAdapter = {
|
|
|
7121
7583
|
{ writer: OpenCodeCommandsWriter, outputPath: ".opencode/commands/" }
|
|
7122
7584
|
],
|
|
7123
7585
|
async init(ctx) {
|
|
7124
|
-
const opencodeDir =
|
|
7586
|
+
const opencodeDir = join27(ctx.projectRoot, ".opencode");
|
|
7125
7587
|
mkdirSync8(opencodeDir, { recursive: true });
|
|
7126
7588
|
return {
|
|
7127
7589
|
filesCreated: [".opencode/"],
|
|
@@ -7134,7 +7596,8 @@ var opencodeAdapter = {
|
|
|
7134
7596
|
const result = await executeWriters(this.writers, providerBundle, ctx.projectRoot, providerId);
|
|
7135
7597
|
return {
|
|
7136
7598
|
filesWritten: result.filesWritten,
|
|
7137
|
-
filesDeleted: []
|
|
7599
|
+
filesDeleted: [],
|
|
7600
|
+
managedOutputs: result.managedOutputs
|
|
7138
7601
|
};
|
|
7139
7602
|
}
|
|
7140
7603
|
};
|
|
@@ -7175,7 +7638,7 @@ async function inferCapabilityId(source, sourceType) {
|
|
|
7175
7638
|
}
|
|
7176
7639
|
async function runAddCap(flags, name) {
|
|
7177
7640
|
try {
|
|
7178
|
-
if (!
|
|
7641
|
+
if (!existsSync24("omni.toml")) {
|
|
7179
7642
|
console.log("✗ No config file found");
|
|
7180
7643
|
console.log(" Run: omnidev init");
|
|
7181
7644
|
process.exit(1);
|
|
@@ -7198,7 +7661,7 @@ async function runAddCap(flags, name) {
|
|
|
7198
7661
|
sourceType = "local";
|
|
7199
7662
|
const localPath = flags.local.startsWith("file://") ? flags.local.slice(7) : flags.local;
|
|
7200
7663
|
source = `file://${localPath}`;
|
|
7201
|
-
if (!
|
|
7664
|
+
if (!existsSync24(localPath)) {
|
|
7202
7665
|
console.error(`✗ Local path not found: ${localPath}`);
|
|
7203
7666
|
process.exit(1);
|
|
7204
7667
|
}
|
|
@@ -7290,7 +7753,7 @@ async function runAddCap(flags, name) {
|
|
|
7290
7753
|
}
|
|
7291
7754
|
async function runAddMcp(flags, name) {
|
|
7292
7755
|
try {
|
|
7293
|
-
if (!
|
|
7756
|
+
if (!existsSync24("omni.toml")) {
|
|
7294
7757
|
console.log("✗ No config file found");
|
|
7295
7758
|
console.log(" Run: omnidev init");
|
|
7296
7759
|
process.exit(1);
|
|
@@ -7577,9 +8040,9 @@ var addRoutes = buildRouteMap({
|
|
|
7577
8040
|
});
|
|
7578
8041
|
|
|
7579
8042
|
// src/commands/capability.ts
|
|
7580
|
-
import { existsSync as
|
|
8043
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync9 } from "node:fs";
|
|
7581
8044
|
import { writeFile as writeFile22 } from "node:fs/promises";
|
|
7582
|
-
import { join as
|
|
8045
|
+
import { join as join28 } from "node:path";
|
|
7583
8046
|
import { input } from "@inquirer/prompts";
|
|
7584
8047
|
init_src();
|
|
7585
8048
|
import { buildCommand as buildCommand2, buildRouteMap as buildRouteMap2 } from "@stricli/core";
|
|
@@ -7768,7 +8231,7 @@ function generateGitignore(programmatic) {
|
|
|
7768
8231
|
}
|
|
7769
8232
|
async function runCapabilityNew(flags, capabilityId) {
|
|
7770
8233
|
try {
|
|
7771
|
-
if (!
|
|
8234
|
+
if (!existsSync25(".omni")) {
|
|
7772
8235
|
console.error("✗ OmniDev is not initialized in this directory.");
|
|
7773
8236
|
console.log("");
|
|
7774
8237
|
console.log(" Run: omnidev init");
|
|
@@ -7792,28 +8255,28 @@ async function runCapabilityNew(flags, capabilityId) {
|
|
|
7792
8255
|
default: defaultPath
|
|
7793
8256
|
});
|
|
7794
8257
|
}
|
|
7795
|
-
if (
|
|
8258
|
+
if (existsSync25(capabilityDir)) {
|
|
7796
8259
|
console.error(`✗ Directory already exists at ${capabilityDir}`);
|
|
7797
8260
|
process.exit(1);
|
|
7798
8261
|
}
|
|
7799
8262
|
const name = toTitleCase(id);
|
|
7800
8263
|
mkdirSync9(capabilityDir, { recursive: true });
|
|
7801
8264
|
const capabilityToml = generateCapabilityToml2({ id, name });
|
|
7802
|
-
await writeFile22(
|
|
7803
|
-
const skillDir =
|
|
8265
|
+
await writeFile22(join28(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
|
|
8266
|
+
const skillDir = join28(capabilityDir, "skills", "getting-started");
|
|
7804
8267
|
mkdirSync9(skillDir, { recursive: true });
|
|
7805
|
-
await writeFile22(
|
|
7806
|
-
const rulesDir =
|
|
8268
|
+
await writeFile22(join28(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
|
|
8269
|
+
const rulesDir = join28(capabilityDir, "rules");
|
|
7807
8270
|
mkdirSync9(rulesDir, { recursive: true });
|
|
7808
|
-
await writeFile22(
|
|
7809
|
-
const hooksDir =
|
|
8271
|
+
await writeFile22(join28(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
|
|
8272
|
+
const hooksDir = join28(capabilityDir, "hooks");
|
|
7810
8273
|
mkdirSync9(hooksDir, { recursive: true });
|
|
7811
|
-
await writeFile22(
|
|
7812
|
-
await writeFile22(
|
|
7813
|
-
await writeFile22(
|
|
8274
|
+
await writeFile22(join28(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
|
|
8275
|
+
await writeFile22(join28(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
|
|
8276
|
+
await writeFile22(join28(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
|
|
7814
8277
|
if (flags.programmatic) {
|
|
7815
|
-
await writeFile22(
|
|
7816
|
-
await writeFile22(
|
|
8278
|
+
await writeFile22(join28(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
|
|
8279
|
+
await writeFile22(join28(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
|
|
7817
8280
|
}
|
|
7818
8281
|
console.log(`✓ Created capability: ${name}`);
|
|
7819
8282
|
console.log(` Location: ${capabilityDir}`);
|
|
@@ -7969,7 +8432,7 @@ var capabilityRoutes = buildRouteMap2({
|
|
|
7969
8432
|
});
|
|
7970
8433
|
|
|
7971
8434
|
// src/commands/doctor.ts
|
|
7972
|
-
import { existsSync as
|
|
8435
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
7973
8436
|
import { execFile } from "node:child_process";
|
|
7974
8437
|
import { readFile as readFile20 } from "node:fs/promises";
|
|
7975
8438
|
import { promisify } from "node:util";
|
|
@@ -8016,50 +8479,52 @@ async function runDoctor() {
|
|
|
8016
8479
|
async function checkPackageManager() {
|
|
8017
8480
|
const execFileAsync = promisify(execFile);
|
|
8018
8481
|
try {
|
|
8019
|
-
const { stdout } = await execFileAsync("
|
|
8020
|
-
const
|
|
8021
|
-
|
|
8022
|
-
|
|
8482
|
+
const { stdout: npmStdout } = await execFileAsync("npm", ["--version"]);
|
|
8483
|
+
const npmVersion = npmStdout.trim();
|
|
8484
|
+
try {
|
|
8485
|
+
const { stdout: bunStdout } = await execFileAsync("bun", ["--version"]);
|
|
8486
|
+
const bunVersion = bunStdout.trim();
|
|
8487
|
+
const firstPart = bunVersion.split(".")[0];
|
|
8488
|
+
if (!firstPart) {
|
|
8489
|
+
return {
|
|
8490
|
+
name: "Package Manager",
|
|
8491
|
+
passed: false,
|
|
8492
|
+
message: `Invalid Bun version format: ${bunVersion}`,
|
|
8493
|
+
fix: "Reinstall Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8494
|
+
};
|
|
8495
|
+
}
|
|
8496
|
+
const major = Number.parseInt(firstPart, 10);
|
|
8497
|
+
if (major < 1) {
|
|
8498
|
+
return {
|
|
8499
|
+
name: "Package Manager",
|
|
8500
|
+
passed: false,
|
|
8501
|
+
message: `npm v${npmVersion}; bun v${bunVersion}`,
|
|
8502
|
+
fix: "Upgrade Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8503
|
+
};
|
|
8504
|
+
}
|
|
8023
8505
|
return {
|
|
8024
8506
|
name: "Package Manager",
|
|
8025
|
-
passed:
|
|
8026
|
-
message: `
|
|
8027
|
-
fix: "Reinstall Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8507
|
+
passed: true,
|
|
8508
|
+
message: `npm v${npmVersion}; bun v${bunVersion}`
|
|
8028
8509
|
};
|
|
8029
|
-
}
|
|
8030
|
-
const major = Number.parseInt(firstPart, 10);
|
|
8031
|
-
if (major < 1) {
|
|
8510
|
+
} catch {
|
|
8032
8511
|
return {
|
|
8033
8512
|
name: "Package Manager",
|
|
8034
|
-
passed:
|
|
8035
|
-
message: `
|
|
8036
|
-
fix: "Upgrade Bun: curl -fsSL https://bun.sh/install | bash"
|
|
8513
|
+
passed: true,
|
|
8514
|
+
message: `npm v${npmVersion}`
|
|
8037
8515
|
};
|
|
8038
8516
|
}
|
|
8039
|
-
return {
|
|
8040
|
-
name: "Package Manager",
|
|
8041
|
-
passed: true,
|
|
8042
|
-
message: `bun v${version2}`
|
|
8043
|
-
};
|
|
8044
|
-
} catch {}
|
|
8045
|
-
try {
|
|
8046
|
-
const { stdout } = await execFileAsync("npm", ["--version"]);
|
|
8047
|
-
return {
|
|
8048
|
-
name: "Package Manager",
|
|
8049
|
-
passed: true,
|
|
8050
|
-
message: `npm v${stdout.trim()}`
|
|
8051
|
-
};
|
|
8052
8517
|
} catch {
|
|
8053
8518
|
return {
|
|
8054
8519
|
name: "Package Manager",
|
|
8055
8520
|
passed: false,
|
|
8056
|
-
message: "
|
|
8057
|
-
fix: "Install
|
|
8521
|
+
message: "npm is not installed",
|
|
8522
|
+
fix: "Install Node.js and npm: https://nodejs.org/"
|
|
8058
8523
|
};
|
|
8059
8524
|
}
|
|
8060
8525
|
}
|
|
8061
8526
|
async function checkOmniLocalDir() {
|
|
8062
|
-
const exists =
|
|
8527
|
+
const exists = existsSync26(".omni");
|
|
8063
8528
|
if (!exists) {
|
|
8064
8529
|
return {
|
|
8065
8530
|
name: ".omni/ directory",
|
|
@@ -8076,7 +8541,7 @@ async function checkOmniLocalDir() {
|
|
|
8076
8541
|
}
|
|
8077
8542
|
async function checkConfig() {
|
|
8078
8543
|
const configPath = "omni.toml";
|
|
8079
|
-
if (!
|
|
8544
|
+
if (!existsSync26(configPath)) {
|
|
8080
8545
|
return {
|
|
8081
8546
|
name: "Configuration",
|
|
8082
8547
|
passed: false,
|
|
@@ -8103,7 +8568,7 @@ async function checkConfig() {
|
|
|
8103
8568
|
}
|
|
8104
8569
|
async function checkRootGitignore() {
|
|
8105
8570
|
const gitignorePath = ".gitignore";
|
|
8106
|
-
if (!
|
|
8571
|
+
if (!existsSync26(gitignorePath)) {
|
|
8107
8572
|
return {
|
|
8108
8573
|
name: "Root .gitignore",
|
|
8109
8574
|
passed: false,
|
|
@@ -8137,7 +8602,7 @@ async function checkRootGitignore() {
|
|
|
8137
8602
|
}
|
|
8138
8603
|
async function checkCapabilitiesDir() {
|
|
8139
8604
|
const capabilitiesDirPath = ".omni/capabilities";
|
|
8140
|
-
if (!
|
|
8605
|
+
if (!existsSync26(capabilitiesDirPath)) {
|
|
8141
8606
|
return {
|
|
8142
8607
|
name: "Capabilities Directory",
|
|
8143
8608
|
passed: true,
|
|
@@ -8153,7 +8618,7 @@ async function checkCapabilitiesDir() {
|
|
|
8153
8618
|
|
|
8154
8619
|
// src/commands/init.ts
|
|
8155
8620
|
import { exec } from "node:child_process";
|
|
8156
|
-
import { existsSync as
|
|
8621
|
+
import { existsSync as existsSync27, mkdirSync as mkdirSync10 } from "node:fs";
|
|
8157
8622
|
import { readFile as readFile21, writeFile as writeFile23 } from "node:fs/promises";
|
|
8158
8623
|
import { promisify as promisify2 } from "node:util";
|
|
8159
8624
|
init_src();
|
|
@@ -8223,7 +8688,7 @@ async function runInit(_flags, providerArg) {
|
|
|
8223
8688
|
}
|
|
8224
8689
|
}
|
|
8225
8690
|
await writeEnabledProviders(providerIds);
|
|
8226
|
-
if (!
|
|
8691
|
+
if (!existsSync27("omni.toml")) {
|
|
8227
8692
|
await writeConfig({
|
|
8228
8693
|
profiles: {
|
|
8229
8694
|
default: {
|
|
@@ -8239,7 +8704,7 @@ async function runInit(_flags, providerArg) {
|
|
|
8239
8704
|
});
|
|
8240
8705
|
await setActiveProfile("default");
|
|
8241
8706
|
}
|
|
8242
|
-
if (!
|
|
8707
|
+
if (!existsSync27("OMNI.md")) {
|
|
8243
8708
|
await writeFile23("OMNI.md", generateOmniMdTemplate(), "utf-8");
|
|
8244
8709
|
}
|
|
8245
8710
|
const config3 = await loadConfig();
|
|
@@ -8317,7 +8782,7 @@ async function addProviderFilesToGitignore(entries) {
|
|
|
8317
8782
|
async function addToGitignore(entriesToAdd, sectionHeader) {
|
|
8318
8783
|
const gitignorePath = ".gitignore";
|
|
8319
8784
|
let content = "";
|
|
8320
|
-
if (
|
|
8785
|
+
if (existsSync27(gitignorePath)) {
|
|
8321
8786
|
content = await readFile21(gitignorePath, "utf-8");
|
|
8322
8787
|
}
|
|
8323
8788
|
const lines = content.split(`
|
|
@@ -8349,7 +8814,7 @@ async function getTrackedProviderFiles(files) {
|
|
|
8349
8814
|
}
|
|
8350
8815
|
|
|
8351
8816
|
// src/commands/profile.ts
|
|
8352
|
-
import { existsSync as
|
|
8817
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
8353
8818
|
init_src();
|
|
8354
8819
|
import { buildCommand as buildCommand5, buildRouteMap as buildRouteMap3 } from "@stricli/core";
|
|
8355
8820
|
var listCommand2 = buildCommand5({
|
|
@@ -8393,7 +8858,7 @@ var profileRoutes = buildRouteMap3({
|
|
|
8393
8858
|
});
|
|
8394
8859
|
async function runProfileList() {
|
|
8395
8860
|
try {
|
|
8396
|
-
if (!
|
|
8861
|
+
if (!existsSync28("omni.toml")) {
|
|
8397
8862
|
console.log("✗ No config file found");
|
|
8398
8863
|
console.log(" Run: omnidev init");
|
|
8399
8864
|
process.exit(1);
|
|
@@ -8433,7 +8898,7 @@ async function runProfileList() {
|
|
|
8433
8898
|
}
|
|
8434
8899
|
async function runProfileSet(profileName) {
|
|
8435
8900
|
try {
|
|
8436
|
-
if (!
|
|
8901
|
+
if (!existsSync28("omni.toml")) {
|
|
8437
8902
|
console.log("✗ No config file found");
|
|
8438
8903
|
console.log(" Run: omnidev init");
|
|
8439
8904
|
process.exit(1);
|
|
@@ -8466,6 +8931,8 @@ async function runProfileSet(profileName) {
|
|
|
8466
8931
|
}
|
|
8467
8932
|
|
|
8468
8933
|
// src/commands/provider.ts
|
|
8934
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
8935
|
+
import { readFile as readFile22 } from "node:fs/promises";
|
|
8469
8936
|
init_src();
|
|
8470
8937
|
import { buildCommand as buildCommand6, buildRouteMap as buildRouteMap4 } from "@stricli/core";
|
|
8471
8938
|
async function runProviderList() {
|
|
@@ -8499,6 +8966,7 @@ async function runProviderEnable(_flags, providerId) {
|
|
|
8499
8966
|
}
|
|
8500
8967
|
await enableProvider(providerId);
|
|
8501
8968
|
console.log(`✓ Enabled provider: ${adapter.displayName}`);
|
|
8969
|
+
await maybeRemindAboutProviderGitignore(providerId);
|
|
8502
8970
|
const enabledAdapters = await getEnabledAdapters();
|
|
8503
8971
|
await syncAgentConfiguration({ silent: false, adapters: enabledAdapters });
|
|
8504
8972
|
}
|
|
@@ -8579,10 +9047,33 @@ var providerRoutes = buildRouteMap4({
|
|
|
8579
9047
|
brief: "Manage AI provider adapters"
|
|
8580
9048
|
}
|
|
8581
9049
|
});
|
|
9050
|
+
async function maybeRemindAboutProviderGitignore(providerId) {
|
|
9051
|
+
const missingEntries = await getMissingGitignoreEntries(getProviderGitignoreFiles([providerId]));
|
|
9052
|
+
if (missingEntries.length === 0) {
|
|
9053
|
+
return;
|
|
9054
|
+
}
|
|
9055
|
+
console.log("");
|
|
9056
|
+
console.log("Also update your .gitignore to ignore provider files if you do not want to commit them:");
|
|
9057
|
+
for (const entry of missingEntries) {
|
|
9058
|
+
console.log(` - ${entry}`);
|
|
9059
|
+
}
|
|
9060
|
+
}
|
|
9061
|
+
async function getMissingGitignoreEntries(entries) {
|
|
9062
|
+
if (entries.length === 0) {
|
|
9063
|
+
return [];
|
|
9064
|
+
}
|
|
9065
|
+
let content = "";
|
|
9066
|
+
if (existsSync29(".gitignore")) {
|
|
9067
|
+
content = await readFile22(".gitignore", "utf-8");
|
|
9068
|
+
}
|
|
9069
|
+
const lines = new Set(content.split(`
|
|
9070
|
+
`).map((line) => line.trim()));
|
|
9071
|
+
return [...new Set(entries)].filter((entry) => !lines.has(entry));
|
|
9072
|
+
}
|
|
8582
9073
|
|
|
8583
9074
|
// src/commands/security.ts
|
|
8584
9075
|
init_src();
|
|
8585
|
-
import { existsSync as
|
|
9076
|
+
import { existsSync as existsSync30 } from "node:fs";
|
|
8586
9077
|
import { buildCommand as buildCommand7, buildRouteMap as buildRouteMap5 } from "@stricli/core";
|
|
8587
9078
|
var VALID_FINDING_TYPES = [
|
|
8588
9079
|
"unicode_bidi",
|
|
@@ -8621,7 +9112,9 @@ async function filterAllowedFindings(summary, options = {}) {
|
|
|
8621
9112
|
symlink_escape: 0,
|
|
8622
9113
|
symlink_absolute: 0,
|
|
8623
9114
|
suspicious_script: 0,
|
|
8624
|
-
binary_file: 0
|
|
9115
|
+
binary_file: 0,
|
|
9116
|
+
hidden_command: 0,
|
|
9117
|
+
network_request: 0
|
|
8625
9118
|
};
|
|
8626
9119
|
const findingsBySeverity = {
|
|
8627
9120
|
low: 0,
|
|
@@ -8699,7 +9192,7 @@ function formatFindingsWithHints(summary) {
|
|
|
8699
9192
|
}
|
|
8700
9193
|
async function runSecurityIssues(flags = {}) {
|
|
8701
9194
|
try {
|
|
8702
|
-
if (!
|
|
9195
|
+
if (!existsSync30("omni.toml")) {
|
|
8703
9196
|
console.log("No config file found");
|
|
8704
9197
|
console.log(" Run: omnidev init");
|
|
8705
9198
|
process.exit(1);
|
|
@@ -8954,7 +9447,7 @@ var securityRoutes = buildRouteMap5({
|
|
|
8954
9447
|
});
|
|
8955
9448
|
|
|
8956
9449
|
// src/commands/sync.ts
|
|
8957
|
-
import { existsSync as
|
|
9450
|
+
import { existsSync as existsSync31 } from "node:fs";
|
|
8958
9451
|
init_src();
|
|
8959
9452
|
import { buildCommand as buildCommand8 } from "@stricli/core";
|
|
8960
9453
|
var PROVIDERS_STATE_PATH = ".omni/state/providers.json";
|
|
@@ -8972,7 +9465,7 @@ async function runSync() {
|
|
|
8972
9465
|
const config3 = await loadConfig();
|
|
8973
9466
|
const activeProfile = await getActiveProfile() ?? "default";
|
|
8974
9467
|
let adapters = await getEnabledAdapters();
|
|
8975
|
-
if (!
|
|
9468
|
+
if (!existsSync31(PROVIDERS_STATE_PATH) || adapters.length === 0) {
|
|
8976
9469
|
console.log("No providers configured yet. Select your provider(s):");
|
|
8977
9470
|
const providerIds = await promptForProviders();
|
|
8978
9471
|
await writeEnabledProviders(providerIds);
|
|
@@ -9182,9 +9675,9 @@ async function buildDynamicApp() {
|
|
|
9182
9675
|
security: securityRoutes
|
|
9183
9676
|
};
|
|
9184
9677
|
debug("Core routes registered", Object.keys(routes));
|
|
9185
|
-
const configPath =
|
|
9186
|
-
debug("Checking for config", { configPath, exists:
|
|
9187
|
-
if (
|
|
9678
|
+
const configPath = join29(process.cwd(), "omni.toml");
|
|
9679
|
+
debug("Checking for config", { configPath, exists: existsSync32(configPath), cwd: process.cwd() });
|
|
9680
|
+
if (existsSync32(configPath)) {
|
|
9188
9681
|
try {
|
|
9189
9682
|
debug("Loading capability commands...");
|
|
9190
9683
|
const capabilityCommands = await loadCapabilityCommands();
|
|
@@ -9259,25 +9752,25 @@ async function loadCapabilityCommands() {
|
|
|
9259
9752
|
return commands;
|
|
9260
9753
|
}
|
|
9261
9754
|
async function loadCapabilityExport(capability3) {
|
|
9262
|
-
const capabilityPath =
|
|
9263
|
-
const builtIndexPath =
|
|
9264
|
-
const jsIndexPath =
|
|
9265
|
-
const tsIndexPath =
|
|
9755
|
+
const capabilityPath = join29(process.cwd(), capability3.path);
|
|
9756
|
+
const builtIndexPath = join29(capabilityPath, "dist", "index.js");
|
|
9757
|
+
const jsIndexPath = join29(capabilityPath, "index.js");
|
|
9758
|
+
const tsIndexPath = join29(capabilityPath, "index.ts");
|
|
9266
9759
|
debug(`Checking entry points for '${capability3.id}'`, {
|
|
9267
9760
|
capabilityPath,
|
|
9268
9761
|
builtIndexPath,
|
|
9269
|
-
builtExists:
|
|
9762
|
+
builtExists: existsSync32(builtIndexPath),
|
|
9270
9763
|
jsIndexPath,
|
|
9271
|
-
jsExists:
|
|
9764
|
+
jsExists: existsSync32(jsIndexPath),
|
|
9272
9765
|
tsIndexPath,
|
|
9273
|
-
tsExists:
|
|
9766
|
+
tsExists: existsSync32(tsIndexPath)
|
|
9274
9767
|
});
|
|
9275
9768
|
let indexPath = null;
|
|
9276
|
-
if (
|
|
9769
|
+
if (existsSync32(builtIndexPath)) {
|
|
9277
9770
|
indexPath = builtIndexPath;
|
|
9278
|
-
} else if (
|
|
9771
|
+
} else if (existsSync32(jsIndexPath)) {
|
|
9279
9772
|
indexPath = jsIndexPath;
|
|
9280
|
-
} else if (
|
|
9773
|
+
} else if (existsSync32(tsIndexPath)) {
|
|
9281
9774
|
indexPath = tsIndexPath;
|
|
9282
9775
|
}
|
|
9283
9776
|
if (!indexPath) {
|