@omnidev-ai/cli 0.17.0 → 0.18.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +534 -307
  2. 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/capability/mcp-env.ts
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 loadCapabilityEnv(capabilityPath) {
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
- return Object.fromEntries(Object.entries(parseEnv(envContent)).filter((entry) => typeof entry[1] === "string"));
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 variables = mergeEnvSources(await loadCapabilityEnv(capabilityPath));
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, variables, capabilityId, "mcp.command");
2526
+ resolvedMcp.command = resolveString(resolvedMcp.command, resolvedVariables, capabilityId, "mcp.command");
2522
2527
  }
2523
2528
  if (resolvedMcp.cwd) {
2524
- resolvedMcp.cwd = resolveString(resolvedMcp.cwd, variables, capabilityId, "mcp.cwd");
2529
+ resolvedMcp.cwd = resolveString(resolvedMcp.cwd, resolvedVariables, capabilityId, "mcp.cwd");
2525
2530
  }
2526
2531
  if (resolvedMcp.url) {
2527
- resolvedMcp.url = resolveString(resolvedMcp.url, variables, capabilityId, "mcp.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, variables, capabilityId, `mcp.args[${index}]`));
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, variables, capabilityId, `mcp.env.${key}`)
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, variables, capabilityId, `mcp.headers.${key}`)
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 CAPABILITY_ENV_FILE = ".env", ENV_PLACEHOLDER, ENV_PLACEHOLDER_DETECTOR;
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
- async function loadSkills(capabilityPath, capabilityId) {
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,7 +2637,7 @@ 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);
2640
+ const skill = await parseSkillFile(skillPath, capabilityId, resolvedVariables, `skill file ${skillPath}`);
2599
2641
  skills.push(skill);
2600
2642
  }
2601
2643
  }
@@ -2603,25 +2645,19 @@ async function loadSkills(capabilityPath, capabilityId) {
2603
2645
  }
2604
2646
  return skills;
2605
2647
  }
2606
- async function parseSkillFile(filePath, capabilityId) {
2648
+ async function parseSkillFile(filePath, capabilityId, variables, sourceLabel) {
2607
2649
  const content = await readFile5(filePath, "utf-8");
2608
- const parsed = parseFrontmatterWithMarkdown(content);
2609
- if (!parsed) {
2610
- throw new Error(`Invalid SKILL.md format at ${filePath}: missing YAML frontmatter`);
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
- };
2650
+ return parseSkillMarkdown(content, capabilityId, {
2651
+ variables,
2652
+ sourceLabel
2653
+ });
2623
2654
  }
2624
- var init_skills = () => {};
2655
+ var SKILL_PLACEHOLDER, SKILL_PLACEHOLDER_DETECTOR;
2656
+ var init_skills = __esm(() => {
2657
+ init_env();
2658
+ SKILL_PLACEHOLDER = /\{OMNIDEV_([A-Za-z_][A-Za-z0-9_]*)\}/g;
2659
+ SKILL_PLACEHOLDER_DETECTOR = /\{OMNIDEV_([A-Za-z_][A-Za-z0-9_]*)\}/;
2660
+ });
2625
2661
 
2626
2662
  // ../core/src/capability/subagents.ts
2627
2663
  import { existsSync as existsSync9, readdirSync as readdirSync5 } from "node:fs";
@@ -2767,40 +2803,13 @@ async function loadTypeDefinitions(capabilityPath) {
2767
2803
  }
2768
2804
  return readFile7(typesPath, "utf-8");
2769
2805
  }
2770
- function convertSkillExports(skillExports, capabilityId) {
2771
- return skillExports.map((skillExport) => {
2806
+ function convertSkillExports(skillExports, capabilityId, variables) {
2807
+ return skillExports.map((skillExport, index) => {
2772
2808
  const exportObj = skillExport;
2773
- const lines = exportObj.skillMd.split(`
2774
- `);
2775
- let name = "unnamed";
2776
- let description = "";
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
- };
2809
+ return parseSkillMarkdown(exportObj.skillMd, capabilityId, {
2810
+ variables,
2811
+ sourceLabel: `programmatic skill export[${index}]`
2812
+ });
2804
2813
  });
2805
2814
  }
2806
2815
  function convertRuleExports(ruleExports, capabilityId) {
@@ -2953,8 +2962,9 @@ function mergeByName(fileBased, programmatic) {
2953
2962
  return Array.from(byName.values());
2954
2963
  }
2955
2964
  async function loadCapability(capabilityPath) {
2965
+ const capabilityEnvVariables = await loadCapabilityEnvVariables(capabilityPath);
2956
2966
  const rawConfig = await loadCapabilityConfig(capabilityPath);
2957
- const config = await resolveCapabilityMcpEnv(rawConfig, capabilityPath);
2967
+ const config = await resolveCapabilityMcpEnv(rawConfig, capabilityPath, capabilityEnvVariables);
2958
2968
  const id = config.capability.id;
2959
2969
  const exports = await importCapabilityExports(capabilityPath);
2960
2970
  const exportsAny = exports;
@@ -2969,8 +2979,8 @@ async function loadCapability(capabilityPath) {
2969
2979
  return;
2970
2980
  };
2971
2981
  const skillsExport = getExportValue("skills");
2972
- const programmaticSkills = Array.isArray(skillsExport) ? convertSkillExports(skillsExport, id) : [];
2973
- const fileSkills = await loadSkills(capabilityPath, id);
2982
+ const programmaticSkills = Array.isArray(skillsExport) ? convertSkillExports(skillsExport, id, capabilityEnvVariables) : [];
2983
+ const fileSkills = await loadSkills(capabilityPath, id, capabilityEnvVariables);
2974
2984
  const skills = mergeByName(fileSkills, programmaticSkills);
2975
2985
  const rulesExport = getExportValue("rules");
2976
2986
  const programmaticRules = Array.isArray(rulesExport) ? convertRuleExports(rulesExport, id) : [];
@@ -3018,11 +3028,12 @@ async function loadCapability(capabilityPath) {
3018
3028
  }
3019
3029
  var CAPABILITIES_DIR = ".omni/capabilities";
3020
3030
  var init_loader2 = __esm(() => {
3021
- init_parser();
3022
3031
  init_loader();
3023
- init_mcp_env();
3032
+ init_parser();
3024
3033
  init_commands();
3025
3034
  init_docs();
3035
+ init_env();
3036
+ init_mcp_env();
3026
3037
  init_rules();
3027
3038
  init_skills();
3028
3039
  init_subagents();
@@ -5370,10 +5381,36 @@ var init_state = __esm(() => {
5370
5381
 
5371
5382
  // ../core/src/sync.ts
5372
5383
  import { spawn as spawn2 } from "node:child_process";
5373
- import { mkdirSync as mkdirSync5 } from "node:fs";
5384
+ import { existsSync as existsSync20, mkdirSync as mkdirSync5, readFileSync as readFileSync3 } from "node:fs";
5385
+ import { join as join10 } from "node:path";
5386
+ function getDeclaredPackageManager(packageManager) {
5387
+ if (typeof packageManager !== "string" || packageManager.trim().length === 0) {
5388
+ return;
5389
+ }
5390
+ const atIndex = packageManager.indexOf("@");
5391
+ return atIndex === -1 ? packageManager : packageManager.slice(0, atIndex);
5392
+ }
5393
+ function resolveCapabilityInstallCommand(capabilityPath, options) {
5394
+ const packageJsonPath = join10(capabilityPath, "package.json");
5395
+ const packageLockPath = join10(capabilityPath, "package-lock.json");
5396
+ let packageManager;
5397
+ try {
5398
+ const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
5399
+ packageManager = getDeclaredPackageManager(pkgJson.packageManager);
5400
+ } catch {}
5401
+ if (!options.hasNpm) {
5402
+ throw new Error("npm is not installed. Install npm to install capability dependencies.");
5403
+ }
5404
+ if (packageManager && packageManager !== "npm") {
5405
+ throw new Error(`Capability at ${capabilityPath} declares packageManager=${packageManager}, but OmniDev only supports npm for capability dependencies.`);
5406
+ }
5407
+ return {
5408
+ cmd: "npm",
5409
+ args: [existsSync20(packageLockPath) ? "ci" : "install"]
5410
+ };
5411
+ }
5374
5412
  async function installCapabilityDependencies(silent) {
5375
- const { existsSync: existsSync20, readdirSync: readdirSync7, readFileSync: readFileSync3 } = await import("node:fs");
5376
- const { join: join10 } = await import("node:path");
5413
+ const { readdirSync: readdirSync7 } = await import("node:fs");
5377
5414
  const { parse: parse2 } = await Promise.resolve().then(() => (init_dist(), exports_dist));
5378
5415
  const capabilitiesDir = ".omni/capabilities";
5379
5416
  if (!existsSync20(capabilitiesDir)) {
@@ -5387,10 +5424,9 @@ async function installCapabilityDependencies(silent) {
5387
5424
  proc.on("close", (code) => resolve2(code === 0));
5388
5425
  });
5389
5426
  }
5390
- const hasBun = await commandExists("bun");
5391
- const hasNpm = hasBun ? false : await commandExists("npm");
5392
- if (!hasBun && !hasNpm) {
5393
- throw new Error("Neither Bun nor npm is installed. Install one of them to install capability dependencies.");
5427
+ const hasNpm = await commandExists("npm");
5428
+ if (!hasNpm) {
5429
+ throw new Error("npm is not installed. Install npm to install capability dependencies.");
5394
5430
  }
5395
5431
  for (const entry of entries) {
5396
5432
  if (!entry.isDirectory()) {
@@ -5413,9 +5449,9 @@ async function installCapabilityDependencies(silent) {
5413
5449
  }
5414
5450
  try {
5415
5451
  await new Promise((resolve2, reject) => {
5416
- const useNpmCi = hasNpm && existsSync20(join10(capabilityPath, "package-lock.json"));
5417
- const cmd = hasBun ? "bun" : "npm";
5418
- const args = hasBun ? ["install"] : useNpmCi ? ["ci"] : ["install"];
5452
+ const { cmd, args } = resolveCapabilityInstallCommand(capabilityPath, {
5453
+ hasNpm
5454
+ });
5419
5455
  const proc = spawn2(cmd, args, {
5420
5456
  cwd: capabilityPath,
5421
5457
  stdio: "pipe"
@@ -5444,9 +5480,7 @@ ${stderr}`));
5444
5480
  } catch {}
5445
5481
  if (hasBuildScript) {
5446
5482
  await new Promise((resolve2, reject) => {
5447
- const cmd = hasBun ? "bun" : "npm";
5448
- const args = ["run", "build"];
5449
- const proc = spawn2(cmd, args, {
5483
+ const proc = spawn2("npm", ["run", "build"], {
5450
5484
  cwd: capabilityPath,
5451
5485
  stdio: "pipe"
5452
5486
  });
@@ -5598,21 +5632,23 @@ var init_types3 = __esm(() => {
5598
5632
  unicode: true,
5599
5633
  symlinks: true,
5600
5634
  scripts: true,
5601
- binaries: false
5635
+ binaries: false,
5636
+ hiddenCommands: true
5602
5637
  }
5603
5638
  };
5604
5639
  DEFAULT_SCAN_SETTINGS = {
5605
5640
  unicode: true,
5606
5641
  symlinks: true,
5607
5642
  scripts: true,
5608
- binaries: false
5643
+ binaries: false,
5644
+ hiddenCommands: true
5609
5645
  };
5610
5646
  });
5611
5647
 
5612
5648
  // ../core/src/security/scanner.ts
5613
- import { existsSync as existsSync20 } from "node:fs";
5649
+ import { existsSync as existsSync21 } from "node:fs";
5614
5650
  import { lstat, readdir as readdir2, readFile as readFile17, readlink, realpath } from "node:fs/promises";
5615
- import { join as join10, relative, resolve as resolve2 } from "node:path";
5651
+ import { join as join11, relative, resolve as resolve2 } from "node:path";
5616
5652
  async function scanFileForUnicode(filePath, relativePath) {
5617
5653
  const findings = [];
5618
5654
  try {
@@ -5693,10 +5729,113 @@ async function scanFileForScripts(filePath, relativePath) {
5693
5729
  } catch {}
5694
5730
  return findings;
5695
5731
  }
5732
+ function extractHiddenRegions(fileContent) {
5733
+ const regions = [];
5734
+ HTML_COMMENT_RE.lastIndex = 0;
5735
+ for (let match = HTML_COMMENT_RE.exec(fileContent);match !== null; match = HTML_COMMENT_RE.exec(fileContent)) {
5736
+ const captured = match[1];
5737
+ if (captured === undefined)
5738
+ continue;
5739
+ const beforeMatch = fileContent.substring(0, match.index);
5740
+ const startLine = beforeMatch.split(`
5741
+ `).length;
5742
+ regions.push({ content: captured, startLine });
5743
+ }
5744
+ HIDDEN_REFERENCE_RE.lastIndex = 0;
5745
+ for (let match = HIDDEN_REFERENCE_RE.exec(fileContent);match !== null; match = HIDDEN_REFERENCE_RE.exec(fileContent)) {
5746
+ const captured = match[1];
5747
+ if (captured === undefined)
5748
+ continue;
5749
+ const beforeMatch = fileContent.substring(0, match.index);
5750
+ const startLine = beforeMatch.split(`
5751
+ `).length;
5752
+ regions.push({ content: captured, startLine });
5753
+ }
5754
+ return regions;
5755
+ }
5756
+ async function scanFileForHiddenCommands(filePath, relativePath) {
5757
+ const findings = [];
5758
+ try {
5759
+ const content = await readFile17(filePath, "utf-8");
5760
+ const hiddenRegions = extractHiddenRegions(content);
5761
+ for (const region of hiddenRegions) {
5762
+ const regionLines = region.content.split(`
5763
+ `);
5764
+ for (let i = 0;i < regionLines.length; i++) {
5765
+ const line = regionLines[i] ?? "";
5766
+ if (!line.trim())
5767
+ continue;
5768
+ for (const { pattern, message, severity } of HIDDEN_COMMAND_PATTERNS) {
5769
+ if (pattern.test(line)) {
5770
+ findings.push({
5771
+ type: "hidden_command",
5772
+ severity,
5773
+ file: relativePath,
5774
+ line: region.startLine + i,
5775
+ message: `Hidden in comment: ${message}`,
5776
+ details: line.trim().substring(0, 100)
5777
+ });
5778
+ }
5779
+ }
5780
+ for (const { pattern, message, severity } of NETWORK_REQUEST_PATTERNS) {
5781
+ if (pattern.test(line)) {
5782
+ findings.push({
5783
+ type: "network_request",
5784
+ severity: severity === "medium" ? "high" : severity,
5785
+ file: relativePath,
5786
+ line: region.startLine + i,
5787
+ message: `Hidden in comment: ${message}`,
5788
+ details: line.trim().substring(0, 100)
5789
+ });
5790
+ }
5791
+ }
5792
+ for (const { pattern, message, severity } of SUSPICIOUS_SCRIPT_PATTERNS) {
5793
+ if (pattern.test(line)) {
5794
+ findings.push({
5795
+ type: "hidden_command",
5796
+ severity: severity === "medium" ? "high" : severity,
5797
+ file: relativePath,
5798
+ line: region.startLine + i,
5799
+ message: `Hidden in comment: ${message}`,
5800
+ details: line.trim().substring(0, 100)
5801
+ });
5802
+ }
5803
+ }
5804
+ }
5805
+ }
5806
+ } catch {}
5807
+ return findings;
5808
+ }
5809
+ async function scanFileForNetworkRequests(filePath, relativePath) {
5810
+ const findings = [];
5811
+ try {
5812
+ const content = await readFile17(filePath, "utf-8");
5813
+ const lines = content.split(`
5814
+ `);
5815
+ for (let lineNum = 0;lineNum < lines.length; lineNum++) {
5816
+ const line = lines[lineNum];
5817
+ if (!line)
5818
+ continue;
5819
+ for (const { pattern, message, severity } of NETWORK_REQUEST_PATTERNS) {
5820
+ if (pattern.test(line)) {
5821
+ findings.push({
5822
+ type: "network_request",
5823
+ severity,
5824
+ file: relativePath,
5825
+ line: lineNum + 1,
5826
+ message,
5827
+ details: line.trim().substring(0, 100)
5828
+ });
5829
+ }
5830
+ }
5831
+ }
5832
+ } catch {}
5833
+ return findings;
5834
+ }
5696
5835
  async function checkSymlink(symlinkPath, relativePath, capabilityRoot) {
5697
5836
  try {
5698
5837
  const linkTarget = await readlink(symlinkPath);
5699
- const resolvedTarget = resolve2(join10(symlinkPath, "..", linkTarget));
5838
+ const resolvedTarget = resolve2(join11(symlinkPath, "..", linkTarget));
5700
5839
  const normalizedRoot = await realpath(capabilityRoot);
5701
5840
  if (linkTarget.startsWith("/")) {
5702
5841
  return {
@@ -5731,7 +5870,7 @@ function isTextFile(filePath) {
5731
5870
  async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_SCAN_SETTINGS) {
5732
5871
  const startTime = Date.now();
5733
5872
  const findings = [];
5734
- if (!existsSync20(capabilityPath)) {
5873
+ if (!existsSync21(capabilityPath)) {
5735
5874
  return {
5736
5875
  capabilityId,
5737
5876
  path: capabilityPath,
@@ -5743,7 +5882,7 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
5743
5882
  async function scanDirectory(dirPath) {
5744
5883
  const entries = await readdir2(dirPath, { withFileTypes: true });
5745
5884
  for (const entry of entries) {
5746
- const fullPath = join10(dirPath, entry.name);
5885
+ const fullPath = join11(dirPath, entry.name);
5747
5886
  const relativePath = relative(capabilityPath, fullPath);
5748
5887
  if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "__pycache__") {
5749
5888
  continue;
@@ -5770,17 +5909,27 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
5770
5909
  });
5771
5910
  }
5772
5911
  if (isTextFile(fullPath)) {
5912
+ const ext = fullPath.toLowerCase().substring(fullPath.lastIndexOf("."));
5773
5913
  if (settings.unicode) {
5774
5914
  const unicodeFindings = await scanFileForUnicode(fullPath, relativePath);
5775
5915
  findings.push(...unicodeFindings);
5776
5916
  }
5777
5917
  if (settings.scripts) {
5778
- const ext = fullPath.toLowerCase().substring(fullPath.lastIndexOf("."));
5779
5918
  if ([".sh", ".bash", ".zsh", ".fish", ".py", ".rb", ".js", ".ts"].includes(ext)) {
5780
5919
  const scriptFindings = await scanFileForScripts(fullPath, relativePath);
5781
5920
  findings.push(...scriptFindings);
5782
5921
  }
5783
5922
  }
5923
+ if (settings.hiddenCommands) {
5924
+ if ([".md", ".txt", ".yaml", ".yml", ".toml"].includes(ext)) {
5925
+ const hiddenFindings = await scanFileForHiddenCommands(fullPath, relativePath);
5926
+ findings.push(...hiddenFindings);
5927
+ }
5928
+ }
5929
+ if (settings.hiddenCommands) {
5930
+ const networkFindings = await scanFileForNetworkRequests(fullPath, relativePath);
5931
+ findings.push(...networkFindings);
5932
+ }
5784
5933
  }
5785
5934
  }
5786
5935
  }
@@ -5812,7 +5961,9 @@ async function scanCapabilities(capabilities2, config2 = {}) {
5812
5961
  symlink_escape: 0,
5813
5962
  symlink_absolute: 0,
5814
5963
  suspicious_script: 0,
5815
- binary_file: 0
5964
+ binary_file: 0,
5965
+ hidden_command: 0,
5966
+ network_request: 0
5816
5967
  };
5817
5968
  const findingsBySeverity = {
5818
5969
  low: 0,
@@ -5887,7 +6038,7 @@ function formatScanResults(summary, verbose = false) {
5887
6038
  return lines.join(`
5888
6039
  `);
5889
6040
  }
5890
- var UNICODE_PATTERNS, SUSPICIOUS_SCRIPT_PATTERNS, BINARY_EXTENSIONS, TEXT_EXTENSIONS;
6041
+ var UNICODE_PATTERNS, SUSPICIOUS_SCRIPT_PATTERNS, NETWORK_REQUEST_PATTERNS, HIDDEN_COMMAND_PATTERNS, BINARY_EXTENSIONS, TEXT_EXTENSIONS, HTML_COMMENT_RE, HIDDEN_REFERENCE_RE;
5891
6042
  var init_scanner = __esm(() => {
5892
6043
  init_types3();
5893
6044
  UNICODE_PATTERNS = {
@@ -5979,6 +6130,75 @@ var init_scanner = __esm(() => {
5979
6130
  severity: "high"
5980
6131
  }
5981
6132
  ];
6133
+ NETWORK_REQUEST_PATTERNS = [
6134
+ {
6135
+ pattern: /\bcurl\s+.*https?:\/\//i,
6136
+ message: "Outbound curl request detected",
6137
+ severity: "medium"
6138
+ },
6139
+ {
6140
+ pattern: /\bwget\s+.*https?:\/\//i,
6141
+ message: "Outbound wget request detected",
6142
+ severity: "medium"
6143
+ },
6144
+ {
6145
+ pattern: /\bfetch\s*\(\s*["'`]https?:\/\//i,
6146
+ message: "Outbound fetch() request detected",
6147
+ severity: "medium"
6148
+ },
6149
+ {
6150
+ pattern: /\b(?:http|https)\.(?:get|request|post|put)\s*\(/i,
6151
+ message: "Outbound HTTP request via Node.js http module",
6152
+ severity: "medium"
6153
+ },
6154
+ {
6155
+ pattern: /\brequests\.(?:get|post|put|delete|patch)\s*\(/i,
6156
+ message: "Outbound HTTP request via Python requests",
6157
+ severity: "medium"
6158
+ },
6159
+ {
6160
+ pattern: /\bnc\b.*\s\d{2,5}\b/i,
6161
+ message: "Netcat connection detected",
6162
+ severity: "high"
6163
+ },
6164
+ {
6165
+ pattern: /\b(?:Invoke-WebRequest|Invoke-RestMethod|iwr|irm)\b/i,
6166
+ message: "Outbound PowerShell web request detected",
6167
+ severity: "medium"
6168
+ }
6169
+ ];
6170
+ HIDDEN_COMMAND_PATTERNS = [
6171
+ {
6172
+ pattern: /`[^`]*(?:curl|wget|bash|sh|python|ruby|node|exec|eval|system)\s[^`]*`/i,
6173
+ message: "Executable command in backtick-wrapped code",
6174
+ severity: "critical"
6175
+ },
6176
+ {
6177
+ pattern: /\|\s*(?:ba)?sh\b/i,
6178
+ message: "Pipe to shell execution",
6179
+ severity: "critical"
6180
+ },
6181
+ {
6182
+ pattern: /(?:^|\s)(?:bash|sh|zsh)\s+-c\s+/i,
6183
+ message: "Shell invocation with -c flag",
6184
+ severity: "high"
6185
+ },
6186
+ {
6187
+ pattern: /\b(?:curl|wget)\s+.*https?:\/\//i,
6188
+ message: "Network fetch command detected",
6189
+ severity: "high"
6190
+ },
6191
+ {
6192
+ pattern: /\b(?:python|ruby|node)\s+-e\s+/i,
6193
+ message: "Inline script execution",
6194
+ severity: "high"
6195
+ },
6196
+ {
6197
+ pattern: /\beval\s*\(.*\)/i,
6198
+ message: "eval() call detected",
6199
+ severity: "high"
6200
+ }
6201
+ ];
5982
6202
  BINARY_EXTENSIONS = new Set([
5983
6203
  ".exe",
5984
6204
  ".dll",
@@ -6013,6 +6233,8 @@ var init_scanner = __esm(() => {
6013
6233
  ".py",
6014
6234
  ".rb"
6015
6235
  ]);
6236
+ HTML_COMMENT_RE = /<!--([\s\S]*?)-->/g;
6237
+ HIDDEN_REFERENCE_RE = /^\[.*?\]:\s*\S+\s+"(.+)"/gm;
6016
6238
  });
6017
6239
 
6018
6240
  // ../core/src/security/index.ts
@@ -6222,6 +6444,7 @@ __export(exports_src, {
6222
6444
  resolveEnabledCapabilities: () => resolveEnabledCapabilities,
6223
6445
  resolveCapabilityRootInConfig: () => resolveCapabilityRootInConfig,
6224
6446
  resolveCapabilityRoot: () => resolveCapabilityRoot,
6447
+ resolveCapabilityInstallCommand: () => resolveCapabilityInstallCommand,
6225
6448
  removeSecurityAllow: () => removeSecurityAllow,
6226
6449
  readSecurityAllows: () => readSecurityAllows,
6227
6450
  readMcpJson: () => readMcpJson,
@@ -6353,13 +6576,13 @@ var init_src = __esm(() => {
6353
6576
  import { run } from "@stricli/core";
6354
6577
 
6355
6578
  // src/lib/dynamic-app.ts
6356
- import { existsSync as existsSync30 } from "node:fs";
6579
+ import { existsSync as existsSync31 } from "node:fs";
6357
6580
  import { createRequire as createRequire2 } from "node:module";
6358
- import { join as join27 } from "node:path";
6581
+ import { join as join28 } from "node:path";
6359
6582
  import { buildApplication, buildRouteMap as buildRouteMap7 } from "@stricli/core";
6360
6583
 
6361
6584
  // src/commands/add.ts
6362
- import { existsSync as existsSync23 } from "node:fs";
6585
+ import { existsSync as existsSync24 } from "node:fs";
6363
6586
  import { basename as basename5, resolve as resolve3 } from "node:path";
6364
6587
 
6365
6588
  // ../adapters/src/writers/generic/executor.ts
@@ -6392,21 +6615,21 @@ async function executeWriters(writerConfigs, bundle, projectRoot, providerId) {
6392
6615
  }
6393
6616
  // ../adapters/src/writers/generic/hooks.ts
6394
6617
  init_src();
6395
- import { existsSync as existsSync21 } from "node:fs";
6618
+ import { existsSync as existsSync22 } from "node:fs";
6396
6619
  import { mkdir as mkdir2, readFile as readFile18, writeFile as writeFile10 } from "node:fs/promises";
6397
- import { dirname, join as join11 } from "node:path";
6620
+ import { dirname, join as join12 } from "node:path";
6398
6621
  var HooksWriter = {
6399
6622
  id: "hooks",
6400
6623
  async write(bundle, ctx) {
6401
6624
  if (!bundle.hooks) {
6402
6625
  return { filesWritten: [] };
6403
6626
  }
6404
- const settingsPath = join11(ctx.projectRoot, ctx.outputPath);
6627
+ const settingsPath = join12(ctx.projectRoot, ctx.outputPath);
6405
6628
  const parentDir = dirname(settingsPath);
6406
6629
  await mkdir2(parentDir, { recursive: true });
6407
6630
  const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
6408
6631
  let existingSettings = {};
6409
- if (existsSync21(settingsPath)) {
6632
+ if (existsSync22(settingsPath)) {
6410
6633
  try {
6411
6634
  const content = await readFile18(settingsPath, "utf-8");
6412
6635
  existingSettings = JSON.parse(content);
@@ -6426,9 +6649,9 @@ var HooksWriter = {
6426
6649
  }
6427
6650
  };
6428
6651
  // ../adapters/src/writers/generic/instructions-md.ts
6429
- import { existsSync as existsSync22 } from "node:fs";
6652
+ import { existsSync as existsSync23 } from "node:fs";
6430
6653
  import { mkdir as mkdir3, readFile as readFile19, writeFile as writeFile11 } from "node:fs/promises";
6431
- import { dirname as dirname2, join as join12 } from "node:path";
6654
+ import { dirname as dirname2, join as join13 } from "node:path";
6432
6655
 
6433
6656
  // ../adapters/src/writers/generic/omni-md.ts
6434
6657
  init_src();
@@ -6453,14 +6676,14 @@ function renderOmniMdForProvider(content, providerId) {
6453
6676
  var InstructionsMdWriter = {
6454
6677
  id: "instructions-md",
6455
6678
  async write(bundle, ctx) {
6456
- const outputFullPath = join12(ctx.projectRoot, ctx.outputPath);
6679
+ const outputFullPath = join13(ctx.projectRoot, ctx.outputPath);
6457
6680
  const parentDir = dirname2(outputFullPath);
6458
6681
  if (parentDir !== ctx.projectRoot) {
6459
6682
  await mkdir3(parentDir, { recursive: true });
6460
6683
  }
6461
- const omniMdPath = join12(ctx.projectRoot, "OMNI.md");
6684
+ const omniMdPath = join13(ctx.projectRoot, "OMNI.md");
6462
6685
  let omniMdContent = "";
6463
- if (existsSync22(omniMdPath)) {
6686
+ if (existsSync23(omniMdPath)) {
6464
6687
  omniMdContent = renderOmniMdForProvider(await readFile19(omniMdPath, "utf-8"), ctx.providerId);
6465
6688
  }
6466
6689
  let content = omniMdContent;
@@ -6478,17 +6701,17 @@ ${bundle.instructionsContent}
6478
6701
  };
6479
6702
  // ../adapters/src/writers/generic/skills.ts
6480
6703
  import { mkdir as mkdir4, writeFile as writeFile12 } from "node:fs/promises";
6481
- import { join as join13 } from "node:path";
6704
+ import { join as join14 } from "node:path";
6482
6705
  var SkillsWriter = {
6483
6706
  id: "skills",
6484
6707
  async write(bundle, ctx) {
6485
- const skillsDir = join13(ctx.projectRoot, ctx.outputPath);
6708
+ const skillsDir = join14(ctx.projectRoot, ctx.outputPath);
6486
6709
  await mkdir4(skillsDir, { recursive: true });
6487
6710
  const filesWritten = [];
6488
6711
  for (const skill of bundle.skills) {
6489
- const skillDir = join13(skillsDir, skill.name);
6712
+ const skillDir = join14(skillsDir, skill.name);
6490
6713
  await mkdir4(skillDir, { recursive: true });
6491
- const skillPath = join13(skillDir, "SKILL.md");
6714
+ const skillPath = join14(skillDir, "SKILL.md");
6492
6715
  const content = `---
6493
6716
  name: ${skill.name}
6494
6717
  description: "${skill.description}"
@@ -6496,7 +6719,7 @@ description: "${skill.description}"
6496
6719
 
6497
6720
  ${skill.instructions}`;
6498
6721
  await writeFile12(skillPath, content, "utf-8");
6499
- filesWritten.push(join13(ctx.outputPath, skill.name, "SKILL.md"));
6722
+ filesWritten.push(join14(ctx.outputPath, skill.name, "SKILL.md"));
6500
6723
  }
6501
6724
  return {
6502
6725
  filesWritten
@@ -6505,7 +6728,7 @@ ${skill.instructions}`;
6505
6728
  };
6506
6729
  // ../adapters/src/writers/generic/commands-as-skills.ts
6507
6730
  import { mkdir as mkdir5, writeFile as writeFile13 } from "node:fs/promises";
6508
- import { join as join14 } from "node:path";
6731
+ import { join as join15 } from "node:path";
6509
6732
  function generateSkillFrontmatter(command) {
6510
6733
  const lines = ["---"];
6511
6734
  lines.push(`name: ${command.name}`);
@@ -6520,19 +6743,19 @@ function generateSkillFrontmatter(command) {
6520
6743
  var CommandsAsSkillsWriter = {
6521
6744
  id: "commands-as-skills",
6522
6745
  async write(bundle, ctx) {
6523
- const skillsDir = join14(ctx.projectRoot, ctx.outputPath);
6746
+ const skillsDir = join15(ctx.projectRoot, ctx.outputPath);
6524
6747
  await mkdir5(skillsDir, { recursive: true });
6525
6748
  const filesWritten = [];
6526
6749
  for (const command of bundle.commands) {
6527
- const commandSkillDir = join14(skillsDir, command.name);
6750
+ const commandSkillDir = join15(skillsDir, command.name);
6528
6751
  await mkdir5(commandSkillDir, { recursive: true });
6529
6752
  const frontmatter = generateSkillFrontmatter(command);
6530
6753
  const content = `${frontmatter}
6531
6754
 
6532
6755
  ${command.prompt}`;
6533
- const skillPath = join14(commandSkillDir, "SKILL.md");
6756
+ const skillPath = join15(commandSkillDir, "SKILL.md");
6534
6757
  await writeFile13(skillPath, content, "utf-8");
6535
- filesWritten.push(join14(ctx.outputPath, command.name, "SKILL.md"));
6758
+ filesWritten.push(join15(ctx.outputPath, command.name, "SKILL.md"));
6536
6759
  }
6537
6760
  return {
6538
6761
  filesWritten
@@ -6588,7 +6811,7 @@ function createProviderScopedBundle(bundle, providerId) {
6588
6811
 
6589
6812
  // ../adapters/src/writers/claude/agents.ts
6590
6813
  import { mkdir as mkdir6, writeFile as writeFile14 } from "node:fs/promises";
6591
- import { join as join15 } from "node:path";
6814
+ import { join as join16 } from "node:path";
6592
6815
  function generateFrontmatter(agent) {
6593
6816
  const lines = ["---"];
6594
6817
  lines.push(`name: ${agent.name}`);
@@ -6615,7 +6838,7 @@ function generateFrontmatter(agent) {
6615
6838
  var ClaudeAgentsWriter = {
6616
6839
  id: "claude-agents",
6617
6840
  async write(bundle, ctx) {
6618
- const agentsDir = join15(ctx.projectRoot, ctx.outputPath);
6841
+ const agentsDir = join16(ctx.projectRoot, ctx.outputPath);
6619
6842
  await mkdir6(agentsDir, { recursive: true });
6620
6843
  const filesWritten = [];
6621
6844
  for (const agent of bundle.subagents) {
@@ -6623,9 +6846,9 @@ var ClaudeAgentsWriter = {
6623
6846
  const content = `${frontmatter}
6624
6847
 
6625
6848
  ${agent.systemPrompt}`;
6626
- const agentPath = join15(agentsDir, `${agent.name}.md`);
6849
+ const agentPath = join16(agentsDir, `${agent.name}.md`);
6627
6850
  await writeFile14(agentPath, content, "utf-8");
6628
- filesWritten.push(join15(ctx.outputPath, `${agent.name}.md`));
6851
+ filesWritten.push(join16(ctx.outputPath, `${agent.name}.md`));
6629
6852
  }
6630
6853
  return {
6631
6854
  filesWritten
@@ -6661,12 +6884,12 @@ var claudeCodeAdapter = {
6661
6884
  };
6662
6885
  // ../adapters/src/codex/index.ts
6663
6886
  import { mkdirSync as mkdirSync6 } from "node:fs";
6664
- import { join as join17 } from "node:path";
6887
+ import { join as join18 } from "node:path";
6665
6888
 
6666
6889
  // ../adapters/src/writers/codex/toml.ts
6667
6890
  init_dist();
6668
6891
  import { mkdir as mkdir7, writeFile as writeFile15 } from "node:fs/promises";
6669
- import { dirname as dirname3, join as join16 } from "node:path";
6892
+ import { dirname as dirname3, join as join17 } from "node:path";
6670
6893
  var FILE_HEADER = `# Generated by OmniDev - DO NOT EDIT
6671
6894
  # Run \`omnidev sync\` to regenerate
6672
6895
 
@@ -6717,7 +6940,7 @@ var CodexTomlWriter = {
6717
6940
  if (mcps.size === 0) {
6718
6941
  return { filesWritten: [] };
6719
6942
  }
6720
- const configPath = join16(ctx.projectRoot, ctx.outputPath);
6943
+ const configPath = join17(ctx.projectRoot, ctx.outputPath);
6721
6944
  const parentDir = dirname3(configPath);
6722
6945
  await mkdir7(parentDir, { recursive: true });
6723
6946
  const mcpServers = {};
@@ -6751,7 +6974,7 @@ var codexAdapter = {
6751
6974
  { writer: CodexTomlWriter, outputPath: ".codex/config.toml" }
6752
6975
  ],
6753
6976
  async init(ctx) {
6754
- const codexDir = join17(ctx.projectRoot, ".codex");
6977
+ const codexDir = join18(ctx.projectRoot, ".codex");
6755
6978
  mkdirSync6(codexDir, { recursive: true });
6756
6979
  return {
6757
6980
  filesCreated: [".codex/"],
@@ -6770,11 +6993,11 @@ var codexAdapter = {
6770
6993
  };
6771
6994
  // ../adapters/src/cursor/index.ts
6772
6995
  import { mkdirSync as mkdirSync7 } from "node:fs";
6773
- import { join as join22 } from "node:path";
6996
+ import { join as join23 } from "node:path";
6774
6997
 
6775
6998
  // ../adapters/src/writers/cursor/agents.ts
6776
6999
  import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
6777
- import { join as join18 } from "node:path";
7000
+ import { join as join19 } from "node:path";
6778
7001
  function mapModelToCursor(model) {
6779
7002
  if (!model || model === "inherit")
6780
7003
  return "inherit";
@@ -6806,7 +7029,7 @@ function generateFrontmatter2(agent) {
6806
7029
  var CursorAgentsWriter = {
6807
7030
  id: "cursor-agents",
6808
7031
  async write(bundle, ctx) {
6809
- const agentsDir = join18(ctx.projectRoot, ctx.outputPath);
7032
+ const agentsDir = join19(ctx.projectRoot, ctx.outputPath);
6810
7033
  await mkdir8(agentsDir, { recursive: true });
6811
7034
  const filesWritten = [];
6812
7035
  for (const agent of bundle.subagents) {
@@ -6814,9 +7037,9 @@ var CursorAgentsWriter = {
6814
7037
  const content = `${frontmatter}
6815
7038
 
6816
7039
  ${agent.systemPrompt}`;
6817
- const agentPath = join18(agentsDir, `${agent.name}.md`);
7040
+ const agentPath = join19(agentsDir, `${agent.name}.md`);
6818
7041
  await writeFile16(agentPath, content, "utf-8");
6819
- filesWritten.push(join18(ctx.outputPath, `${agent.name}.md`));
7042
+ filesWritten.push(join19(ctx.outputPath, `${agent.name}.md`));
6820
7043
  }
6821
7044
  return {
6822
7045
  filesWritten
@@ -6825,11 +7048,11 @@ ${agent.systemPrompt}`;
6825
7048
  };
6826
7049
  // ../adapters/src/writers/cursor/commands.ts
6827
7050
  import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
6828
- import { join as join19 } from "node:path";
7051
+ import { join as join20 } from "node:path";
6829
7052
  var CursorCommandsWriter = {
6830
7053
  id: "cursor-commands",
6831
7054
  async write(bundle, ctx) {
6832
- const commandsDir = join19(ctx.projectRoot, ctx.outputPath);
7055
+ const commandsDir = join20(ctx.projectRoot, ctx.outputPath);
6833
7056
  await mkdir9(commandsDir, { recursive: true });
6834
7057
  const filesWritten = [];
6835
7058
  for (const command of bundle.commands) {
@@ -6838,9 +7061,9 @@ var CursorCommandsWriter = {
6838
7061
  ${command.description}
6839
7062
 
6840
7063
  ${command.prompt}`;
6841
- const commandPath = join19(commandsDir, `${command.name}.md`);
7064
+ const commandPath = join20(commandsDir, `${command.name}.md`);
6842
7065
  await writeFile17(commandPath, content, "utf-8");
6843
- filesWritten.push(join19(ctx.outputPath, `${command.name}.md`));
7066
+ filesWritten.push(join20(ctx.outputPath, `${command.name}.md`));
6844
7067
  }
6845
7068
  return {
6846
7069
  filesWritten
@@ -6849,7 +7072,7 @@ ${command.prompt}`;
6849
7072
  };
6850
7073
  // ../adapters/src/writers/cursor/mcp-json.ts
6851
7074
  import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
6852
- import { dirname as dirname4, join as join20 } from "node:path";
7075
+ import { dirname as dirname4, join as join21 } from "node:path";
6853
7076
  function buildCursorMcpConfig(mcp) {
6854
7077
  const transport = mcp.transport ?? "stdio";
6855
7078
  if (transport === "http" || transport === "sse") {
@@ -6894,7 +7117,7 @@ var CursorMcpJsonWriter = {
6894
7117
  if (mcps.size === 0) {
6895
7118
  return { filesWritten: [] };
6896
7119
  }
6897
- const configPath = join20(ctx.projectRoot, ctx.outputPath);
7120
+ const configPath = join21(ctx.projectRoot, ctx.outputPath);
6898
7121
  const parentDir = dirname4(configPath);
6899
7122
  await mkdir10(parentDir, { recursive: true });
6900
7123
  const mcpServers = {};
@@ -6919,17 +7142,17 @@ var CursorMcpJsonWriter = {
6919
7142
  };
6920
7143
  // ../adapters/src/writers/cursor/rules.ts
6921
7144
  import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
6922
- import { join as join21 } from "node:path";
7145
+ import { join as join22 } from "node:path";
6923
7146
  var CursorRulesWriter = {
6924
7147
  id: "cursor-rules",
6925
7148
  async write(bundle, ctx) {
6926
- const rulesDir = join21(ctx.projectRoot, ctx.outputPath);
7149
+ const rulesDir = join22(ctx.projectRoot, ctx.outputPath);
6927
7150
  await mkdir11(rulesDir, { recursive: true });
6928
7151
  const filesWritten = [];
6929
7152
  for (const rule of bundle.rules) {
6930
- const rulePath = join21(rulesDir, `omnidev-${rule.name}.mdc`);
7153
+ const rulePath = join22(rulesDir, `omnidev-${rule.name}.mdc`);
6931
7154
  await writeFile19(rulePath, rule.content, "utf-8");
6932
- filesWritten.push(join21(ctx.outputPath, `omnidev-${rule.name}.mdc`));
7155
+ filesWritten.push(join22(ctx.outputPath, `omnidev-${rule.name}.mdc`));
6933
7156
  }
6934
7157
  return {
6935
7158
  filesWritten
@@ -6949,7 +7172,7 @@ var cursorAdapter = {
6949
7172
  { writer: CursorMcpJsonWriter, outputPath: ".cursor/mcp.json" }
6950
7173
  ],
6951
7174
  async init(ctx) {
6952
- const rulesDir = join22(ctx.projectRoot, ".cursor", "rules");
7175
+ const rulesDir = join23(ctx.projectRoot, ".cursor", "rules");
6953
7176
  mkdirSync7(rulesDir, { recursive: true });
6954
7177
  return {
6955
7178
  filesCreated: [".cursor/rules/"],
@@ -6975,11 +7198,11 @@ var cursorAdapter = {
6975
7198
  };
6976
7199
  // ../adapters/src/opencode/index.ts
6977
7200
  import { mkdirSync as mkdirSync8 } from "node:fs";
6978
- import { join as join25 } from "node:path";
7201
+ import { join as join26 } from "node:path";
6979
7202
 
6980
7203
  // ../adapters/src/writers/opencode/agents.ts
6981
7204
  import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
6982
- import { join as join23 } from "node:path";
7205
+ import { join as join24 } from "node:path";
6983
7206
  function mapModelToOpenCode(model) {
6984
7207
  if (!model || model === "inherit")
6985
7208
  return;
@@ -7057,7 +7280,7 @@ function generateFrontmatter3(agent) {
7057
7280
  var OpenCodeAgentsWriter = {
7058
7281
  id: "opencode-agents",
7059
7282
  async write(bundle, ctx) {
7060
- const agentsDir = join23(ctx.projectRoot, ctx.outputPath);
7283
+ const agentsDir = join24(ctx.projectRoot, ctx.outputPath);
7061
7284
  await mkdir12(agentsDir, { recursive: true });
7062
7285
  const filesWritten = [];
7063
7286
  for (const agent of bundle.subagents) {
@@ -7065,9 +7288,9 @@ var OpenCodeAgentsWriter = {
7065
7288
  const content = `${frontmatter}
7066
7289
 
7067
7290
  ${agent.systemPrompt}`;
7068
- const agentPath = join23(agentsDir, `${agent.name}.md`);
7291
+ const agentPath = join24(agentsDir, `${agent.name}.md`);
7069
7292
  await writeFile20(agentPath, content, "utf-8");
7070
- filesWritten.push(join23(ctx.outputPath, `${agent.name}.md`));
7293
+ filesWritten.push(join24(ctx.outputPath, `${agent.name}.md`));
7071
7294
  }
7072
7295
  return {
7073
7296
  filesWritten
@@ -7076,7 +7299,7 @@ ${agent.systemPrompt}`;
7076
7299
  };
7077
7300
  // ../adapters/src/writers/opencode/commands.ts
7078
7301
  import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
7079
- import { join as join24 } from "node:path";
7302
+ import { join as join25 } from "node:path";
7080
7303
  function generateFrontmatter4(command) {
7081
7304
  const lines = ["---"];
7082
7305
  lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
@@ -7093,7 +7316,7 @@ function generateFrontmatter4(command) {
7093
7316
  var OpenCodeCommandsWriter = {
7094
7317
  id: "opencode-commands",
7095
7318
  async write(bundle, ctx) {
7096
- const commandsDir = join24(ctx.projectRoot, ctx.outputPath);
7319
+ const commandsDir = join25(ctx.projectRoot, ctx.outputPath);
7097
7320
  await mkdir13(commandsDir, { recursive: true });
7098
7321
  const filesWritten = [];
7099
7322
  for (const command of bundle.commands) {
@@ -7101,9 +7324,9 @@ var OpenCodeCommandsWriter = {
7101
7324
  const content = `${frontmatter}
7102
7325
 
7103
7326
  ${command.prompt}`;
7104
- const commandPath = join24(commandsDir, `${command.name}.md`);
7327
+ const commandPath = join25(commandsDir, `${command.name}.md`);
7105
7328
  await writeFile21(commandPath, content, "utf-8");
7106
- filesWritten.push(join24(ctx.outputPath, `${command.name}.md`));
7329
+ filesWritten.push(join25(ctx.outputPath, `${command.name}.md`));
7107
7330
  }
7108
7331
  return {
7109
7332
  filesWritten
@@ -7121,7 +7344,7 @@ var opencodeAdapter = {
7121
7344
  { writer: OpenCodeCommandsWriter, outputPath: ".opencode/commands/" }
7122
7345
  ],
7123
7346
  async init(ctx) {
7124
- const opencodeDir = join25(ctx.projectRoot, ".opencode");
7347
+ const opencodeDir = join26(ctx.projectRoot, ".opencode");
7125
7348
  mkdirSync8(opencodeDir, { recursive: true });
7126
7349
  return {
7127
7350
  filesCreated: [".opencode/"],
@@ -7175,7 +7398,7 @@ async function inferCapabilityId(source, sourceType) {
7175
7398
  }
7176
7399
  async function runAddCap(flags, name) {
7177
7400
  try {
7178
- if (!existsSync23("omni.toml")) {
7401
+ if (!existsSync24("omni.toml")) {
7179
7402
  console.log("✗ No config file found");
7180
7403
  console.log(" Run: omnidev init");
7181
7404
  process.exit(1);
@@ -7198,7 +7421,7 @@ async function runAddCap(flags, name) {
7198
7421
  sourceType = "local";
7199
7422
  const localPath = flags.local.startsWith("file://") ? flags.local.slice(7) : flags.local;
7200
7423
  source = `file://${localPath}`;
7201
- if (!existsSync23(localPath)) {
7424
+ if (!existsSync24(localPath)) {
7202
7425
  console.error(`✗ Local path not found: ${localPath}`);
7203
7426
  process.exit(1);
7204
7427
  }
@@ -7290,7 +7513,7 @@ async function runAddCap(flags, name) {
7290
7513
  }
7291
7514
  async function runAddMcp(flags, name) {
7292
7515
  try {
7293
- if (!existsSync23("omni.toml")) {
7516
+ if (!existsSync24("omni.toml")) {
7294
7517
  console.log("✗ No config file found");
7295
7518
  console.log(" Run: omnidev init");
7296
7519
  process.exit(1);
@@ -7577,9 +7800,9 @@ var addRoutes = buildRouteMap({
7577
7800
  });
7578
7801
 
7579
7802
  // src/commands/capability.ts
7580
- import { existsSync as existsSync24, mkdirSync as mkdirSync9 } from "node:fs";
7803
+ import { existsSync as existsSync25, mkdirSync as mkdirSync9 } from "node:fs";
7581
7804
  import { writeFile as writeFile22 } from "node:fs/promises";
7582
- import { join as join26 } from "node:path";
7805
+ import { join as join27 } from "node:path";
7583
7806
  import { input } from "@inquirer/prompts";
7584
7807
  init_src();
7585
7808
  import { buildCommand as buildCommand2, buildRouteMap as buildRouteMap2 } from "@stricli/core";
@@ -7768,7 +7991,7 @@ function generateGitignore(programmatic) {
7768
7991
  }
7769
7992
  async function runCapabilityNew(flags, capabilityId) {
7770
7993
  try {
7771
- if (!existsSync24(".omni")) {
7994
+ if (!existsSync25(".omni")) {
7772
7995
  console.error("✗ OmniDev is not initialized in this directory.");
7773
7996
  console.log("");
7774
7997
  console.log(" Run: omnidev init");
@@ -7792,28 +8015,28 @@ async function runCapabilityNew(flags, capabilityId) {
7792
8015
  default: defaultPath
7793
8016
  });
7794
8017
  }
7795
- if (existsSync24(capabilityDir)) {
8018
+ if (existsSync25(capabilityDir)) {
7796
8019
  console.error(`✗ Directory already exists at ${capabilityDir}`);
7797
8020
  process.exit(1);
7798
8021
  }
7799
8022
  const name = toTitleCase(id);
7800
8023
  mkdirSync9(capabilityDir, { recursive: true });
7801
8024
  const capabilityToml = generateCapabilityToml2({ id, name });
7802
- await writeFile22(join26(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
7803
- const skillDir = join26(capabilityDir, "skills", "getting-started");
8025
+ await writeFile22(join27(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
8026
+ const skillDir = join27(capabilityDir, "skills", "getting-started");
7804
8027
  mkdirSync9(skillDir, { recursive: true });
7805
- await writeFile22(join26(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
7806
- const rulesDir = join26(capabilityDir, "rules");
8028
+ await writeFile22(join27(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
8029
+ const rulesDir = join27(capabilityDir, "rules");
7807
8030
  mkdirSync9(rulesDir, { recursive: true });
7808
- await writeFile22(join26(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
7809
- const hooksDir = join26(capabilityDir, "hooks");
8031
+ await writeFile22(join27(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
8032
+ const hooksDir = join27(capabilityDir, "hooks");
7810
8033
  mkdirSync9(hooksDir, { recursive: true });
7811
- await writeFile22(join26(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
7812
- await writeFile22(join26(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
7813
- await writeFile22(join26(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
8034
+ await writeFile22(join27(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
8035
+ await writeFile22(join27(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
8036
+ await writeFile22(join27(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
7814
8037
  if (flags.programmatic) {
7815
- await writeFile22(join26(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
7816
- await writeFile22(join26(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
8038
+ await writeFile22(join27(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
8039
+ await writeFile22(join27(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
7817
8040
  }
7818
8041
  console.log(`✓ Created capability: ${name}`);
7819
8042
  console.log(` Location: ${capabilityDir}`);
@@ -7969,7 +8192,7 @@ var capabilityRoutes = buildRouteMap2({
7969
8192
  });
7970
8193
 
7971
8194
  // src/commands/doctor.ts
7972
- import { existsSync as existsSync25 } from "node:fs";
8195
+ import { existsSync as existsSync26 } from "node:fs";
7973
8196
  import { execFile } from "node:child_process";
7974
8197
  import { readFile as readFile20 } from "node:fs/promises";
7975
8198
  import { promisify } from "node:util";
@@ -8016,50 +8239,52 @@ async function runDoctor() {
8016
8239
  async function checkPackageManager() {
8017
8240
  const execFileAsync = promisify(execFile);
8018
8241
  try {
8019
- const { stdout } = await execFileAsync("bun", ["--version"]);
8020
- const version2 = stdout.trim();
8021
- const firstPart = version2.split(".")[0];
8022
- if (!firstPart) {
8242
+ const { stdout: npmStdout } = await execFileAsync("npm", ["--version"]);
8243
+ const npmVersion = npmStdout.trim();
8244
+ try {
8245
+ const { stdout: bunStdout } = await execFileAsync("bun", ["--version"]);
8246
+ const bunVersion = bunStdout.trim();
8247
+ const firstPart = bunVersion.split(".")[0];
8248
+ if (!firstPart) {
8249
+ return {
8250
+ name: "Package Manager",
8251
+ passed: false,
8252
+ message: `Invalid Bun version format: ${bunVersion}`,
8253
+ fix: "Reinstall Bun: curl -fsSL https://bun.sh/install | bash"
8254
+ };
8255
+ }
8256
+ const major = Number.parseInt(firstPart, 10);
8257
+ if (major < 1) {
8258
+ return {
8259
+ name: "Package Manager",
8260
+ passed: false,
8261
+ message: `npm v${npmVersion}; bun v${bunVersion}`,
8262
+ fix: "Upgrade Bun: curl -fsSL https://bun.sh/install | bash"
8263
+ };
8264
+ }
8023
8265
  return {
8024
8266
  name: "Package Manager",
8025
- passed: false,
8026
- message: `Invalid Bun version format: ${version2}`,
8027
- fix: "Reinstall Bun: curl -fsSL https://bun.sh/install | bash"
8267
+ passed: true,
8268
+ message: `npm v${npmVersion}; bun v${bunVersion}`
8028
8269
  };
8029
- }
8030
- const major = Number.parseInt(firstPart, 10);
8031
- if (major < 1) {
8270
+ } catch {
8032
8271
  return {
8033
8272
  name: "Package Manager",
8034
- passed: false,
8035
- message: `bun v${version2}`,
8036
- fix: "Upgrade Bun: curl -fsSL https://bun.sh/install | bash"
8273
+ passed: true,
8274
+ message: `npm v${npmVersion}`
8037
8275
  };
8038
8276
  }
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
8277
  } catch {
8053
8278
  return {
8054
8279
  name: "Package Manager",
8055
8280
  passed: false,
8056
- message: "Neither Bun nor npm is installed",
8057
- fix: "Install Bun (recommended): curl -fsSL https://bun.sh/install | bash"
8281
+ message: "npm is not installed",
8282
+ fix: "Install Node.js and npm: https://nodejs.org/"
8058
8283
  };
8059
8284
  }
8060
8285
  }
8061
8286
  async function checkOmniLocalDir() {
8062
- const exists = existsSync25(".omni");
8287
+ const exists = existsSync26(".omni");
8063
8288
  if (!exists) {
8064
8289
  return {
8065
8290
  name: ".omni/ directory",
@@ -8076,7 +8301,7 @@ async function checkOmniLocalDir() {
8076
8301
  }
8077
8302
  async function checkConfig() {
8078
8303
  const configPath = "omni.toml";
8079
- if (!existsSync25(configPath)) {
8304
+ if (!existsSync26(configPath)) {
8080
8305
  return {
8081
8306
  name: "Configuration",
8082
8307
  passed: false,
@@ -8103,7 +8328,7 @@ async function checkConfig() {
8103
8328
  }
8104
8329
  async function checkRootGitignore() {
8105
8330
  const gitignorePath = ".gitignore";
8106
- if (!existsSync25(gitignorePath)) {
8331
+ if (!existsSync26(gitignorePath)) {
8107
8332
  return {
8108
8333
  name: "Root .gitignore",
8109
8334
  passed: false,
@@ -8137,7 +8362,7 @@ async function checkRootGitignore() {
8137
8362
  }
8138
8363
  async function checkCapabilitiesDir() {
8139
8364
  const capabilitiesDirPath = ".omni/capabilities";
8140
- if (!existsSync25(capabilitiesDirPath)) {
8365
+ if (!existsSync26(capabilitiesDirPath)) {
8141
8366
  return {
8142
8367
  name: "Capabilities Directory",
8143
8368
  passed: true,
@@ -8153,7 +8378,7 @@ async function checkCapabilitiesDir() {
8153
8378
 
8154
8379
  // src/commands/init.ts
8155
8380
  import { exec } from "node:child_process";
8156
- import { existsSync as existsSync26, mkdirSync as mkdirSync10 } from "node:fs";
8381
+ import { existsSync as existsSync27, mkdirSync as mkdirSync10 } from "node:fs";
8157
8382
  import { readFile as readFile21, writeFile as writeFile23 } from "node:fs/promises";
8158
8383
  import { promisify as promisify2 } from "node:util";
8159
8384
  init_src();
@@ -8223,7 +8448,7 @@ async function runInit(_flags, providerArg) {
8223
8448
  }
8224
8449
  }
8225
8450
  await writeEnabledProviders(providerIds);
8226
- if (!existsSync26("omni.toml")) {
8451
+ if (!existsSync27("omni.toml")) {
8227
8452
  await writeConfig({
8228
8453
  profiles: {
8229
8454
  default: {
@@ -8239,7 +8464,7 @@ async function runInit(_flags, providerArg) {
8239
8464
  });
8240
8465
  await setActiveProfile("default");
8241
8466
  }
8242
- if (!existsSync26("OMNI.md")) {
8467
+ if (!existsSync27("OMNI.md")) {
8243
8468
  await writeFile23("OMNI.md", generateOmniMdTemplate(), "utf-8");
8244
8469
  }
8245
8470
  const config3 = await loadConfig();
@@ -8317,7 +8542,7 @@ async function addProviderFilesToGitignore(entries) {
8317
8542
  async function addToGitignore(entriesToAdd, sectionHeader) {
8318
8543
  const gitignorePath = ".gitignore";
8319
8544
  let content = "";
8320
- if (existsSync26(gitignorePath)) {
8545
+ if (existsSync27(gitignorePath)) {
8321
8546
  content = await readFile21(gitignorePath, "utf-8");
8322
8547
  }
8323
8548
  const lines = content.split(`
@@ -8349,7 +8574,7 @@ async function getTrackedProviderFiles(files) {
8349
8574
  }
8350
8575
 
8351
8576
  // src/commands/profile.ts
8352
- import { existsSync as existsSync27 } from "node:fs";
8577
+ import { existsSync as existsSync28 } from "node:fs";
8353
8578
  init_src();
8354
8579
  import { buildCommand as buildCommand5, buildRouteMap as buildRouteMap3 } from "@stricli/core";
8355
8580
  var listCommand2 = buildCommand5({
@@ -8393,7 +8618,7 @@ var profileRoutes = buildRouteMap3({
8393
8618
  });
8394
8619
  async function runProfileList() {
8395
8620
  try {
8396
- if (!existsSync27("omni.toml")) {
8621
+ if (!existsSync28("omni.toml")) {
8397
8622
  console.log("✗ No config file found");
8398
8623
  console.log(" Run: omnidev init");
8399
8624
  process.exit(1);
@@ -8433,7 +8658,7 @@ async function runProfileList() {
8433
8658
  }
8434
8659
  async function runProfileSet(profileName) {
8435
8660
  try {
8436
- if (!existsSync27("omni.toml")) {
8661
+ if (!existsSync28("omni.toml")) {
8437
8662
  console.log("✗ No config file found");
8438
8663
  console.log(" Run: omnidev init");
8439
8664
  process.exit(1);
@@ -8582,7 +8807,7 @@ var providerRoutes = buildRouteMap4({
8582
8807
 
8583
8808
  // src/commands/security.ts
8584
8809
  init_src();
8585
- import { existsSync as existsSync28 } from "node:fs";
8810
+ import { existsSync as existsSync29 } from "node:fs";
8586
8811
  import { buildCommand as buildCommand7, buildRouteMap as buildRouteMap5 } from "@stricli/core";
8587
8812
  var VALID_FINDING_TYPES = [
8588
8813
  "unicode_bidi",
@@ -8621,7 +8846,9 @@ async function filterAllowedFindings(summary, options = {}) {
8621
8846
  symlink_escape: 0,
8622
8847
  symlink_absolute: 0,
8623
8848
  suspicious_script: 0,
8624
- binary_file: 0
8849
+ binary_file: 0,
8850
+ hidden_command: 0,
8851
+ network_request: 0
8625
8852
  };
8626
8853
  const findingsBySeverity = {
8627
8854
  low: 0,
@@ -8699,7 +8926,7 @@ function formatFindingsWithHints(summary) {
8699
8926
  }
8700
8927
  async function runSecurityIssues(flags = {}) {
8701
8928
  try {
8702
- if (!existsSync28("omni.toml")) {
8929
+ if (!existsSync29("omni.toml")) {
8703
8930
  console.log("No config file found");
8704
8931
  console.log(" Run: omnidev init");
8705
8932
  process.exit(1);
@@ -8954,7 +9181,7 @@ var securityRoutes = buildRouteMap5({
8954
9181
  });
8955
9182
 
8956
9183
  // src/commands/sync.ts
8957
- import { existsSync as existsSync29 } from "node:fs";
9184
+ import { existsSync as existsSync30 } from "node:fs";
8958
9185
  init_src();
8959
9186
  import { buildCommand as buildCommand8 } from "@stricli/core";
8960
9187
  var PROVIDERS_STATE_PATH = ".omni/state/providers.json";
@@ -8972,7 +9199,7 @@ async function runSync() {
8972
9199
  const config3 = await loadConfig();
8973
9200
  const activeProfile = await getActiveProfile() ?? "default";
8974
9201
  let adapters = await getEnabledAdapters();
8975
- if (!existsSync29(PROVIDERS_STATE_PATH) || adapters.length === 0) {
9202
+ if (!existsSync30(PROVIDERS_STATE_PATH) || adapters.length === 0) {
8976
9203
  console.log("No providers configured yet. Select your provider(s):");
8977
9204
  const providerIds = await promptForProviders();
8978
9205
  await writeEnabledProviders(providerIds);
@@ -9182,9 +9409,9 @@ async function buildDynamicApp() {
9182
9409
  security: securityRoutes
9183
9410
  };
9184
9411
  debug("Core routes registered", Object.keys(routes));
9185
- const configPath = join27(process.cwd(), "omni.toml");
9186
- debug("Checking for config", { configPath, exists: existsSync30(configPath), cwd: process.cwd() });
9187
- if (existsSync30(configPath)) {
9412
+ const configPath = join28(process.cwd(), "omni.toml");
9413
+ debug("Checking for config", { configPath, exists: existsSync31(configPath), cwd: process.cwd() });
9414
+ if (existsSync31(configPath)) {
9188
9415
  try {
9189
9416
  debug("Loading capability commands...");
9190
9417
  const capabilityCommands = await loadCapabilityCommands();
@@ -9259,25 +9486,25 @@ async function loadCapabilityCommands() {
9259
9486
  return commands;
9260
9487
  }
9261
9488
  async function loadCapabilityExport(capability3) {
9262
- const capabilityPath = join27(process.cwd(), capability3.path);
9263
- const builtIndexPath = join27(capabilityPath, "dist", "index.js");
9264
- const jsIndexPath = join27(capabilityPath, "index.js");
9265
- const tsIndexPath = join27(capabilityPath, "index.ts");
9489
+ const capabilityPath = join28(process.cwd(), capability3.path);
9490
+ const builtIndexPath = join28(capabilityPath, "dist", "index.js");
9491
+ const jsIndexPath = join28(capabilityPath, "index.js");
9492
+ const tsIndexPath = join28(capabilityPath, "index.ts");
9266
9493
  debug(`Checking entry points for '${capability3.id}'`, {
9267
9494
  capabilityPath,
9268
9495
  builtIndexPath,
9269
- builtExists: existsSync30(builtIndexPath),
9496
+ builtExists: existsSync31(builtIndexPath),
9270
9497
  jsIndexPath,
9271
- jsExists: existsSync30(jsIndexPath),
9498
+ jsExists: existsSync31(jsIndexPath),
9272
9499
  tsIndexPath,
9273
- tsExists: existsSync30(tsIndexPath)
9500
+ tsExists: existsSync31(tsIndexPath)
9274
9501
  });
9275
9502
  let indexPath = null;
9276
- if (existsSync30(builtIndexPath)) {
9503
+ if (existsSync31(builtIndexPath)) {
9277
9504
  indexPath = builtIndexPath;
9278
- } else if (existsSync30(jsIndexPath)) {
9505
+ } else if (existsSync31(jsIndexPath)) {
9279
9506
  indexPath = jsIndexPath;
9280
- } else if (existsSync30(tsIndexPath)) {
9507
+ } else if (existsSync31(tsIndexPath)) {
9281
9508
  indexPath = tsIndexPath;
9282
9509
  }
9283
9510
  if (!indexPath) {