@omnidev-ai/cli 0.18.1 → 0.19.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 +725 -240
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1833,47 +1833,23 @@ function resolveCapabilityRoot(content, capabilityPath) {
1833
1833
  }
1834
1834
  return result;
1835
1835
  }
1836
- function resolveCapabilityRootInConfig(config, capabilityPath) {
1837
- const result = {};
1838
- if (config.description !== undefined) {
1839
- result.description = config.description;
1836
+ function resolveCapabilityRootInValue(value, capabilityPath) {
1837
+ if (typeof value === "string") {
1838
+ return resolveCapabilityRoot(value, capabilityPath);
1840
1839
  }
1841
- const events = [
1842
- "PreToolUse",
1843
- "PostToolUse",
1844
- "PermissionRequest",
1845
- "UserPromptSubmit",
1846
- "Stop",
1847
- "SubagentStop",
1848
- "Notification",
1849
- "SessionStart",
1850
- "SessionEnd",
1851
- "PreCompact"
1852
- ];
1853
- for (const event of events) {
1854
- const matchers = config[event];
1855
- if (matchers) {
1856
- result[event] = matchers.map((matcher) => ({
1857
- ...matcher,
1858
- hooks: matcher.hooks.map((hook) => {
1859
- if (hook.type === "command") {
1860
- return {
1861
- ...hook,
1862
- command: resolveCapabilityRoot(hook.command, capabilityPath)
1863
- };
1864
- }
1865
- if (hook.type === "prompt") {
1866
- return {
1867
- ...hook,
1868
- prompt: resolveCapabilityRoot(hook.prompt, capabilityPath)
1869
- };
1870
- }
1871
- return hook;
1872
- })
1873
- }));
1874
- }
1840
+ if (Array.isArray(value)) {
1841
+ return value.map((entry) => resolveCapabilityRootInValue(entry, capabilityPath));
1875
1842
  }
1876
- return result;
1843
+ if (value && typeof value === "object") {
1844
+ return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
1845
+ key,
1846
+ resolveCapabilityRootInValue(entry, capabilityPath)
1847
+ ]));
1848
+ }
1849
+ return value;
1850
+ }
1851
+ function resolveCapabilityRootInConfig(config, capabilityPath) {
1852
+ return resolveCapabilityRootInValue(config, capabilityPath);
1877
1853
  }
1878
1854
  var REVERSE_MAPPINGS;
1879
1855
  var init_variables = __esm(() => {
@@ -2183,6 +2159,55 @@ function loadHooksFromCapability(capabilityPath, options) {
2183
2159
  }
2184
2160
  return loadJsonHooksFiles(capabilityPath, hooksJsonInDir, hooksJsonAtRoot, hooksDir, opts);
2185
2161
  }
2162
+ function splitHooksTomlConfig(parsed) {
2163
+ const topLevelIssues = [];
2164
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
2165
+ return {
2166
+ sharedConfig: parsed,
2167
+ providerConfigs: undefined,
2168
+ topLevelIssues
2169
+ };
2170
+ }
2171
+ const parsedObj = parsed;
2172
+ const sharedConfig = {};
2173
+ const providerConfigs = {};
2174
+ for (const [key, value] of Object.entries(parsedObj)) {
2175
+ if (key === "description" || HOOK_EVENTS.includes(key)) {
2176
+ sharedConfig[key] = value;
2177
+ continue;
2178
+ }
2179
+ if (PROVIDER_SECTION_KEYS.includes(key)) {
2180
+ if (value && typeof value === "object" && !Array.isArray(value)) {
2181
+ providerConfigs[key] = value;
2182
+ } else {
2183
+ topLevelIssues.push({
2184
+ severity: "error",
2185
+ code: "HOOKS_INVALID_TOML",
2186
+ message: `[${key}] must be a table`
2187
+ });
2188
+ }
2189
+ continue;
2190
+ }
2191
+ topLevelIssues.push({
2192
+ severity: "error",
2193
+ code: "HOOKS_UNKNOWN_EVENT",
2194
+ message: `Unknown hook event: "${key}"`,
2195
+ suggestion: `Valid events are: ${HOOK_EVENTS.join(", ")}, plus [claude] and [codex] sections`
2196
+ });
2197
+ }
2198
+ return {
2199
+ sharedConfig,
2200
+ providerConfigs: Object.keys(providerConfigs).length > 0 ? providerConfigs : undefined,
2201
+ topLevelIssues
2202
+ };
2203
+ }
2204
+ function prefixValidationIssues(issues, sectionLabel) {
2205
+ return issues.map((issue) => ({
2206
+ ...issue,
2207
+ message: `[${sectionLabel}] ${issue.message}`,
2208
+ ...issue.suggestion ? { suggestion: `[${sectionLabel}] ${issue.suggestion}` } : {}
2209
+ }));
2210
+ }
2186
2211
  function loadTomlHooks(capabilityPath, configPath, hooksDir, opts) {
2187
2212
  let rawContent;
2188
2213
  try {
@@ -2234,25 +2259,56 @@ function loadTomlHooks(capabilityPath, configPath, hooksDir, opts) {
2234
2259
  loadError: `Invalid TOML: ${error instanceof Error ? error.message : String(error)}`
2235
2260
  };
2236
2261
  }
2262
+ const {
2263
+ sharedConfig,
2264
+ providerConfigs: rawProviderConfigs,
2265
+ topLevelIssues
2266
+ } = splitHooksTomlConfig(parsed);
2237
2267
  let validation;
2238
2268
  if (opts.validate) {
2239
- validation = validateHooksConfig(parsed, {
2269
+ const sharedValidation = validateHooksConfig(sharedConfig, {
2240
2270
  basePath: hooksDir,
2241
2271
  checkScripts: opts.checkScripts ?? false
2242
2272
  });
2273
+ const providerErrors = [];
2274
+ const providerWarnings = [];
2275
+ for (const [provider, providerConfig] of Object.entries(rawProviderConfigs ?? {})) {
2276
+ const providerValidation = validateHooksConfig(providerConfig, {
2277
+ basePath: hooksDir,
2278
+ checkScripts: opts.checkScripts ?? false
2279
+ });
2280
+ providerErrors.push(...prefixValidationIssues(providerValidation.errors, provider));
2281
+ providerWarnings.push(...prefixValidationIssues(providerValidation.warnings, provider));
2282
+ }
2283
+ validation = {
2284
+ valid: sharedValidation.valid && topLevelIssues.length === 0 && providerErrors.length === 0,
2285
+ errors: [...topLevelIssues, ...sharedValidation.errors, ...providerErrors],
2286
+ warnings: [...sharedValidation.warnings, ...providerWarnings]
2287
+ };
2243
2288
  } else {
2244
2289
  validation = createEmptyValidationResult();
2245
2290
  }
2246
- let config = validation.valid ? parsed : createEmptyHooksConfig();
2291
+ let config = validation.valid ? sharedConfig : createEmptyHooksConfig();
2292
+ let providerConfigs = validation.valid ? rawProviderConfigs : undefined;
2247
2293
  if (opts.resolveCapabilityRoot && validation.valid) {
2248
2294
  config = resolveCapabilityRootInConfig(config, capabilityPath);
2295
+ if (providerConfigs) {
2296
+ providerConfigs = Object.fromEntries(Object.entries(providerConfigs).map(([provider, providerConfig]) => [
2297
+ provider,
2298
+ resolveCapabilityRootInValue(providerConfig, capabilityPath)
2299
+ ]));
2300
+ }
2249
2301
  }
2250
- return {
2302
+ const result = {
2251
2303
  config,
2252
2304
  validation,
2253
2305
  found: true,
2254
2306
  configPath
2255
2307
  };
2308
+ if (providerConfigs) {
2309
+ result.providerConfigs = providerConfigs;
2310
+ }
2311
+ return result;
2256
2312
  }
2257
2313
  function loadJsonHooksFiles(capabilityPath, hooksJsonInDir, hooksJsonAtRoot, hooksDir, opts) {
2258
2314
  const configs = [];
@@ -2348,6 +2404,7 @@ function loadCapabilityHooks(capabilityName, capabilityPath, options) {
2348
2404
  capabilityName,
2349
2405
  capabilityPath,
2350
2406
  config: result.config,
2407
+ ...result.providerConfigs ? { providerConfigs: result.providerConfigs } : {},
2351
2408
  validation: result.validation
2352
2409
  };
2353
2410
  }
@@ -2363,6 +2420,7 @@ function getHooksDirectory(capabilityPath) {
2363
2420
  function getHooksConfigPath(capabilityPath) {
2364
2421
  return join3(capabilityPath, HOOKS_DIRECTORY, HOOKS_CONFIG_FILENAME);
2365
2422
  }
2423
+ var PROVIDER_SECTION_KEYS;
2366
2424
  var init_loader = __esm(() => {
2367
2425
  init_dist();
2368
2426
  init_constants();
@@ -2370,6 +2428,7 @@ var init_loader = __esm(() => {
2370
2428
  init_variables();
2371
2429
  init_json_loader();
2372
2430
  init_constants();
2431
+ PROVIDER_SECTION_KEYS = ["claude", "codex"];
2373
2432
  });
2374
2433
 
2375
2434
  // ../core/src/providers.ts
@@ -2668,75 +2727,235 @@ import { readFile as readFile6 } from "node:fs/promises";
2668
2727
  import { basename as basename4, join as join7 } from "node:path";
2669
2728
  async function loadSubagents(capabilityPath, capabilityId) {
2670
2729
  const subagents = [];
2671
- const possibleDirNames = ["subagents", "agents", "agent", "subagent"];
2672
- for (const dirName of possibleDirNames) {
2730
+ for (const dirName of POSSIBLE_DIR_NAMES) {
2673
2731
  const dir = join7(capabilityPath, dirName);
2674
2732
  if (!existsSync9(dir)) {
2675
2733
  continue;
2676
2734
  }
2735
+ const rootSubagent = await parseSubagentDirectory(dir, capabilityId);
2736
+ if (rootSubagent) {
2737
+ subagents.push(rootSubagent);
2738
+ }
2677
2739
  const entries = readdirSync5(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
2678
2740
  for (const entry of entries) {
2679
2741
  if (entry.isDirectory()) {
2680
- let subagentPath = join7(dir, entry.name, "SUBAGENT.md");
2681
- if (!existsSync9(subagentPath)) {
2682
- subagentPath = join7(dir, entry.name, "AGENT.md");
2683
- }
2684
- if (existsSync9(subagentPath)) {
2685
- const subagent = await parseSubagentFile(subagentPath, capabilityId);
2742
+ const subagent = await parseSubagentDirectory(join7(dir, entry.name), capabilityId);
2743
+ if (subagent) {
2686
2744
  subagents.push(subagent);
2687
2745
  }
2688
2746
  } else if (entry.isFile() && entry.name.endsWith(".md")) {
2747
+ if (PROMPT_FILE_NAMES.includes(entry.name) || LEGACY_AGENT_FILES.includes(entry.name)) {
2748
+ continue;
2749
+ }
2689
2750
  const subagentPath = join7(dir, entry.name);
2690
- const subagent = await parseSubagentFile(subagentPath, capabilityId);
2691
- subagents.push(subagent);
2751
+ const content = await readFile6(subagentPath, "utf-8");
2752
+ subagents.push(parseLegacySubagentMarkdown(content, capabilityId, subagentPath, basename4(subagentPath, ".md")));
2692
2753
  }
2693
2754
  }
2694
2755
  }
2695
2756
  return subagents;
2696
2757
  }
2697
- async function parseSubagentFile(filePath, capabilityId) {
2698
- const content = await readFile6(filePath, "utf-8");
2758
+ function parseLegacySubagentMarkdown(content, capabilityId, sourceLabel, inferredName) {
2699
2759
  const parsed = parseFrontmatterWithMarkdown(content);
2700
2760
  if (!parsed) {
2701
- throw new Error(`Invalid SUBAGENT.md format at ${filePath}: missing YAML frontmatter`);
2761
+ throw new Error(`Invalid SUBAGENT.md format at ${sourceLabel}: missing YAML frontmatter`);
2702
2762
  }
2703
2763
  const frontmatter = parsed.frontmatter;
2704
- const systemPrompt = parsed.markdown;
2705
- const inferredName = basename4(filePath, ".md").replace(/^SUBAGENT$/i, "").replace(/^AGENT$/i, "");
2706
- const name = frontmatter.name || inferredName;
2764
+ const name = frontmatter.name || inferredName?.replace(/^SUBAGENT$/i, "").replace(/^AGENT$/i, "") || undefined;
2707
2765
  if (!name || !frontmatter.description) {
2708
- throw new Error(`Invalid SUBAGENT.md at ${filePath}: name and description required`);
2766
+ throw new Error(`Invalid SUBAGENT.md at ${sourceLabel}: name and description required`);
2709
2767
  }
2710
- const result = {
2711
- name,
2712
- description: frontmatter.description,
2713
- systemPrompt: systemPrompt.trim(),
2714
- capabilityId
2715
- };
2768
+ const claude = {};
2716
2769
  if (frontmatter.tools) {
2717
- result.tools = parseCommaSeparatedList(frontmatter.tools);
2770
+ claude.tools = parseCommaSeparatedList(frontmatter.tools);
2718
2771
  }
2719
2772
  if (frontmatter.disallowedTools) {
2720
- result.disallowedTools = parseCommaSeparatedList(frontmatter.disallowedTools);
2773
+ claude.disallowedTools = parseCommaSeparatedList(frontmatter.disallowedTools);
2721
2774
  }
2722
2775
  if (frontmatter.model) {
2723
- result.model = frontmatter.model;
2776
+ claude.model = frontmatter.model;
2724
2777
  }
2725
2778
  if (frontmatter.permissionMode) {
2726
- result.permissionMode = frontmatter.permissionMode;
2779
+ claude.permissionMode = frontmatter.permissionMode;
2727
2780
  }
2728
2781
  if (frontmatter.skills) {
2729
- result.skills = parseCommaSeparatedList(frontmatter.skills);
2782
+ claude.skills = parseCommaSeparatedList(frontmatter.skills);
2730
2783
  }
2731
2784
  if (frontmatter.hooks) {
2732
- result.hooks = frontmatter.hooks;
2785
+ claude.hooks = frontmatter.hooks;
2733
2786
  }
2734
- return result;
2787
+ const subagent = {
2788
+ name,
2789
+ description: frontmatter.description,
2790
+ systemPrompt: parsed.markdown.trim(),
2791
+ capabilityId
2792
+ };
2793
+ if (hasClaudeConfig(claude)) {
2794
+ subagent.claude = claude;
2795
+ }
2796
+ return withClaudeCompatibilityAliases(subagent);
2797
+ }
2798
+ function parseSubagentManifest(agentTomlContent, promptContent, capabilityId, sourceLabel) {
2799
+ let parsed;
2800
+ try {
2801
+ parsed = parse(agentTomlContent);
2802
+ } catch (error) {
2803
+ const message = error instanceof Error ? error.message : String(error);
2804
+ throw new Error(`Invalid agent.toml at ${sourceLabel}: ${message}`);
2805
+ }
2806
+ if (typeof parsed.name !== "string" || parsed.name.trim().length === 0) {
2807
+ throw new Error(`Invalid agent.toml at ${sourceLabel}: name is required`);
2808
+ }
2809
+ if (typeof parsed.description !== "string" || parsed.description.trim().length === 0) {
2810
+ throw new Error(`Invalid agent.toml at ${sourceLabel}: description is required`);
2811
+ }
2812
+ const claude = parseClaudeConfig(parsed.claude, sourceLabel);
2813
+ const codex = parseCodexConfig(parsed.codex, sourceLabel);
2814
+ const subagent = {
2815
+ name: parsed.name.trim(),
2816
+ description: parsed.description.trim(),
2817
+ systemPrompt: promptContent.trim(),
2818
+ capabilityId
2819
+ };
2820
+ if (claude) {
2821
+ subagent.claude = claude;
2822
+ }
2823
+ if (codex) {
2824
+ subagent.codex = codex;
2825
+ }
2826
+ return withClaudeCompatibilityAliases(subagent);
2827
+ }
2828
+ async function parseSubagentDirectory(dirPath, capabilityId) {
2829
+ const manifestPath = findFirstExisting(dirPath, MANIFEST_FILE_NAMES);
2830
+ const promptPath = findFirstExisting(dirPath, PROMPT_FILE_NAMES);
2831
+ if (manifestPath || promptPath) {
2832
+ if (!manifestPath || !promptPath) {
2833
+ throw new Error(`Invalid subagent directory at ${dirPath}: agent.toml and prompt.md must both be present`);
2834
+ }
2835
+ const [agentTomlContent, promptContent] = await Promise.all([
2836
+ readFile6(manifestPath, "utf-8"),
2837
+ readFile6(promptPath, "utf-8")
2838
+ ]);
2839
+ return parseSubagentManifest(agentTomlContent, promptContent, capabilityId, manifestPath);
2840
+ }
2841
+ const legacyPath = findFirstExisting(dirPath, LEGACY_AGENT_FILES);
2842
+ if (!legacyPath) {
2843
+ return null;
2844
+ }
2845
+ const content = await readFile6(legacyPath, "utf-8");
2846
+ return parseLegacySubagentMarkdown(content, capabilityId, legacyPath);
2847
+ }
2848
+ function findFirstExisting(dirPath, fileNames) {
2849
+ for (const fileName of fileNames) {
2850
+ const filePath = join7(dirPath, fileName);
2851
+ if (existsSync9(filePath)) {
2852
+ return filePath;
2853
+ }
2854
+ }
2855
+ return null;
2856
+ }
2857
+ function parseClaudeConfig(value, sourceLabel) {
2858
+ if (!value || typeof value !== "object") {
2859
+ return;
2860
+ }
2861
+ const claude = {};
2862
+ if (value.tools !== undefined) {
2863
+ claude.tools = readStringArray(value.tools, `${sourceLabel} [claude].tools`);
2864
+ }
2865
+ if (value.disallowed_tools !== undefined) {
2866
+ claude.disallowedTools = readStringArray(value.disallowed_tools, `${sourceLabel} [claude].disallowed_tools`);
2867
+ }
2868
+ if (value.model !== undefined) {
2869
+ claude.model = readEnum(value.model, ["sonnet", "opus", "haiku", "inherit"], `${sourceLabel} [claude].model`);
2870
+ }
2871
+ if (value.permission_mode !== undefined) {
2872
+ claude.permissionMode = readEnum(value.permission_mode, ["default", "acceptEdits", "dontAsk", "bypassPermissions", "plan"], `${sourceLabel} [claude].permission_mode`);
2873
+ }
2874
+ if (value.skills !== undefined) {
2875
+ claude.skills = readStringArray(value.skills, `${sourceLabel} [claude].skills`);
2876
+ }
2877
+ if (value.hooks !== undefined) {
2878
+ if (typeof value.hooks !== "object" || value.hooks === null) {
2879
+ throw new Error(`Invalid ${sourceLabel} [claude].hooks: expected a table`);
2880
+ }
2881
+ claude.hooks = value.hooks;
2882
+ }
2883
+ return hasClaudeConfig(claude) ? claude : undefined;
2884
+ }
2885
+ function parseCodexConfig(value, sourceLabel) {
2886
+ if (!value || typeof value !== "object") {
2887
+ return;
2888
+ }
2889
+ const codex = {};
2890
+ if (value.model !== undefined) {
2891
+ codex.model = readString(value.model, `${sourceLabel} [codex].model`);
2892
+ }
2893
+ if (value.model_reasoning_effort !== undefined) {
2894
+ codex.modelReasoningEffort = readEnum(value.model_reasoning_effort, ["low", "medium", "high", "xhigh"], `${sourceLabel} [codex].model_reasoning_effort`);
2895
+ }
2896
+ if (value.sandbox_mode !== undefined) {
2897
+ codex.sandboxMode = readEnum(value.sandbox_mode, ["read-only", "workspace-write", "danger-full-access"], `${sourceLabel} [codex].sandbox_mode`);
2898
+ }
2899
+ if (value.nickname_candidates !== undefined) {
2900
+ codex.nicknameCandidates = readStringArray(value.nickname_candidates, `${sourceLabel} [codex].nickname_candidates`);
2901
+ }
2902
+ return Object.keys(codex).length > 0 ? codex : undefined;
2903
+ }
2904
+ function withClaudeCompatibilityAliases(subagent) {
2905
+ if (subagent.claude) {
2906
+ if (subagent.claude.tools) {
2907
+ subagent.tools = subagent.claude.tools;
2908
+ }
2909
+ if (subagent.claude.disallowedTools) {
2910
+ subagent.disallowedTools = subagent.claude.disallowedTools;
2911
+ }
2912
+ if (subagent.claude.model) {
2913
+ subagent.model = subagent.claude.model;
2914
+ }
2915
+ if (subagent.claude.permissionMode) {
2916
+ subagent.permissionMode = subagent.claude.permissionMode;
2917
+ }
2918
+ if (subagent.claude.skills) {
2919
+ subagent.skills = subagent.claude.skills;
2920
+ }
2921
+ if (subagent.claude.hooks) {
2922
+ subagent.hooks = subagent.claude.hooks;
2923
+ }
2924
+ }
2925
+ return subagent;
2926
+ }
2927
+ function hasClaudeConfig(config) {
2928
+ return Object.keys(config).length > 0;
2929
+ }
2930
+ function readString(value, fieldName) {
2931
+ if (typeof value !== "string" || value.trim().length === 0) {
2932
+ throw new Error(`Invalid ${fieldName}: expected a non-empty string`);
2933
+ }
2934
+ return value.trim();
2935
+ }
2936
+ function readStringArray(value, fieldName) {
2937
+ if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
2938
+ throw new Error(`Invalid ${fieldName}: expected an array of strings`);
2939
+ }
2940
+ return value.map((item) => item.trim()).filter(Boolean);
2941
+ }
2942
+ function readEnum(value, allowed, fieldName) {
2943
+ if (typeof value !== "string" || !allowed.includes(value)) {
2944
+ throw new Error(`Invalid ${fieldName}: expected one of ${allowed.join(", ")}`);
2945
+ }
2946
+ return value;
2735
2947
  }
2736
2948
  function parseCommaSeparatedList(value) {
2737
2949
  return value.split(",").map((item) => item.trim()).filter(Boolean);
2738
2950
  }
2739
- var init_subagents = () => {};
2951
+ var POSSIBLE_DIR_NAMES, LEGACY_AGENT_FILES, MANIFEST_FILE_NAMES, PROMPT_FILE_NAMES;
2952
+ var init_subagents = __esm(() => {
2953
+ init_dist();
2954
+ POSSIBLE_DIR_NAMES = ["subagents", "agents", "agent", "subagent"];
2955
+ LEGACY_AGENT_FILES = ["SUBAGENT.md", "subagent.md", "AGENT.md", "agent.md", "Agent.md"];
2956
+ MANIFEST_FILE_NAMES = ["agent.toml", "AGENT.toml"];
2957
+ PROMPT_FILE_NAMES = ["prompt.md", "PROMPT.md"];
2958
+ });
2740
2959
 
2741
2960
  // ../core/src/capability/loader.ts
2742
2961
  import { existsSync as existsSync10, readdirSync as readdirSync6 } from "node:fs";
@@ -2835,75 +3054,19 @@ function convertDocExports(docExports, capabilityId) {
2835
3054
  });
2836
3055
  }
2837
3056
  function convertSubagentExports(subagentExports, capabilityId) {
2838
- return subagentExports.map((subagentExport) => {
3057
+ return subagentExports.map((subagentExport, index) => {
2839
3058
  const exportObj = subagentExport;
2840
- const lines = exportObj.subagentMd.split(`
2841
- `);
2842
- let name = "unnamed";
2843
- let description = "";
2844
- let systemPrompt = exportObj.subagentMd;
2845
- let tools;
2846
- let disallowedTools;
2847
- let model;
2848
- let permissionMode;
2849
- let skills;
2850
- if (lines[0]?.trim() === "---") {
2851
- const endIndex = lines.findIndex((line, i) => i > 0 && line.trim() === "---");
2852
- if (endIndex > 0) {
2853
- const frontmatter = lines.slice(1, endIndex);
2854
- systemPrompt = lines.slice(endIndex + 1).join(`
2855
- `).trim();
2856
- for (const line of frontmatter) {
2857
- const match = line.match(/^(\w+):\s*(.+)$/);
2858
- if (match?.[1] && match[2]) {
2859
- const key = match[1];
2860
- const value = match[2].replace(/^["']|["']$/g, "");
2861
- switch (key) {
2862
- case "name":
2863
- name = value;
2864
- break;
2865
- case "description":
2866
- description = value;
2867
- break;
2868
- case "tools":
2869
- tools = value.split(",").map((t) => t.trim());
2870
- break;
2871
- case "disallowedTools":
2872
- disallowedTools = value.split(",").map((t) => t.trim());
2873
- break;
2874
- case "model":
2875
- model = value;
2876
- break;
2877
- case "permissionMode":
2878
- permissionMode = value;
2879
- break;
2880
- case "skills":
2881
- skills = value.split(",").map((s) => s.trim());
2882
- break;
2883
- }
2884
- }
2885
- }
3059
+ const sourceLabel = `programmatic subagent export[${index}]`;
3060
+ if (typeof exportObj.agentToml === "string" || typeof exportObj.promptMd === "string") {
3061
+ if (typeof exportObj.agentToml !== "string" || typeof exportObj.promptMd !== "string") {
3062
+ throw new Error(`Invalid ${sourceLabel}: agentToml and promptMd must both be provided`);
2886
3063
  }
3064
+ return parseSubagentManifest(exportObj.agentToml, exportObj.promptMd, capabilityId, sourceLabel);
2887
3065
  }
2888
- const result = {
2889
- name,
2890
- description,
2891
- systemPrompt,
2892
- capabilityId
2893
- };
2894
- if (tools)
2895
- result.tools = tools;
2896
- if (disallowedTools)
2897
- result.disallowedTools = disallowedTools;
2898
- if (model) {
2899
- result.model = model;
2900
- }
2901
- if (permissionMode) {
2902
- result.permissionMode = permissionMode;
2903
- }
2904
- if (skills)
2905
- result.skills = skills;
2906
- return result;
3066
+ if (typeof exportObj.subagentMd === "string") {
3067
+ return parseLegacySubagentMarkdown(exportObj.subagentMd, capabilityId, sourceLabel, `subagent-${index + 1}`);
3068
+ }
3069
+ throw new Error(`Invalid ${sourceLabel}: expected agentToml + promptMd or subagentMd`);
2907
3070
  });
2908
3071
  }
2909
3072
  function convertCommandExports(commandExports, capabilityId) {
@@ -4761,7 +4924,15 @@ var init_sources = __esm(() => {
4761
4924
  /^copying(?:\..+)?$/i
4762
4925
  ];
4763
4926
  SKILL_FILES = ["SKILL.md", "skill.md", "Skill.md"];
4764
- AGENT_FILES = ["AGENT.md", "agent.md", "Agent.md", "SUBAGENT.md", "subagent.md"];
4927
+ AGENT_FILES = [
4928
+ "AGENT.md",
4929
+ "agent.md",
4930
+ "Agent.md",
4931
+ "SUBAGENT.md",
4932
+ "subagent.md",
4933
+ "agent.toml",
4934
+ "AGENT.toml"
4935
+ ];
4765
4936
  COMMAND_FILES = ["COMMAND.md", "command.md", "Command.md"];
4766
4937
  CONTENT_HASH_EXCLUDES = [
4767
4938
  ".git",
@@ -4789,6 +4960,211 @@ var init_capability = __esm(() => {
4789
4960
  init_subagents();
4790
4961
  });
4791
4962
 
4963
+ // ../core/src/hooks/provider-config.ts
4964
+ function getProviderDisplayName(providerId) {
4965
+ switch (providerId) {
4966
+ case "claude-code":
4967
+ return "Claude Code";
4968
+ case "codex":
4969
+ return "Codex";
4970
+ case "cursor":
4971
+ return "Cursor";
4972
+ case "opencode":
4973
+ return "OpenCode";
4974
+ }
4975
+ }
4976
+ function hasOwnKey(value, key) {
4977
+ return Object.hasOwn(value, key);
4978
+ }
4979
+ function hasHooksInConfig(config) {
4980
+ if (!config) {
4981
+ return false;
4982
+ }
4983
+ for (const event of HOOK_EVENTS) {
4984
+ const matchers = config[event];
4985
+ if (Array.isArray(matchers) && matchers.length > 0) {
4986
+ return true;
4987
+ }
4988
+ }
4989
+ return false;
4990
+ }
4991
+ function matcherMatchesAny(matcher, values) {
4992
+ if (matcher === undefined || matcher === "" || matcher === "*") {
4993
+ return true;
4994
+ }
4995
+ try {
4996
+ const regex = new RegExp(matcher);
4997
+ return values.some((value) => regex.test(value));
4998
+ } catch {
4999
+ return false;
5000
+ }
5001
+ }
5002
+ function cloneMatcher(matcher) {
5003
+ return {
5004
+ ...matcher.matcher !== undefined ? { matcher: matcher.matcher } : {},
5005
+ hooks: matcher.hooks.map((hook) => ({ ...hook }))
5006
+ };
5007
+ }
5008
+ function filterSharedHooksForCodex(config, capabilityName) {
5009
+ const warnings = [];
5010
+ if (process.platform === "win32") {
5011
+ if (hasHooksInConfig(config)) {
5012
+ warnings.push(`[hooks] Warning: Capability "${capabilityName}" has shared hooks, but Codex hooks are currently disabled on Windows. Skipping Codex hook output.`);
5013
+ }
5014
+ return { config: {}, warnings };
5015
+ }
5016
+ const filtered = {};
5017
+ for (const event of HOOK_EVENTS) {
5018
+ const matchers = config[event];
5019
+ if (!matchers || matchers.length === 0) {
5020
+ continue;
5021
+ }
5022
+ if (!CODEX_SUPPORTED_EVENTS.has(event)) {
5023
+ warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared event "${event}" is not supported by Codex and was skipped.`);
5024
+ continue;
5025
+ }
5026
+ const filteredMatchers = [];
5027
+ for (const matcher of matchers) {
5028
+ const nextMatcher = cloneMatcher(matcher);
5029
+ const originalHookCount = nextMatcher.hooks.length;
5030
+ nextMatcher.hooks = nextMatcher.hooks.filter((hook, hookIndex) => {
5031
+ if (hook.type === "command") {
5032
+ return true;
5033
+ }
5034
+ warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared ${event} hook ${hookIndex + 1} uses prompt hooks, which Codex does not support. It was skipped.`);
5035
+ return false;
5036
+ });
5037
+ if (nextMatcher.hooks.length === 0) {
5038
+ continue;
5039
+ }
5040
+ if (event === "UserPromptSubmit" || event === "Stop") {
5041
+ if (nextMatcher.matcher !== undefined && nextMatcher.matcher !== "" && nextMatcher.matcher !== "*") {
5042
+ warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared ${event} matcher "${nextMatcher.matcher}" is ignored by Codex. The matcher was dropped.`);
5043
+ delete nextMatcher.matcher;
5044
+ }
5045
+ filteredMatchers.push(nextMatcher);
5046
+ continue;
5047
+ }
5048
+ if (event === "PreToolUse" || event === "PostToolUse") {
5049
+ if (!matcherMatchesAny(nextMatcher.matcher, ["Bash"])) {
5050
+ warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared ${event} matcher "${nextMatcher.matcher ?? ""}" does not match Codex's current tool runtime ("Bash") and was skipped.`);
5051
+ continue;
5052
+ }
5053
+ filteredMatchers.push(nextMatcher);
5054
+ continue;
5055
+ }
5056
+ if (event === "SessionStart") {
5057
+ if (!matcherMatchesAny(nextMatcher.matcher, ["startup", "resume"])) {
5058
+ warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared SessionStart matcher "${nextMatcher.matcher ?? ""}" does not match Codex's current sources ("startup" or "resume") and was skipped.`);
5059
+ continue;
5060
+ }
5061
+ }
5062
+ if (nextMatcher.hooks.length !== originalHookCount || nextMatcher.matcher !== matcher.matcher) {
5063
+ filteredMatchers.push(nextMatcher);
5064
+ } else {
5065
+ filteredMatchers.push(matcher);
5066
+ }
5067
+ }
5068
+ if (filteredMatchers.length > 0) {
5069
+ filtered[event] = filteredMatchers;
5070
+ }
5071
+ }
5072
+ return { config: filtered, warnings };
5073
+ }
5074
+ function getProviderOverrideWarnings(providerId, capabilityName, providerConfigs) {
5075
+ if (!providerConfigs) {
5076
+ return [];
5077
+ }
5078
+ if (providerId === "claude-code" && providerConfigs.codex) {
5079
+ return [
5080
+ `[hooks] Warning: Capability "${capabilityName}" defines [codex] hooks; they are not used by Claude Code.`
5081
+ ];
5082
+ }
5083
+ if (providerId === "codex" && providerConfigs.claude) {
5084
+ return [
5085
+ `[hooks] Warning: Capability "${capabilityName}" defines [claude] hooks; they are not used by Codex.`
5086
+ ];
5087
+ }
5088
+ return [];
5089
+ }
5090
+ function applyProviderOverrides(baseConfig, providerId, capabilityName, providerConfigs) {
5091
+ const warnings = getProviderOverrideWarnings(providerId, capabilityName, providerConfigs);
5092
+ const providerSection = PROVIDER_SECTION_BY_ID[providerId];
5093
+ if (!providerSection) {
5094
+ return { config: baseConfig, warnings };
5095
+ }
5096
+ const overrideConfig = providerConfigs?.[providerSection];
5097
+ if (!overrideConfig) {
5098
+ return { config: baseConfig, warnings };
5099
+ }
5100
+ const result = { ...baseConfig };
5101
+ for (const event of HOOK_EVENTS) {
5102
+ if (!hasOwnKey(overrideConfig, event)) {
5103
+ continue;
5104
+ }
5105
+ const eventValue = overrideConfig[event];
5106
+ if (!Array.isArray(eventValue)) {
5107
+ warnings.push(`[hooks] Warning: Capability "${capabilityName}" [${providerSection}].${event} must be an array to be emitted for ${getProviderDisplayName(providerId)}. The override was skipped.`);
5108
+ continue;
5109
+ }
5110
+ result[event] = eventValue;
5111
+ }
5112
+ return { config: result, warnings };
5113
+ }
5114
+ function mergeCapabilityHookConfig(target, capabilityConfig) {
5115
+ for (const event of HOOK_EVENTS) {
5116
+ const eventValue = capabilityConfig[event];
5117
+ if (!Array.isArray(eventValue) || eventValue.length === 0) {
5118
+ continue;
5119
+ }
5120
+ const existing = target[event];
5121
+ target[event] = Array.isArray(existing) ? [...existing, ...eventValue] : [...eventValue];
5122
+ }
5123
+ }
5124
+ function composeHooksForProvider(capabilityHooks, providerId) {
5125
+ if (providerId !== "claude-code" && providerId !== "codex") {
5126
+ return { config: {}, warnings: [] };
5127
+ }
5128
+ const warnings = [];
5129
+ const mergedConfig = {};
5130
+ for (const capHooks of capabilityHooks) {
5131
+ if (providerId === "codex" && process.platform === "win32") {
5132
+ if (hasHooksInConfig(capHooks.config) || hasHooksInConfig(capHooks.providerConfigs?.codex)) {
5133
+ warnings.push(`[hooks] Warning: Capability "${capHooks.capabilityName}" has Codex hooks configured, but Codex hooks are currently disabled on Windows. Skipping Codex hook output.`);
5134
+ }
5135
+ continue;
5136
+ }
5137
+ let capabilityConfig = capHooks.config;
5138
+ if (providerId === "codex") {
5139
+ const filtered = filterSharedHooksForCodex(capabilityConfig, capHooks.capabilityName);
5140
+ capabilityConfig = filtered.config;
5141
+ warnings.push(...filtered.warnings);
5142
+ }
5143
+ const withOverrides = applyProviderOverrides(capabilityConfig, providerId, capHooks.capabilityName, capHooks.providerConfigs);
5144
+ warnings.push(...withOverrides.warnings);
5145
+ mergeCapabilityHookConfig(mergedConfig, withOverrides.config);
5146
+ }
5147
+ return {
5148
+ config: mergedConfig,
5149
+ warnings
5150
+ };
5151
+ }
5152
+ var CODEX_SUPPORTED_EVENTS, PROVIDER_SECTION_BY_ID;
5153
+ var init_provider_config = __esm(() => {
5154
+ init_constants();
5155
+ CODEX_SUPPORTED_EVENTS = new Set([
5156
+ "SessionStart",
5157
+ "PreToolUse",
5158
+ "PostToolUse",
5159
+ "UserPromptSubmit",
5160
+ "Stop"
5161
+ ]);
5162
+ PROVIDER_SECTION_BY_ID = {
5163
+ "claude-code": "claude",
5164
+ codex: "codex"
5165
+ };
5166
+ });
5167
+
4792
5168
  // ../core/src/hooks/index.ts
4793
5169
  var init_hooks = __esm(() => {
4794
5170
  init_constants();
@@ -4797,6 +5173,7 @@ var init_hooks = __esm(() => {
4797
5173
  init_variables();
4798
5174
  init_loader();
4799
5175
  init_merger();
5176
+ init_provider_config();
4800
5177
  init_json_loader();
4801
5178
  });
4802
5179
 
@@ -6569,6 +6946,7 @@ __export(exports_src, {
6569
6946
  saveManifest: () => saveManifest,
6570
6947
  saveLockFile: () => saveLockFile,
6571
6948
  resolveEnabledCapabilities: () => resolveEnabledCapabilities,
6949
+ resolveCapabilityRootInValue: () => resolveCapabilityRootInValue,
6572
6950
  resolveCapabilityRootInConfig: () => resolveCapabilityRootInConfig,
6573
6951
  resolveCapabilityRoot: () => resolveCapabilityRoot,
6574
6952
  resolveCapabilityInstallCommand: () => resolveCapabilityInstallCommand,
@@ -6619,6 +6997,7 @@ __export(exports_src, {
6619
6997
  isFileSourceConfig: () => isFileSourceConfig,
6620
6998
  isFileSource: () => isFileSource,
6621
6999
  installCapabilityDependencies: () => installCapabilityDependencies,
7000
+ hasHooksInConfig: () => hasHooksInConfig,
6622
7001
  hasHooks: () => hasHooks,
6623
7002
  hasAnyHooks: () => hasAnyHooks,
6624
7003
  getVersion: () => getVersion,
@@ -6657,6 +7036,7 @@ __export(exports_src, {
6657
7036
  countHooks: () => countHooks,
6658
7037
  containsOmnidevVariables: () => containsOmnidevVariables,
6659
7038
  containsClaudeVariables: () => containsClaudeVariables,
7039
+ composeHooksForProvider: () => composeHooksForProvider,
6660
7040
  clearCapabilityAllows: () => clearCapabilityAllows,
6661
7041
  clearAllSecurityAllows: () => clearAllSecurityAllows,
6662
7042
  clearActiveProfileState: () => clearActiveProfileState,
@@ -6707,7 +7087,7 @@ import { run } from "@stricli/core";
6707
7087
  // src/lib/dynamic-app.ts
6708
7088
  import { existsSync as existsSync32 } from "node:fs";
6709
7089
  import { createRequire as createRequire2 } from "node:module";
6710
- import { join as join29 } from "node:path";
7090
+ import { join as join31 } from "node:path";
6711
7091
  import { buildApplication, buildRouteMap as buildRouteMap7 } from "@stricli/core";
6712
7092
 
6713
7093
  // src/commands/add.ts
@@ -6774,10 +7154,10 @@ var HooksWriter = {
6774
7154
  if (!bundle.hooks) {
6775
7155
  return { filesWritten: [] };
6776
7156
  }
7157
+ const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
6777
7158
  const settingsPath = join13(ctx.projectRoot, ctx.outputPath);
6778
7159
  const parentDir = dirname2(settingsPath);
6779
7160
  await mkdir2(parentDir, { recursive: true });
6780
- const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
6781
7161
  let existingSettings = {};
6782
7162
  if (existsSync22(settingsPath)) {
6783
7163
  try {
@@ -7011,9 +7391,12 @@ function createProviderScopedBundle(bundle, providerId) {
7011
7391
  subagents,
7012
7392
  instructionsContent: generateInstructionsContent2(rules, docs)
7013
7393
  };
7014
- const mergedHooks = mergeHooksConfigs(capabilities2.flatMap((capability3) => capability3.hooks ? [capability3.hooks] : []));
7015
- if (hasAnyHooks(mergedHooks)) {
7016
- scopedBundle.hooks = mergedHooks;
7394
+ const composedHooks = composeHooksForProvider(capabilities2.flatMap((capability3) => capability3.hooks ? [capability3.hooks] : []), providerId);
7395
+ for (const warning of composedHooks.warnings) {
7396
+ console.warn(warning);
7397
+ }
7398
+ if (hasHooksInConfig(composedHooks.config)) {
7399
+ scopedBundle.hooks = composedHooks.config;
7017
7400
  }
7018
7401
  return scopedBundle;
7019
7402
  }
@@ -7021,24 +7404,34 @@ function createProviderScopedBundle(bundle, providerId) {
7021
7404
  // ../adapters/src/writers/claude/agents.ts
7022
7405
  import { mkdir as mkdir6, writeFile as writeFile14 } from "node:fs/promises";
7023
7406
  import { join as join17 } from "node:path";
7407
+ function getClaudeConfig(agent) {
7408
+ return {
7409
+ tools: agent.claude?.tools ?? agent.tools,
7410
+ disallowedTools: agent.claude?.disallowedTools ?? agent.disallowedTools,
7411
+ model: agent.claude?.model ?? agent.model,
7412
+ permissionMode: agent.claude?.permissionMode ?? agent.permissionMode,
7413
+ skills: agent.claude?.skills ?? agent.skills
7414
+ };
7415
+ }
7024
7416
  function generateFrontmatter(agent) {
7417
+ const claude2 = getClaudeConfig(agent);
7025
7418
  const lines = ["---"];
7026
7419
  lines.push(`name: ${agent.name}`);
7027
7420
  lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
7028
- if (agent.tools && agent.tools.length > 0) {
7029
- lines.push(`tools: ${agent.tools.join(", ")}`);
7421
+ if (claude2.tools && claude2.tools.length > 0) {
7422
+ lines.push(`tools: ${claude2.tools.join(", ")}`);
7030
7423
  }
7031
- if (agent.disallowedTools && agent.disallowedTools.length > 0) {
7032
- lines.push(`disallowedTools: ${agent.disallowedTools.join(", ")}`);
7424
+ if (claude2.disallowedTools && claude2.disallowedTools.length > 0) {
7425
+ lines.push(`disallowedTools: ${claude2.disallowedTools.join(", ")}`);
7033
7426
  }
7034
- if (agent.model && agent.model !== "inherit") {
7035
- lines.push(`model: ${agent.model}`);
7427
+ if (claude2.model && claude2.model !== "inherit") {
7428
+ lines.push(`model: ${claude2.model}`);
7036
7429
  }
7037
- if (agent.permissionMode && agent.permissionMode !== "default") {
7038
- lines.push(`permissionMode: ${agent.permissionMode}`);
7430
+ if (claude2.permissionMode && claude2.permissionMode !== "default") {
7431
+ lines.push(`permissionMode: ${claude2.permissionMode}`);
7039
7432
  }
7040
- if (agent.skills && agent.skills.length > 0) {
7041
- lines.push(`skills: ${agent.skills.join(", ")}`);
7433
+ if (claude2.skills && claude2.skills.length > 0) {
7434
+ lines.push(`skills: ${claude2.skills.join(", ")}`);
7042
7435
  }
7043
7436
  lines.push("---");
7044
7437
  return lines.join(`
@@ -7098,12 +7491,82 @@ var claudeCodeAdapter = {
7098
7491
  };
7099
7492
  // ../adapters/src/codex/index.ts
7100
7493
  import { mkdirSync as mkdirSync6 } from "node:fs";
7101
- import { join as join19 } from "node:path";
7494
+ import { join as join21 } from "node:path";
7102
7495
 
7103
- // ../adapters/src/writers/codex/toml.ts
7496
+ // ../adapters/src/writers/codex/agents.ts
7104
7497
  init_dist();
7105
7498
  import { mkdir as mkdir7, writeFile as writeFile15 } from "node:fs/promises";
7106
- import { dirname as dirname4, join as join18 } from "node:path";
7499
+ import { join as join18 } from "node:path";
7500
+ function buildCodexAgentFile(agent) {
7501
+ const codex = agent.codex ?? {};
7502
+ const file = {
7503
+ name: agent.name,
7504
+ description: agent.description,
7505
+ developer_instructions: agent.systemPrompt
7506
+ };
7507
+ if (codex.model) {
7508
+ file.model = codex.model;
7509
+ }
7510
+ if (codex.modelReasoningEffort) {
7511
+ file.model_reasoning_effort = codex.modelReasoningEffort;
7512
+ }
7513
+ if (codex.sandboxMode) {
7514
+ file.sandbox_mode = codex.sandboxMode;
7515
+ }
7516
+ if (codex.nicknameCandidates && codex.nicknameCandidates.length > 0) {
7517
+ file.nickname_candidates = codex.nicknameCandidates;
7518
+ }
7519
+ return file;
7520
+ }
7521
+ var CodexAgentsWriter = {
7522
+ id: "codex-agents",
7523
+ async write(bundle, ctx) {
7524
+ if (bundle.subagents.length === 0) {
7525
+ return { filesWritten: [] };
7526
+ }
7527
+ const agentsDir = join18(ctx.projectRoot, ctx.outputPath);
7528
+ await mkdir7(agentsDir, { recursive: true });
7529
+ const filesWritten = [];
7530
+ const managedOutputs = [];
7531
+ for (const agent of bundle.subagents) {
7532
+ const content = stringify(buildCodexAgentFile(agent));
7533
+ const relativePath = join18(ctx.outputPath, `${agent.name}.toml`);
7534
+ const filePath = join18(ctx.projectRoot, relativePath);
7535
+ await writeFile15(filePath, content, "utf-8");
7536
+ filesWritten.push(relativePath);
7537
+ managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7538
+ }
7539
+ return {
7540
+ filesWritten,
7541
+ managedOutputs
7542
+ };
7543
+ }
7544
+ };
7545
+ // ../adapters/src/writers/codex/hooks.ts
7546
+ import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
7547
+ import { dirname as dirname4, join as join19 } from "node:path";
7548
+ var CodexHooksWriter = {
7549
+ id: "codex-hooks",
7550
+ async write(bundle, ctx) {
7551
+ if (!bundle.hooks) {
7552
+ return { filesWritten: [] };
7553
+ }
7554
+ const hooksPath = join19(ctx.projectRoot, ctx.outputPath);
7555
+ await mkdir8(dirname4(hooksPath), { recursive: true });
7556
+ const content = `${JSON.stringify({ hooks: bundle.hooks }, null, 2)}
7557
+ `;
7558
+ await writeFile16(hooksPath, content, "utf-8");
7559
+ return {
7560
+ filesWritten: [ctx.outputPath],
7561
+ managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
7562
+ };
7563
+ }
7564
+ };
7565
+ // ../adapters/src/writers/codex/toml.ts
7566
+ init_src();
7567
+ init_dist();
7568
+ import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
7569
+ import { dirname as dirname5, join as join20 } from "node:path";
7107
7570
  var FILE_HEADER = `# Generated by OmniDev - DO NOT EDIT
7108
7571
  # Run \`omnidev sync\` to regenerate
7109
7572
 
@@ -7151,12 +7614,13 @@ var CodexTomlWriter = {
7151
7614
  id: "codex-toml",
7152
7615
  async write(bundle, ctx) {
7153
7616
  const mcps = collectMcps(bundle);
7154
- if (mcps.size === 0) {
7617
+ const hasHooks2 = hasHooksInConfig(bundle.hooks);
7618
+ if (mcps.size === 0 && !hasHooks2) {
7155
7619
  return { filesWritten: [] };
7156
7620
  }
7157
- const configPath = join18(ctx.projectRoot, ctx.outputPath);
7158
- const parentDir = dirname4(configPath);
7159
- await mkdir7(parentDir, { recursive: true });
7621
+ const configPath = join20(ctx.projectRoot, ctx.outputPath);
7622
+ const parentDir = dirname5(configPath);
7623
+ await mkdir9(parentDir, { recursive: true });
7160
7624
  const mcpServers = {};
7161
7625
  for (const [id, mcp] of mcps) {
7162
7626
  const converted = buildCodexMcpConfig(id, mcp);
@@ -7164,14 +7628,18 @@ var CodexTomlWriter = {
7164
7628
  mcpServers[id] = converted;
7165
7629
  }
7166
7630
  }
7167
- if (Object.keys(mcpServers).length === 0) {
7631
+ if (Object.keys(mcpServers).length === 0 && !hasHooks2) {
7168
7632
  return { filesWritten: [] };
7169
7633
  }
7170
- const codexConfig = {
7171
- mcp_servers: mcpServers
7172
- };
7634
+ const codexConfig = {};
7635
+ if (hasHooks2) {
7636
+ codexConfig.features = { codex_hooks: true };
7637
+ }
7638
+ if (Object.keys(mcpServers).length > 0) {
7639
+ codexConfig.mcp_servers = mcpServers;
7640
+ }
7173
7641
  const tomlContent = FILE_HEADER + stringify(codexConfig);
7174
- await writeFile15(configPath, tomlContent, "utf-8");
7642
+ await writeFile17(configPath, tomlContent, "utf-8");
7175
7643
  return {
7176
7644
  filesWritten: [ctx.outputPath],
7177
7645
  managedOutputs: [createManagedOutput(ctx.outputPath, this.id, tomlContent)]
@@ -7186,10 +7654,12 @@ var codexAdapter = {
7186
7654
  { writer: InstructionsMdWriter, outputPath: "AGENTS.md" },
7187
7655
  { writer: SkillsWriter, outputPath: ".codex/skills/" },
7188
7656
  { writer: CommandsAsSkillsWriter, outputPath: ".codex/skills/" },
7657
+ { writer: CodexAgentsWriter, outputPath: ".codex/agents/" },
7658
+ { writer: CodexHooksWriter, outputPath: ".codex/hooks.json" },
7189
7659
  { writer: CodexTomlWriter, outputPath: ".codex/config.toml" }
7190
7660
  ],
7191
7661
  async init(ctx) {
7192
- const codexDir = join19(ctx.projectRoot, ".codex");
7662
+ const codexDir = join21(ctx.projectRoot, ".codex");
7193
7663
  mkdirSync6(codexDir, { recursive: true });
7194
7664
  return {
7195
7665
  filesCreated: [".codex/"],
@@ -7209,11 +7679,17 @@ var codexAdapter = {
7209
7679
  };
7210
7680
  // ../adapters/src/cursor/index.ts
7211
7681
  import { mkdirSync as mkdirSync7 } from "node:fs";
7212
- import { join as join24 } from "node:path";
7682
+ import { join as join26 } from "node:path";
7213
7683
 
7214
7684
  // ../adapters/src/writers/cursor/agents.ts
7215
- import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
7216
- import { join as join20 } from "node:path";
7685
+ import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
7686
+ import { join as join22 } from "node:path";
7687
+ function getClaudeConfig2(agent) {
7688
+ return {
7689
+ model: agent.claude?.model ?? agent.model,
7690
+ permissionMode: agent.claude?.permissionMode ?? agent.permissionMode
7691
+ };
7692
+ }
7217
7693
  function mapModelToCursor(model) {
7218
7694
  if (!model || model === "inherit")
7219
7695
  return "inherit";
@@ -7225,14 +7701,15 @@ function mapModelToCursor(model) {
7225
7701
  return modelMap[model] ?? "inherit";
7226
7702
  }
7227
7703
  function generateFrontmatter2(agent) {
7704
+ const claude2 = getClaudeConfig2(agent);
7228
7705
  const lines = ["---"];
7229
7706
  lines.push(`name: ${agent.name}`);
7230
7707
  lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
7231
- const model = mapModelToCursor(agent.model);
7708
+ const model = mapModelToCursor(claude2.model);
7232
7709
  if (model) {
7233
7710
  lines.push(`model: ${model}`);
7234
7711
  }
7235
- if (agent.permissionMode === "plan") {
7712
+ if (claude2.permissionMode === "plan") {
7236
7713
  lines.push("readonly: true");
7237
7714
  }
7238
7715
  if (agent.isBackground) {
@@ -7245,8 +7722,8 @@ function generateFrontmatter2(agent) {
7245
7722
  var CursorAgentsWriter = {
7246
7723
  id: "cursor-agents",
7247
7724
  async write(bundle, ctx) {
7248
- const agentsDir = join20(ctx.projectRoot, ctx.outputPath);
7249
- await mkdir8(agentsDir, { recursive: true });
7725
+ const agentsDir = join22(ctx.projectRoot, ctx.outputPath);
7726
+ await mkdir10(agentsDir, { recursive: true });
7250
7727
  const filesWritten = [];
7251
7728
  const managedOutputs = [];
7252
7729
  for (const agent of bundle.subagents) {
@@ -7254,9 +7731,9 @@ var CursorAgentsWriter = {
7254
7731
  const content = `${frontmatter}
7255
7732
 
7256
7733
  ${agent.systemPrompt}`;
7257
- const agentPath = join20(agentsDir, `${agent.name}.md`);
7258
- await writeFile16(agentPath, content, "utf-8");
7259
- const relativePath = join20(ctx.outputPath, `${agent.name}.md`);
7734
+ const agentPath = join22(agentsDir, `${agent.name}.md`);
7735
+ await writeFile18(agentPath, content, "utf-8");
7736
+ const relativePath = join22(ctx.outputPath, `${agent.name}.md`);
7260
7737
  filesWritten.push(relativePath);
7261
7738
  managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7262
7739
  }
@@ -7267,13 +7744,13 @@ ${agent.systemPrompt}`;
7267
7744
  }
7268
7745
  };
7269
7746
  // ../adapters/src/writers/cursor/commands.ts
7270
- import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
7271
- import { join as join21 } from "node:path";
7747
+ import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
7748
+ import { join as join23 } from "node:path";
7272
7749
  var CursorCommandsWriter = {
7273
7750
  id: "cursor-commands",
7274
7751
  async write(bundle, ctx) {
7275
- const commandsDir = join21(ctx.projectRoot, ctx.outputPath);
7276
- await mkdir9(commandsDir, { recursive: true });
7752
+ const commandsDir = join23(ctx.projectRoot, ctx.outputPath);
7753
+ await mkdir11(commandsDir, { recursive: true });
7277
7754
  const filesWritten = [];
7278
7755
  const managedOutputs = [];
7279
7756
  for (const command of bundle.commands) {
@@ -7282,9 +7759,9 @@ var CursorCommandsWriter = {
7282
7759
  ${command.description}
7283
7760
 
7284
7761
  ${command.prompt}`;
7285
- const commandPath = join21(commandsDir, `${command.name}.md`);
7286
- await writeFile17(commandPath, content, "utf-8");
7287
- const relativePath = join21(ctx.outputPath, `${command.name}.md`);
7762
+ const commandPath = join23(commandsDir, `${command.name}.md`);
7763
+ await writeFile19(commandPath, content, "utf-8");
7764
+ const relativePath = join23(ctx.outputPath, `${command.name}.md`);
7288
7765
  filesWritten.push(relativePath);
7289
7766
  managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7290
7767
  }
@@ -7295,8 +7772,8 @@ ${command.prompt}`;
7295
7772
  }
7296
7773
  };
7297
7774
  // ../adapters/src/writers/cursor/mcp-json.ts
7298
- import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
7299
- import { dirname as dirname5, join as join22 } from "node:path";
7775
+ import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
7776
+ import { dirname as dirname6, join as join24 } from "node:path";
7300
7777
  function buildCursorMcpConfig(mcp) {
7301
7778
  const transport = mcp.transport ?? "stdio";
7302
7779
  if (transport === "http" || transport === "sse") {
@@ -7341,9 +7818,9 @@ var CursorMcpJsonWriter = {
7341
7818
  if (mcps.size === 0) {
7342
7819
  return { filesWritten: [] };
7343
7820
  }
7344
- const configPath = join22(ctx.projectRoot, ctx.outputPath);
7345
- const parentDir = dirname5(configPath);
7346
- await mkdir10(parentDir, { recursive: true });
7821
+ const configPath = join24(ctx.projectRoot, ctx.outputPath);
7822
+ const parentDir = dirname6(configPath);
7823
+ await mkdir12(parentDir, { recursive: true });
7347
7824
  const mcpServers = {};
7348
7825
  for (const [id, mcp] of mcps) {
7349
7826
  const converted = buildCursorMcpConfig(mcp);
@@ -7359,7 +7836,7 @@ var CursorMcpJsonWriter = {
7359
7836
  };
7360
7837
  const content = `${JSON.stringify(cursorMcpJson, null, 2)}
7361
7838
  `;
7362
- await writeFile18(configPath, content, "utf-8");
7839
+ await writeFile20(configPath, content, "utf-8");
7363
7840
  return {
7364
7841
  filesWritten: [ctx.outputPath],
7365
7842
  managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
@@ -7367,19 +7844,19 @@ var CursorMcpJsonWriter = {
7367
7844
  }
7368
7845
  };
7369
7846
  // ../adapters/src/writers/cursor/rules.ts
7370
- import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
7371
- import { join as join23 } from "node:path";
7847
+ import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
7848
+ import { join as join25 } from "node:path";
7372
7849
  var CursorRulesWriter = {
7373
7850
  id: "cursor-rules",
7374
7851
  async write(bundle, ctx) {
7375
- const rulesDir = join23(ctx.projectRoot, ctx.outputPath);
7376
- await mkdir11(rulesDir, { recursive: true });
7852
+ const rulesDir = join25(ctx.projectRoot, ctx.outputPath);
7853
+ await mkdir13(rulesDir, { recursive: true });
7377
7854
  const filesWritten = [];
7378
7855
  const managedOutputs = [];
7379
7856
  for (const rule of bundle.rules) {
7380
- const rulePath = join23(rulesDir, `omnidev-${rule.name}.mdc`);
7381
- await writeFile19(rulePath, rule.content, "utf-8");
7382
- const relativePath = join23(ctx.outputPath, `omnidev-${rule.name}.mdc`);
7857
+ const rulePath = join25(rulesDir, `omnidev-${rule.name}.mdc`);
7858
+ await writeFile21(rulePath, rule.content, "utf-8");
7859
+ const relativePath = join25(ctx.outputPath, `omnidev-${rule.name}.mdc`);
7383
7860
  filesWritten.push(relativePath);
7384
7861
  managedOutputs.push(createManagedOutput(relativePath, this.id, rule.content));
7385
7862
  }
@@ -7402,7 +7879,7 @@ var cursorAdapter = {
7402
7879
  { writer: CursorMcpJsonWriter, outputPath: ".cursor/mcp.json" }
7403
7880
  ],
7404
7881
  async init(ctx) {
7405
- const rulesDir = join24(ctx.projectRoot, ".cursor", "rules");
7882
+ const rulesDir = join26(ctx.projectRoot, ".cursor", "rules");
7406
7883
  mkdirSync7(rulesDir, { recursive: true });
7407
7884
  return {
7408
7885
  filesCreated: [".cursor/rules/"],
@@ -7429,11 +7906,18 @@ var cursorAdapter = {
7429
7906
  };
7430
7907
  // ../adapters/src/opencode/index.ts
7431
7908
  import { mkdirSync as mkdirSync8 } from "node:fs";
7432
- import { join as join27 } from "node:path";
7909
+ import { join as join29 } from "node:path";
7433
7910
 
7434
7911
  // ../adapters/src/writers/opencode/agents.ts
7435
- import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
7436
- import { join as join25 } from "node:path";
7912
+ import { mkdir as mkdir14, writeFile as writeFile22 } from "node:fs/promises";
7913
+ import { join as join27 } from "node:path";
7914
+ function getClaudeConfig3(agent) {
7915
+ return {
7916
+ tools: agent.claude?.tools ?? agent.tools,
7917
+ model: agent.claude?.model ?? agent.model,
7918
+ permissionMode: agent.claude?.permissionMode ?? agent.permissionMode
7919
+ };
7920
+ }
7437
7921
  function mapModelToOpenCode(model) {
7438
7922
  if (!model || model === "inherit")
7439
7923
  return;
@@ -7465,9 +7949,10 @@ function mapToolsToOpenCode(tools) {
7465
7949
  return toolsObject;
7466
7950
  }
7467
7951
  function generateFrontmatter3(agent) {
7952
+ const claude2 = getClaudeConfig3(agent);
7468
7953
  const lines = ["---"];
7469
7954
  lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
7470
- const modelId = agent.modelId ?? mapModelToOpenCode(agent.model);
7955
+ const modelId = agent.modelId ?? mapModelToOpenCode(claude2.model);
7471
7956
  if (modelId) {
7472
7957
  lines.push(`model: ${modelId}`);
7473
7958
  }
@@ -7483,14 +7968,14 @@ function generateFrontmatter3(agent) {
7483
7968
  if (agent.hidden !== undefined) {
7484
7969
  lines.push(`hidden: ${agent.hidden}`);
7485
7970
  }
7486
- const toolsObj = agent.toolPermissions ?? mapToolsToOpenCode(agent.tools);
7971
+ const toolsObj = agent.toolPermissions ?? mapToolsToOpenCode(claude2.tools);
7487
7972
  if (toolsObj) {
7488
7973
  lines.push("tools:");
7489
7974
  for (const [tool, enabled] of Object.entries(toolsObj)) {
7490
7975
  lines.push(` ${tool}: ${enabled}`);
7491
7976
  }
7492
7977
  }
7493
- const permissions = agent.permissions ?? mapPermissionsToOpenCode(agent.permissionMode);
7978
+ const permissions = agent.permissions ?? mapPermissionsToOpenCode(claude2.permissionMode);
7494
7979
  if (permissions) {
7495
7980
  lines.push("permissions:");
7496
7981
  for (const [key, value] of Object.entries(permissions)) {
@@ -7511,8 +7996,8 @@ function generateFrontmatter3(agent) {
7511
7996
  var OpenCodeAgentsWriter = {
7512
7997
  id: "opencode-agents",
7513
7998
  async write(bundle, ctx) {
7514
- const agentsDir = join25(ctx.projectRoot, ctx.outputPath);
7515
- await mkdir12(agentsDir, { recursive: true });
7999
+ const agentsDir = join27(ctx.projectRoot, ctx.outputPath);
8000
+ await mkdir14(agentsDir, { recursive: true });
7516
8001
  const filesWritten = [];
7517
8002
  const managedOutputs = [];
7518
8003
  for (const agent of bundle.subagents) {
@@ -7520,9 +8005,9 @@ var OpenCodeAgentsWriter = {
7520
8005
  const content = `${frontmatter}
7521
8006
 
7522
8007
  ${agent.systemPrompt}`;
7523
- const agentPath = join25(agentsDir, `${agent.name}.md`);
7524
- await writeFile20(agentPath, content, "utf-8");
7525
- const relativePath = join25(ctx.outputPath, `${agent.name}.md`);
8008
+ const agentPath = join27(agentsDir, `${agent.name}.md`);
8009
+ await writeFile22(agentPath, content, "utf-8");
8010
+ const relativePath = join27(ctx.outputPath, `${agent.name}.md`);
7526
8011
  filesWritten.push(relativePath);
7527
8012
  managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7528
8013
  }
@@ -7533,8 +8018,8 @@ ${agent.systemPrompt}`;
7533
8018
  }
7534
8019
  };
7535
8020
  // ../adapters/src/writers/opencode/commands.ts
7536
- import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
7537
- import { join as join26 } from "node:path";
8021
+ import { mkdir as mkdir15, writeFile as writeFile23 } from "node:fs/promises";
8022
+ import { join as join28 } from "node:path";
7538
8023
  function generateFrontmatter4(command) {
7539
8024
  const lines = ["---"];
7540
8025
  lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
@@ -7551,8 +8036,8 @@ function generateFrontmatter4(command) {
7551
8036
  var OpenCodeCommandsWriter = {
7552
8037
  id: "opencode-commands",
7553
8038
  async write(bundle, ctx) {
7554
- const commandsDir = join26(ctx.projectRoot, ctx.outputPath);
7555
- await mkdir13(commandsDir, { recursive: true });
8039
+ const commandsDir = join28(ctx.projectRoot, ctx.outputPath);
8040
+ await mkdir15(commandsDir, { recursive: true });
7556
8041
  const filesWritten = [];
7557
8042
  const managedOutputs = [];
7558
8043
  for (const command of bundle.commands) {
@@ -7560,9 +8045,9 @@ var OpenCodeCommandsWriter = {
7560
8045
  const content = `${frontmatter}
7561
8046
 
7562
8047
  ${command.prompt}`;
7563
- const commandPath = join26(commandsDir, `${command.name}.md`);
7564
- await writeFile21(commandPath, content, "utf-8");
7565
- const relativePath = join26(ctx.outputPath, `${command.name}.md`);
8048
+ const commandPath = join28(commandsDir, `${command.name}.md`);
8049
+ await writeFile23(commandPath, content, "utf-8");
8050
+ const relativePath = join28(ctx.outputPath, `${command.name}.md`);
7566
8051
  filesWritten.push(relativePath);
7567
8052
  managedOutputs.push(createManagedOutput(relativePath, this.id, content));
7568
8053
  }
@@ -7583,7 +8068,7 @@ var opencodeAdapter = {
7583
8068
  { writer: OpenCodeCommandsWriter, outputPath: ".opencode/commands/" }
7584
8069
  ],
7585
8070
  async init(ctx) {
7586
- const opencodeDir = join27(ctx.projectRoot, ".opencode");
8071
+ const opencodeDir = join29(ctx.projectRoot, ".opencode");
7587
8072
  mkdirSync8(opencodeDir, { recursive: true });
7588
8073
  return {
7589
8074
  filesCreated: [".opencode/"],
@@ -7885,7 +8370,7 @@ If the capability name is omitted, it will be inferred from:
7885
8370
  - For GitHub sources: the repository name or last path segment
7886
8371
 
7887
8372
  Claude plugins (.claude-plugin/plugin.json) are automatically wrapped as OmniDev capabilities.
7888
- Hooks defined in hooks.json are also supported and will be synced to .claude/settings.json.
8373
+ Hooks defined in hooks.json are also supported and will be synced into OmniDev's hook pipeline.
7889
8374
 
7890
8375
  Examples:
7891
8376
  omnidev add cap my-cap --github expo/skills # Uses version = "latest"
@@ -8041,8 +8526,8 @@ var addRoutes = buildRouteMap({
8041
8526
 
8042
8527
  // src/commands/capability.ts
8043
8528
  import { existsSync as existsSync25, mkdirSync as mkdirSync9 } from "node:fs";
8044
- import { writeFile as writeFile22 } from "node:fs/promises";
8045
- import { join as join28 } from "node:path";
8529
+ import { writeFile as writeFile24 } from "node:fs/promises";
8530
+ import { join as join30 } from "node:path";
8046
8531
  import { input } from "@inquirer/prompts";
8047
8532
  init_src();
8048
8533
  import { buildCommand as buildCommand2, buildRouteMap as buildRouteMap2 } from "@stricli/core";
@@ -8262,21 +8747,21 @@ async function runCapabilityNew(flags, capabilityId) {
8262
8747
  const name = toTitleCase(id);
8263
8748
  mkdirSync9(capabilityDir, { recursive: true });
8264
8749
  const capabilityToml = generateCapabilityToml2({ id, name });
8265
- await writeFile22(join28(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
8266
- const skillDir = join28(capabilityDir, "skills", "getting-started");
8750
+ await writeFile24(join30(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
8751
+ const skillDir = join30(capabilityDir, "skills", "getting-started");
8267
8752
  mkdirSync9(skillDir, { recursive: true });
8268
- await writeFile22(join28(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
8269
- const rulesDir = join28(capabilityDir, "rules");
8753
+ await writeFile24(join30(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
8754
+ const rulesDir = join30(capabilityDir, "rules");
8270
8755
  mkdirSync9(rulesDir, { recursive: true });
8271
- await writeFile22(join28(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
8272
- const hooksDir = join28(capabilityDir, "hooks");
8756
+ await writeFile24(join30(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
8757
+ const hooksDir = join30(capabilityDir, "hooks");
8273
8758
  mkdirSync9(hooksDir, { recursive: true });
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");
8759
+ await writeFile24(join30(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
8760
+ await writeFile24(join30(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
8761
+ await writeFile24(join30(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
8277
8762
  if (flags.programmatic) {
8278
- await writeFile22(join28(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
8279
- await writeFile22(join28(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
8763
+ await writeFile24(join30(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
8764
+ await writeFile24(join30(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
8280
8765
  }
8281
8766
  console.log(`✓ Created capability: ${name}`);
8282
8767
  console.log(` Location: ${capabilityDir}`);
@@ -8619,7 +9104,7 @@ async function checkCapabilitiesDir() {
8619
9104
  // src/commands/init.ts
8620
9105
  import { exec } from "node:child_process";
8621
9106
  import { existsSync as existsSync27, mkdirSync as mkdirSync10 } from "node:fs";
8622
- import { readFile as readFile21, writeFile as writeFile23 } from "node:fs/promises";
9107
+ import { readFile as readFile21, writeFile as writeFile25 } from "node:fs/promises";
8623
9108
  import { promisify as promisify2 } from "node:util";
8624
9109
  init_src();
8625
9110
  import { buildCommand as buildCommand4 } from "@stricli/core";
@@ -8705,7 +9190,7 @@ async function runInit(_flags, providerArg) {
8705
9190
  await setActiveProfile("default");
8706
9191
  }
8707
9192
  if (!existsSync27("OMNI.md")) {
8708
- await writeFile23("OMNI.md", generateOmniMdTemplate(), "utf-8");
9193
+ await writeFile25("OMNI.md", generateOmniMdTemplate(), "utf-8");
8709
9194
  }
8710
9195
  const config3 = await loadConfig();
8711
9196
  const ctx = {
@@ -8798,7 +9283,7 @@ async function addToGitignore(entriesToAdd, sectionHeader) {
8798
9283
  ${missingEntries.join(`
8799
9284
  `)}
8800
9285
  `;
8801
- await writeFile23(gitignorePath, content + section, "utf-8");
9286
+ await writeFile25(gitignorePath, content + section, "utf-8");
8802
9287
  }
8803
9288
  async function getTrackedProviderFiles(files) {
8804
9289
  const tracked = [];
@@ -9675,7 +10160,7 @@ async function buildDynamicApp() {
9675
10160
  security: securityRoutes
9676
10161
  };
9677
10162
  debug("Core routes registered", Object.keys(routes));
9678
- const configPath = join29(process.cwd(), "omni.toml");
10163
+ const configPath = join31(process.cwd(), "omni.toml");
9679
10164
  debug("Checking for config", { configPath, exists: existsSync32(configPath), cwd: process.cwd() });
9680
10165
  if (existsSync32(configPath)) {
9681
10166
  try {
@@ -9752,10 +10237,10 @@ async function loadCapabilityCommands() {
9752
10237
  return commands;
9753
10238
  }
9754
10239
  async function loadCapabilityExport(capability3) {
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");
10240
+ const capabilityPath = join31(process.cwd(), capability3.path);
10241
+ const builtIndexPath = join31(capabilityPath, "dist", "index.js");
10242
+ const jsIndexPath = join31(capabilityPath, "index.js");
10243
+ const tsIndexPath = join31(capabilityPath, "index.ts");
9759
10244
  debug(`Checking entry points for '${capability3.id}'`, {
9760
10245
  capabilityPath,
9761
10246
  builtIndexPath,