@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.d.ts +62 -20
- package/dist/index.js +263 -138
- package/package.json +1 -1
- package/src/capability/index.ts +5 -1
- package/src/capability/rules.ts +2 -100
- package/src/capability/sources.ts +155 -9
- package/src/config/config.ts +2 -2
- package/src/config/toml-patcher.ts +1 -1
- package/src/index.ts +1 -0
- package/src/sync.ts +1 -8
- package/src/templates/agents.ts +2 -2
- package/src/templates/capability.ts +167 -0
- package/src/templates/claude.ts +2 -45
- package/src/types/index.ts +23 -4
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 (
|
|
2395
|
-
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(` -
|
|
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
|
-
|
|
3156
|
+
<!-- This section is populated during sync with capability rules and docs -->
|
|
3126
3157
|
`;
|
|
3127
3158
|
}
|
|
3128
|
-
// src/templates/
|
|
3129
|
-
function
|
|
3130
|
-
|
|
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
|
-
|
|
3168
|
+
# Optional author information
|
|
3169
|
+
# [capability.author]
|
|
3170
|
+
# name = "Your Name"
|
|
3171
|
+
# email = "you@example.com"
|
|
3133
3172
|
|
|
3134
|
-
|
|
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
|
-
|
|
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
|
|
3140
|
-
return `#
|
|
3213
|
+
function generateRuleTemplate(ruleName) {
|
|
3214
|
+
return `# ${formatDisplayName(ruleName)}
|
|
3141
3215
|
|
|
3142
|
-
|
|
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
|
-
##
|
|
3218
|
+
## Overview
|
|
3147
3219
|
|
|
3148
|
-
|
|
3220
|
+
TODO: Describe what this rule enforces or guides.
|
|
3149
3221
|
|
|
3150
|
-
|
|
3151
|
-
- Rules (for guardrails and conventions)
|
|
3152
|
-
- Docs (reference material)
|
|
3153
|
-
- Commands and subagents (optional)
|
|
3222
|
+
## Guidelines
|
|
3154
3223
|
|
|
3155
|
-
|
|
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
|
-
|
|
3233
|
+
TODO: Add example of correct behavior
|
|
3159
3234
|
\`\`\`
|
|
3160
3235
|
|
|
3161
|
-
|
|
3236
|
+
### Bad
|
|
3162
3237
|
|
|
3163
3238
|
\`\`\`
|
|
3164
|
-
|
|
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
|
-
|
|
3168
|
-
|
|
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
|
-
|
|
3295
|
+
<!-- Add your project-specific instructions here -->
|
|
3171
3296
|
|
|
3172
|
-
|
|
3297
|
+
## OmniDev
|
|
3173
3298
|
|
|
3174
|
-
<!--
|
|
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
|
-
|
|
3421
|
+
generateHooksTemplate,
|
|
3422
|
+
generateHookScript,
|
|
3299
3423
|
generateClaudeTemplate,
|
|
3424
|
+
generateCapabilityToml2 as generateCapabilityToml,
|
|
3300
3425
|
generateAgentsTemplate,
|
|
3301
3426
|
findDuplicateCommands,
|
|
3302
3427
|
fetchCapabilitySource,
|