@omnidev-ai/core 0.9.0 → 0.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -855,7 +855,7 @@ function getHooksConfigPath(capabilityPath) {
855
855
 
856
856
  // src/capability/rules.ts
857
857
  import { existsSync as existsSync6, readdirSync as readdirSync3 } from "node:fs";
858
- import { readFile as readFile4, writeFile } from "node:fs/promises";
858
+ import { readFile as readFile4 } from "node:fs/promises";
859
859
  import { basename as basename2, join as join4 } from "node:path";
860
860
  async function loadRules(capabilityPath, capabilityId) {
861
861
  const rulesDir = join4(capabilityPath, "rules");
@@ -877,80 +877,6 @@ async function loadRules(capabilityPath, capabilityId) {
877
877
  }
878
878
  return rules;
879
879
  }
880
- async function writeRules(rules, docs = []) {
881
- const instructionsPath = ".omni/instructions.md";
882
- const rulesContent = generateRulesContent(rules, docs);
883
- let content;
884
- if (existsSync6(instructionsPath)) {
885
- content = await readFile4(instructionsPath, "utf-8");
886
- } else {
887
- content = `# OmniDev Instructions
888
-
889
- ## Project Description
890
- <!-- TODO: Add 2-3 sentences describing your project -->
891
- [Describe what this project does and its main purpose]
892
-
893
- <!-- BEGIN OMNIDEV GENERATED CONTENT - DO NOT EDIT BELOW THIS LINE -->
894
- <!-- END OMNIDEV GENERATED CONTENT -->
895
- `;
896
- }
897
- const beginMarker = "<!-- BEGIN OMNIDEV GENERATED CONTENT - DO NOT EDIT BELOW THIS LINE -->";
898
- const endMarker = "<!-- END OMNIDEV GENERATED CONTENT -->";
899
- const beginIndex = content.indexOf(beginMarker);
900
- const endIndex = content.indexOf(endMarker);
901
- if (beginIndex === -1 || endIndex === -1) {
902
- content += `
903
-
904
- ${beginMarker}
905
- ${rulesContent}
906
- ${endMarker}
907
- `;
908
- } else {
909
- content = content.substring(0, beginIndex + beginMarker.length) + `
910
- ` + rulesContent + `
911
- ` + content.substring(endIndex);
912
- }
913
- await writeFile(instructionsPath, content, "utf-8");
914
- }
915
- function generateRulesContent(rules, docs = []) {
916
- if (rules.length === 0 && docs.length === 0) {
917
- return `<!-- This section is automatically updated when capabilities change -->
918
-
919
- ## Capabilities
920
-
921
- No capabilities enabled yet. Run \`omnidev capability enable <name>\` to enable capabilities.`;
922
- }
923
- let content = `<!-- This section is automatically updated when capabilities change -->
924
-
925
- ## Capabilities
926
-
927
- `;
928
- if (docs.length > 0) {
929
- content += `### Documentation
930
-
931
- `;
932
- for (const doc of docs) {
933
- content += `#### ${doc.name} (from ${doc.capabilityId})
934
-
935
- ${doc.content}
936
-
937
- `;
938
- }
939
- }
940
- if (rules.length > 0) {
941
- content += `### Rules
942
-
943
- `;
944
- for (const rule of rules) {
945
- content += `#### ${rule.name} (from ${rule.capabilityId})
946
-
947
- ${rule.content}
948
-
949
- `;
950
- }
951
- }
952
- return content.trim();
953
- }
954
880
 
955
881
  // src/capability/skills.ts
956
882
  import { existsSync as existsSync7, readdirSync as readdirSync4 } from "node:fs";
@@ -1323,7 +1249,7 @@ async function loadCapability(capabilityPath, env) {
1323
1249
  }
1324
1250
  // src/config/config.ts
1325
1251
  import { existsSync as existsSync10 } from "node:fs";
1326
- import { readFile as readFile8, writeFile as writeFile2 } from "node:fs/promises";
1252
+ import { readFile as readFile8, writeFile } from "node:fs/promises";
1327
1253
  var CONFIG_PATH = "omni.toml";
1328
1254
  var LOCAL_CONFIG = "omni.local.toml";
1329
1255
  function mergeConfigs(base, override) {
@@ -1359,7 +1285,7 @@ async function loadConfig() {
1359
1285
  }
1360
1286
  async function writeConfig(config) {
1361
1287
  const content = generateConfigToml(config);
1362
- await writeFile2(CONFIG_PATH, content, "utf-8");
1288
+ await writeFile(CONFIG_PATH, content, "utf-8");
1363
1289
  }
1364
1290
  function generateConfigToml(config) {
1365
1291
  const lines = [];
@@ -1414,7 +1340,7 @@ function generateConfigToml(config) {
1414
1340
  for (const [name, sourceConfig] of Object.entries(sources)) {
1415
1341
  if (typeof sourceConfig === "string") {
1416
1342
  lines.push(`${name} = "${sourceConfig}"`);
1417
- } else if (sourceConfig.path) {
1343
+ } else if ("path" in sourceConfig && sourceConfig.path) {
1418
1344
  lines.push(`${name} = { source = "${sourceConfig.source}", path = "${sourceConfig.path}" }`);
1419
1345
  } else {
1420
1346
  lines.push(`${name} = "${sourceConfig.source}"`);
@@ -1546,7 +1472,7 @@ function generateConfigToml(config) {
1546
1472
 
1547
1473
  // src/state/active-profile.ts
1548
1474
  import { existsSync as existsSync11, mkdirSync } from "node:fs";
1549
- import { readFile as readFile9, unlink, writeFile as writeFile3 } from "node:fs/promises";
1475
+ import { readFile as readFile9, unlink, writeFile as writeFile2 } from "node:fs/promises";
1550
1476
  var STATE_DIR = ".omni/state";
1551
1477
  var ACTIVE_PROFILE_PATH = `${STATE_DIR}/active-profile`;
1552
1478
  async function readActiveProfileState() {
@@ -1563,7 +1489,7 @@ async function readActiveProfileState() {
1563
1489
  }
1564
1490
  async function writeActiveProfileState(profileName) {
1565
1491
  mkdirSync(STATE_DIR, { recursive: true });
1566
- await writeFile3(ACTIVE_PROFILE_PATH, profileName, "utf-8");
1492
+ await writeFile2(ACTIVE_PROFILE_PATH, profileName, "utf-8");
1567
1493
  }
1568
1494
  async function clearActiveProfileState() {
1569
1495
  if (existsSync11(ACTIVE_PROFILE_PATH)) {
@@ -1779,9 +1705,26 @@ async function buildCapabilityRegistry() {
1779
1705
  // src/capability/sources.ts
1780
1706
  import { existsSync as existsSync12 } from "node:fs";
1781
1707
  import { spawn } from "node:child_process";
1782
- import { cp, mkdir, readdir, readFile as readFile10, rename, rm, stat, writeFile as writeFile4 } from "node:fs/promises";
1708
+ import { cp, mkdir, readdir, readFile as readFile10, rename, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
1783
1709
  import { join as join8 } from "node:path";
1784
1710
  import { parse as parseToml2 } from "smol-toml";
1711
+
1712
+ // src/types/index.ts
1713
+ function isFileSourceConfig(config) {
1714
+ if (typeof config === "string") {
1715
+ return config.startsWith("file://");
1716
+ }
1717
+ return config.source.startsWith("file://");
1718
+ }
1719
+ function getActiveProviders(config) {
1720
+ if (config.providers)
1721
+ return config.providers;
1722
+ if (config.provider)
1723
+ return [config.provider];
1724
+ return ["claude"];
1725
+ }
1726
+
1727
+ // src/capability/sources.ts
1785
1728
  var OMNI_LOCAL = ".omni";
1786
1729
  var SKILL_DIRS = ["skills", "skill"];
1787
1730
  var AGENT_DIRS = ["agents", "agent", "subagents", "subagent"];
@@ -1813,8 +1756,39 @@ async function spawnCapture(command, args, options) {
1813
1756
  });
1814
1757
  });
1815
1758
  }
1759
+ function isGitSource(source) {
1760
+ return source.startsWith("github:") || source.startsWith("git@") || source.startsWith("https://") || source.startsWith("http://");
1761
+ }
1762
+ function isFileSource(source) {
1763
+ return source.startsWith("file://");
1764
+ }
1765
+ function parseFileSourcePath(source) {
1766
+ if (!source.startsWith("file://")) {
1767
+ throw new Error(`Invalid file source: ${source}`);
1768
+ }
1769
+ return source.slice(7);
1770
+ }
1771
+ async function readCapabilityIdFromPath(capabilityPath) {
1772
+ const tomlPath = join8(capabilityPath, "capability.toml");
1773
+ if (existsSync12(tomlPath)) {
1774
+ try {
1775
+ const content = await readFile10(tomlPath, "utf-8");
1776
+ const parsed = parseToml2(content);
1777
+ const capability = parsed["capability"];
1778
+ if (capability?.["id"] && typeof capability["id"] === "string") {
1779
+ return capability["id"];
1780
+ }
1781
+ } catch {}
1782
+ }
1783
+ const parts = capabilityPath.replace(/\\/g, "/").split("/");
1784
+ const dirName = parts.pop() || parts.pop();
1785
+ return dirName || null;
1786
+ }
1816
1787
  function parseSourceConfig(source) {
1817
1788
  if (typeof source === "string") {
1789
+ if (isFileSource(source)) {
1790
+ return { source };
1791
+ }
1818
1792
  let sourceUrl = source;
1819
1793
  let ref;
1820
1794
  if (source.startsWith("github:") && source.includes("#")) {
@@ -1828,6 +1802,9 @@ function parseSourceConfig(source) {
1828
1802
  }
1829
1803
  return result;
1830
1804
  }
1805
+ if (isFileSourceConfig(source)) {
1806
+ return source;
1807
+ }
1831
1808
  return source;
1832
1809
  }
1833
1810
  function sourceToGitUrl(source) {
@@ -1886,7 +1863,7 @@ async function saveLockFile(lockFile) {
1886
1863
 
1887
1864
  `;
1888
1865
  const content = header + stringifyLockFile(lockFile);
1889
- await writeFile4(lockPath, content, "utf-8");
1866
+ await writeFile3(lockPath, content, "utf-8");
1890
1867
  }
1891
1868
  async function getRepoCommit(repoPath) {
1892
1869
  const { exitCode, stdout, stderr } = await spawnCapture("git", ["rev-parse", "HEAD"], {
@@ -2157,7 +2134,7 @@ repository = "${repoUrl}"
2157
2134
  wrapped = true
2158
2135
  commit = "${commit}"
2159
2136
  `;
2160
- await writeFile4(join8(repoPath, "capability.toml"), tomlContent, "utf-8");
2137
+ await writeFile3(join8(repoPath, "capability.toml"), tomlContent, "utf-8");
2161
2138
  }
2162
2139
  async function fetchGitCapabilitySource(id, config, options) {
2163
2140
  const gitUrl = sourceToGitUrl(config.source);
@@ -2249,8 +2226,52 @@ async function fetchGitCapabilitySource(id, config, options) {
2249
2226
  wrapped: needsWrap
2250
2227
  };
2251
2228
  }
2229
+ async function fetchFileCapabilitySource(id, config, options) {
2230
+ const sourcePath = parseFileSourcePath(config.source);
2231
+ const targetPath = getSourceCapabilityPath(id);
2232
+ if (!existsSync12(sourcePath)) {
2233
+ throw new Error(`File source not found: ${sourcePath}`);
2234
+ }
2235
+ const sourceStats = await stat(sourcePath);
2236
+ if (!sourceStats.isDirectory()) {
2237
+ throw new Error(`File source must be a directory: ${sourcePath}`);
2238
+ }
2239
+ if (!existsSync12(join8(sourcePath, "capability.toml"))) {
2240
+ throw new Error(`No capability.toml found in: ${sourcePath}`);
2241
+ }
2242
+ if (!options?.silent) {
2243
+ console.log(` Copying ${id} from ${sourcePath}...`);
2244
+ }
2245
+ if (existsSync12(targetPath)) {
2246
+ await rm(targetPath, { recursive: true });
2247
+ }
2248
+ await mkdir(join8(targetPath, ".."), { recursive: true });
2249
+ await cp(sourcePath, targetPath, { recursive: true });
2250
+ let version = "local";
2251
+ const capTomlPath = join8(targetPath, "capability.toml");
2252
+ if (existsSync12(capTomlPath)) {
2253
+ try {
2254
+ const content = await readFile10(capTomlPath, "utf-8");
2255
+ const parsed = parseToml2(content);
2256
+ const capability = parsed["capability"];
2257
+ if (capability?.["version"] && typeof capability["version"] === "string") {
2258
+ version = capability["version"];
2259
+ }
2260
+ } catch {}
2261
+ }
2262
+ return {
2263
+ id,
2264
+ path: targetPath,
2265
+ version,
2266
+ updated: true,
2267
+ wrapped: false
2268
+ };
2269
+ }
2252
2270
  async function fetchCapabilitySource(id, sourceConfig, options) {
2253
2271
  const config = parseSourceConfig(sourceConfig);
2272
+ if (isFileSourceConfig(sourceConfig) || isFileSource(config.source)) {
2273
+ return fetchFileCapabilitySource(id, config, options);
2274
+ }
2254
2275
  return fetchGitCapabilitySource(id, config, options);
2255
2276
  }
2256
2277
  function generateMcpCapabilityTomlContent(id, mcpConfig) {
@@ -2317,7 +2338,7 @@ generated_from_omni_toml = true
2317
2338
  }
2318
2339
  async function generateMcpCapabilityToml(id, mcpConfig, targetPath) {
2319
2340
  const tomlContent = generateMcpCapabilityTomlContent(id, mcpConfig);
2320
- await writeFile4(join8(targetPath, "capability.toml"), tomlContent, "utf-8");
2341
+ await writeFile3(join8(targetPath, "capability.toml"), tomlContent, "utf-8");
2321
2342
  }
2322
2343
  async function isGeneratedMcpCapability(capabilityDir) {
2323
2344
  const tomlPath = join8(capabilityDir, "capability.toml");
@@ -2387,12 +2408,14 @@ async function fetchAllCapabilitySources(config, options) {
2387
2408
  version: result.version,
2388
2409
  updated_at: new Date().toISOString()
2389
2410
  };
2390
- const gitConfig = parseSourceConfig(source);
2391
2411
  if (result.commit) {
2392
2412
  lockEntry.commit = result.commit;
2393
2413
  }
2394
- if (gitConfig.ref) {
2395
- lockEntry.ref = gitConfig.ref;
2414
+ if (!isFileSourceConfig(source)) {
2415
+ const gitConfig = parseSourceConfig(source);
2416
+ if (gitConfig.ref) {
2417
+ lockEntry.ref = gitConfig.ref;
2418
+ }
2396
2419
  }
2397
2420
  const existing = lockFile.capabilities[id];
2398
2421
  const hasChanged = !existing || existing.commit !== result.commit;
@@ -2432,6 +2455,16 @@ async function checkForUpdates(config) {
2432
2455
  const sourceConfig = parseSourceConfig(source);
2433
2456
  const targetPath = getSourceCapabilityPath(id);
2434
2457
  const existing = lockFile.capabilities[id];
2458
+ if (isFileSourceConfig(source) || isFileSource(sourceConfig.source)) {
2459
+ updates.push({
2460
+ id,
2461
+ source: sourceConfig.source,
2462
+ currentVersion: existing?.version || "local",
2463
+ latestVersion: "local",
2464
+ hasUpdate: false
2465
+ });
2466
+ continue;
2467
+ }
2435
2468
  const gitConfig = sourceConfig;
2436
2469
  if (!existsSync12(join8(targetPath, ".git"))) {
2437
2470
  updates.push({
@@ -2470,7 +2503,7 @@ async function checkForUpdates(config) {
2470
2503
  }
2471
2504
  // src/config/provider.ts
2472
2505
  import { existsSync as existsSync13 } from "node:fs";
2473
- import { readFile as readFile11, writeFile as writeFile5 } from "node:fs/promises";
2506
+ import { readFile as readFile11, writeFile as writeFile4 } from "node:fs/promises";
2474
2507
  import { parse as parse2 } from "smol-toml";
2475
2508
  var PROVIDER_CONFIG_PATH = ".omni/provider.toml";
2476
2509
  async function loadProviderConfig() {
@@ -2504,7 +2537,7 @@ async function writeProviderConfig(config) {
2504
2537
  lines.push("# Default: Claude");
2505
2538
  lines.push('provider = "claude"');
2506
2539
  }
2507
- await writeFile5(PROVIDER_CONFIG_PATH, `${lines.join(`
2540
+ await writeFile4(PROVIDER_CONFIG_PATH, `${lines.join(`
2508
2541
  `)}
2509
2542
  `, "utf-8");
2510
2543
  }
@@ -2520,7 +2553,7 @@ function parseProviderFlag(flag) {
2520
2553
  }
2521
2554
  // src/config/toml-patcher.ts
2522
2555
  import { existsSync as existsSync14 } from "node:fs";
2523
- import { readFile as readFile12, writeFile as writeFile6 } from "node:fs/promises";
2556
+ import { readFile as readFile12, writeFile as writeFile5 } from "node:fs/promises";
2524
2557
  var CONFIG_PATH2 = "omni.toml";
2525
2558
  async function readConfigFile() {
2526
2559
  if (!existsSync14(CONFIG_PATH2)) {
@@ -2529,7 +2562,7 @@ async function readConfigFile() {
2529
2562
  return readFile12(CONFIG_PATH2, "utf-8");
2530
2563
  }
2531
2564
  async function writeConfigFile(content) {
2532
- await writeFile6(CONFIG_PATH2, content, "utf-8");
2565
+ await writeFile5(CONFIG_PATH2, content, "utf-8");
2533
2566
  }
2534
2567
  function findSection(lines, sectionPattern) {
2535
2568
  return lines.findIndex((line) => sectionPattern.test(line.trim()));
@@ -2550,7 +2583,7 @@ function formatCapabilitySource(name, source) {
2550
2583
  if (typeof source === "string") {
2551
2584
  return `${name} = "${source}"`;
2552
2585
  }
2553
- if (source.path) {
2586
+ if ("path" in source && source.path) {
2554
2587
  return `${name} = { source = "${source.source}", path = "${source.path}" }`;
2555
2588
  }
2556
2589
  return `${name} = "${source.source}"`;
@@ -2726,7 +2759,7 @@ function escapeRegExp(str) {
2726
2759
  }
2727
2760
  // src/mcp-json/manager.ts
2728
2761
  import { existsSync as existsSync15 } from "node:fs";
2729
- import { readFile as readFile13, writeFile as writeFile7 } from "node:fs/promises";
2762
+ import { readFile as readFile13, writeFile as writeFile6 } from "node:fs/promises";
2730
2763
  var MCP_JSON_PATH = ".mcp.json";
2731
2764
  async function readMcpJson() {
2732
2765
  if (!existsSync15(MCP_JSON_PATH)) {
@@ -2743,7 +2776,7 @@ async function readMcpJson() {
2743
2776
  }
2744
2777
  }
2745
2778
  async function writeMcpJson(config2) {
2746
- await writeFile7(MCP_JSON_PATH, `${JSON.stringify(config2, null, 2)}
2779
+ await writeFile6(MCP_JSON_PATH, `${JSON.stringify(config2, null, 2)}
2747
2780
  `, "utf-8");
2748
2781
  }
2749
2782
  function buildMcpServerConfig(mcp) {
@@ -2813,7 +2846,7 @@ async function syncMcpJson(capabilities2, previousManifest, options = {}) {
2813
2846
  }
2814
2847
  // src/state/manifest.ts
2815
2848
  import { existsSync as existsSync16, mkdirSync as mkdirSync2, rmSync } from "node:fs";
2816
- import { readFile as readFile14, writeFile as writeFile8 } from "node:fs/promises";
2849
+ import { readFile as readFile14, writeFile as writeFile7 } from "node:fs/promises";
2817
2850
  var MANIFEST_PATH = ".omni/state/manifest.json";
2818
2851
  var CURRENT_VERSION = 1;
2819
2852
  async function loadManifest() {
@@ -2829,7 +2862,7 @@ async function loadManifest() {
2829
2862
  }
2830
2863
  async function saveManifest(manifest) {
2831
2864
  mkdirSync2(".omni/state", { recursive: true });
2832
- await writeFile8(MANIFEST_PATH, `${JSON.stringify(manifest, null, 2)}
2865
+ await writeFile7(MANIFEST_PATH, `${JSON.stringify(manifest, null, 2)}
2833
2866
  `, "utf-8");
2834
2867
  }
2835
2868
  function buildManifestFromCapabilities(capabilities2) {
@@ -2881,7 +2914,7 @@ async function cleanupStaleResources(previousManifest, currentCapabilityIds) {
2881
2914
  }
2882
2915
  // src/state/providers.ts
2883
2916
  import { existsSync as existsSync17, mkdirSync as mkdirSync3 } from "node:fs";
2884
- import { readFile as readFile15, writeFile as writeFile9 } from "node:fs/promises";
2917
+ import { readFile as readFile15, writeFile as writeFile8 } from "node:fs/promises";
2885
2918
  var STATE_DIR2 = ".omni/state";
2886
2919
  var PROVIDERS_PATH = `${STATE_DIR2}/providers.json`;
2887
2920
  var DEFAULT_PROVIDERS = ["claude-code"];
@@ -2900,7 +2933,7 @@ async function readEnabledProviders() {
2900
2933
  async function writeEnabledProviders(providers) {
2901
2934
  mkdirSync3(STATE_DIR2, { recursive: true });
2902
2935
  const state = { enabled: providers };
2903
- await writeFile9(PROVIDERS_PATH, `${JSON.stringify(state, null, 2)}
2936
+ await writeFile8(PROVIDERS_PATH, `${JSON.stringify(state, null, 2)}
2904
2937
  `, "utf-8");
2905
2938
  }
2906
2939
  async function enableProvider(providerId) {
@@ -2995,7 +3028,6 @@ async function buildSyncBundle(options) {
2995
3028
  docs,
2996
3029
  commands,
2997
3030
  subagents,
2998
- instructionsPath: ".omni/instructions.md",
2999
3031
  instructionsContent
3000
3032
  };
3001
3033
  if (hasAnyHooks(mergedHooks)) {
@@ -3044,7 +3076,6 @@ async function syncAgentConfiguration(options) {
3044
3076
  }
3045
3077
  }
3046
3078
  mkdirSync4(".omni", { recursive: true });
3047
- await writeRules(bundle.rules, bundle.docs);
3048
3079
  await syncMcpJson(capabilities2, previousManifest, { silent });
3049
3080
  const newManifest = buildManifestFromCapabilities(capabilities2);
3050
3081
  await saveManifest(newManifest);
@@ -3067,7 +3098,7 @@ async function syncAgentConfiguration(options) {
3067
3098
  }
3068
3099
  if (!silent) {
3069
3100
  console.log("✓ Synced:");
3070
- console.log(` - .omni/instructions.md (${bundle.docs.length} docs, ${bundle.rules.length} rules)`);
3101
+ console.log(` - ${bundle.docs.length} docs, ${bundle.rules.length} rules`);
3071
3102
  if (adapters.length > 0) {
3072
3103
  console.log(` - Provider adapters: ${adapters.map((a) => a.displayName).join(", ")}`);
3073
3104
  }
@@ -3122,56 +3153,150 @@ function generateAgentsTemplate() {
3122
3153
 
3123
3154
  ## OmniDev
3124
3155
 
3125
- @import .omni/instructions.md
3156
+ <!-- This section is populated during sync with capability rules and docs -->
3126
3157
  `;
3127
3158
  }
3128
- // src/templates/claude.ts
3129
- function generateClaudeTemplate() {
3130
- return `# Project Instructions
3159
+ // src/templates/capability.ts
3160
+ function generateCapabilityToml2(options) {
3161
+ const description = options.description || "TODO: Add a description for your capability";
3162
+ return `[capability]
3163
+ id = "${options.id}"
3164
+ name = "${options.name}"
3165
+ version = "0.1.0"
3166
+ description = "${description}"
3131
3167
 
3132
- <!-- Add your project-specific instructions here -->
3168
+ # Optional author information
3169
+ # [capability.author]
3170
+ # name = "Your Name"
3171
+ # email = "you@example.com"
3133
3172
 
3134
- ## OmniDev
3173
+ # Optional metadata
3174
+ # [capability.metadata]
3175
+ # repository = "https://github.com/user/repo"
3176
+ # license = "MIT"
3177
+ `;
3178
+ }
3179
+ function generateSkillTemplate(skillName) {
3180
+ return `---
3181
+ name: ${skillName}
3182
+ description: TODO: Add a description for this skill
3183
+ ---
3135
3184
 
3136
- @import .omni/instructions.md
3185
+ ## What I do
3186
+
3187
+ <!-- Describe what this skill helps the AI agent accomplish -->
3188
+ - TODO: List the main capabilities of this skill
3189
+
3190
+ ## When to use me
3191
+
3192
+ <!-- Describe scenarios when this skill should be invoked -->
3193
+ Use this skill when you need to:
3194
+ - TODO: Add trigger conditions
3195
+
3196
+ ## Implementation
3197
+
3198
+ <!-- Add detailed instructions for the AI agent -->
3199
+ ### Steps
3200
+
3201
+ 1. TODO: Add implementation steps
3202
+ 2. Validate inputs and outputs
3203
+ 3. Report results to the user
3204
+
3205
+ ## Examples
3206
+
3207
+ <!-- Optional: Add examples of how this skill should be used -->
3208
+ \`\`\`
3209
+ TODO: Add example usage
3210
+ \`\`\`
3137
3211
  `;
3138
3212
  }
3139
- function generateInstructionsTemplate() {
3140
- return `# OmniDev Instructions
3213
+ function generateRuleTemplate(ruleName) {
3214
+ return `# ${formatDisplayName(ruleName)}
3141
3215
 
3142
- ## Project Description
3143
- <!-- TODO: Add 2-3 sentences describing your project -->
3144
- [Describe what this project does and its main purpose]
3216
+ <!-- Rules are guidelines that the AI agent should follow when working in this project -->
3145
3217
 
3146
- ## How OmniDev Works
3218
+ ## Overview
3147
3219
 
3148
- OmniDev manages capability content for your project. Capabilities can provide:
3220
+ TODO: Describe what this rule enforces or guides.
3149
3221
 
3150
- - Skills (for agent workflows)
3151
- - Rules (for guardrails and conventions)
3152
- - Docs (reference material)
3153
- - Commands and subagents (optional)
3222
+ ## Guidelines
3154
3223
 
3155
- Enable capabilities with:
3224
+ - TODO: Add specific guidelines the AI should follow
3225
+ - Be specific and actionable
3226
+ - Include examples where helpful
3227
+
3228
+ ## Examples
3229
+
3230
+ ### Good
3156
3231
 
3157
3232
  \`\`\`
3158
- omnidev capability enable <capability-id>
3233
+ TODO: Add example of correct behavior
3159
3234
  \`\`\`
3160
3235
 
3161
- OmniDev will automatically sync enabled capabilities into your workspace. If you want to force a refresh:
3236
+ ### Bad
3162
3237
 
3163
3238
  \`\`\`
3164
- omnidev sync
3239
+ TODO: Add example of incorrect behavior
3165
3240
  \`\`\`
3241
+ `;
3242
+ }
3243
+ function generateHooksTemplate() {
3244
+ return `# Hook configuration for this capability
3245
+ # See: https://omnidev.dev/docs/advanced/hooks
3246
+
3247
+ # Example: Validate bash commands before execution
3248
+ # [[PreToolUse]]
3249
+ # matcher = "Bash"
3250
+ # [[PreToolUse.hooks]]
3251
+ # type = "command"
3252
+ # command = "\${OMNIDEV_CAPABILITY_ROOT}/hooks/validate-bash.sh"
3253
+ # timeout = 30
3254
+
3255
+ # Example: Run linter after file edits
3256
+ # [[PostToolUse]]
3257
+ # matcher = "Write|Edit"
3258
+ # [[PostToolUse.hooks]]
3259
+ # type = "command"
3260
+ # command = "\${OMNIDEV_CAPABILITY_ROOT}/hooks/run-linter.sh"
3261
+
3262
+ # Example: Load context at session start
3263
+ # [[SessionStart]]
3264
+ # matcher = "startup|resume"
3265
+ # [[SessionStart.hooks]]
3266
+ # type = "command"
3267
+ # command = "\${OMNIDEV_CAPABILITY_ROOT}/hooks/load-context.sh"
3268
+ `;
3269
+ }
3270
+ function generateHookScript() {
3271
+ return `#!/bin/bash
3272
+ # Sample hook script
3273
+ # This script receives JSON input via stdin
3274
+
3275
+ # Read JSON input from stdin
3276
+ INPUT=$(cat)
3277
+
3278
+ # Example: Extract tool information
3279
+ # TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
3280
+ # COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
3166
3281
 
3167
- <!-- BEGIN OMNIDEV GENERATED CONTENT - DO NOT EDIT BELOW THIS LINE -->
3168
- <!-- This section is automatically updated by 'omnidev agents sync' -->
3282
+ # Add your validation logic here
3283
+ # Exit 0 to allow, exit 2 to block
3284
+
3285
+ exit 0
3286
+ `;
3287
+ }
3288
+ function formatDisplayName(kebabCase) {
3289
+ return kebabCase.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
3290
+ }
3291
+ // src/templates/claude.ts
3292
+ function generateClaudeTemplate() {
3293
+ return `# Project Instructions
3169
3294
 
3170
- ## Capabilities
3295
+ <!-- Add your project-specific instructions here -->
3171
3296
 
3172
- No capabilities enabled yet. Run \`omnidev capability enable <name>\` to enable capabilities.
3297
+ ## OmniDev
3173
3298
 
3174
- <!-- END OMNIDEV GENERATED CONTENT -->
3299
+ <!-- This section is populated during sync with capability rules and docs -->
3175
3300
  `;
3176
3301
  }
3177
3302
  // src/templates/omni.ts
@@ -3195,14 +3320,6 @@ function generateOmniMdTemplate() {
3195
3320
  <!-- Describe your project's architecture and key components -->
3196
3321
  `;
3197
3322
  }
3198
- // src/types/index.ts
3199
- function getActiveProviders(config2) {
3200
- if (config2.providers)
3201
- return config2.providers;
3202
- if (config2.provider)
3203
- return [config2.provider];
3204
- return ["claude"];
3205
- }
3206
3323
  // src/debug.ts
3207
3324
  function debug(message, data) {
3208
3325
  if (process.env["OMNIDEV_DEBUG"] !== "1") {
@@ -3224,7 +3341,6 @@ function getVersion() {
3224
3341
  return version;
3225
3342
  }
3226
3343
  export {
3227
- writeRules,
3228
3344
  writeProviderConfig,
3229
3345
  writeMcpJson,
3230
3346
  writeEnabledProviders,
@@ -3247,6 +3363,7 @@ export {
3247
3363
  resolveEnabledCapabilities,
3248
3364
  readMcpJson,
3249
3365
  readEnabledProviders,
3366
+ readCapabilityIdFromPath,
3250
3367
  readActiveProfileState,
3251
3368
  patchAddToProfile,
3252
3369
  patchAddMcp,
@@ -3254,6 +3371,7 @@ export {
3254
3371
  parseSourceConfig,
3255
3372
  parseProviderFlag,
3256
3373
  parseOmniConfig,
3374
+ parseFileSourcePath,
3257
3375
  parseCapabilityConfig,
3258
3376
  mergeHooksConfigs,
3259
3377
  mergeAndDeduplicateHooks,
@@ -3282,6 +3400,9 @@ export {
3282
3400
  isHookPrompt,
3283
3401
  isHookEvent,
3284
3402
  isHookCommand,
3403
+ isGitSource,
3404
+ isFileSourceConfig,
3405
+ isFileSource,
3285
3406
  installCapabilityDependencies,
3286
3407
  hasHooks,
3287
3408
  hasAnyHooks,
@@ -3294,9 +3415,13 @@ export {
3294
3415
  getEnabledCapabilities,
3295
3416
  getActiveProviders,
3296
3417
  getActiveProfile,
3418
+ generateSkillTemplate,
3419
+ generateRuleTemplate,
3297
3420
  generateOmniMdTemplate,
3298
- generateInstructionsTemplate,
3421
+ generateHooksTemplate,
3422
+ generateHookScript,
3299
3423
  generateClaudeTemplate,
3424
+ generateCapabilityToml2 as generateCapabilityToml,
3300
3425
  generateAgentsTemplate,
3301
3426
  findDuplicateCommands,
3302
3427
  fetchCapabilitySource,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@omnidev-ai/core",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "repository": {