@omnidev-ai/core 0.1.1 → 0.3.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/package.json +1 -1
- package/src/capability/commands.test.ts +6 -10
- package/src/capability/docs.test.ts +39 -46
- package/src/capability/docs.ts +3 -1
- package/src/capability/loader.test.ts +10 -157
- package/src/capability/loader.ts +8 -69
- package/src/capability/registry.test.ts +9 -27
- package/src/capability/rules.test.ts +25 -35
- package/src/capability/rules.ts +3 -1
- package/src/capability/skills.test.ts +6 -10
- package/src/capability/sources.test.ts +142 -41
- package/src/capability/sources.ts +377 -345
- package/src/capability/subagents.test.ts +7 -11
- package/src/capability/subagents.ts +3 -1
- package/src/capability/wrapping-integration.test.ts +412 -0
- package/src/config/capabilities.ts +0 -28
- package/src/config/env.test.ts +4 -18
- package/src/config/loader.test.ts +4 -86
- package/src/config/loader.ts +88 -18
- package/src/config/parser.test.ts +0 -25
- package/src/config/profiles.test.ts +5 -39
- package/src/config/provider.test.ts +5 -19
- package/src/index.ts +1 -3
- package/src/mcp-json/manager.test.ts +77 -182
- package/src/mcp-json/manager.ts +22 -34
- package/src/state/active-profile.test.ts +4 -18
- package/src/state/index.ts +1 -0
- package/src/state/manifest.test.ts +25 -162
- package/src/state/manifest.ts +4 -31
- package/src/state/providers.test.ts +125 -0
- package/src/state/providers.ts +69 -0
- package/src/sync.ts +128 -53
- package/src/templates/claude.ts +9 -74
- package/src/test-utils/helpers.test.ts +18 -0
- package/src/test-utils/helpers.ts +87 -2
- package/src/test-utils/index.ts +3 -0
- package/src/types/capability-export.ts +0 -77
- package/src/types/index.ts +66 -22
- package/src/gitignore/manager.test.ts +0 -216
- package/src/gitignore/manager.ts +0 -167
package/src/config/loader.ts
CHANGED
|
@@ -26,6 +26,11 @@ function mergeConfigs(base: OmniConfig, override: OmniConfig): OmniConfig {
|
|
|
26
26
|
};
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// Deep merge mcps (only if at least one config has it)
|
|
30
|
+
if (base.mcps || override.mcps) {
|
|
31
|
+
merged.mcps = { ...base.mcps, ...override.mcps };
|
|
32
|
+
}
|
|
33
|
+
|
|
29
34
|
return merged;
|
|
30
35
|
}
|
|
31
36
|
|
|
@@ -70,65 +75,130 @@ export async function writeConfig(config: OmniConfig): Promise<void> {
|
|
|
70
75
|
function generateConfigToml(config: OmniConfig): string {
|
|
71
76
|
const lines: string[] = [];
|
|
72
77
|
|
|
78
|
+
lines.push("# =============================================================================");
|
|
73
79
|
lines.push("# OmniDev Configuration");
|
|
74
|
-
lines.push("#
|
|
80
|
+
lines.push("# =============================================================================");
|
|
81
|
+
lines.push("# This file defines your project's capabilities, profiles, and settings.");
|
|
82
|
+
lines.push("#");
|
|
83
|
+
lines.push("# Files:");
|
|
84
|
+
lines.push("# • omni.toml - Main config (commit to share with team)");
|
|
85
|
+
lines.push("# • omni.local.toml - Local overrides (add to .gitignore)");
|
|
86
|
+
lines.push("# • omni.lock.toml - Version lock file (commit for reproducibility)");
|
|
87
|
+
lines.push("#");
|
|
88
|
+
lines.push("# Quick start:");
|
|
89
|
+
lines.push("# 1. Add capability sources to [capabilities.sources]");
|
|
90
|
+
lines.push("# 2. Reference them in your profiles");
|
|
91
|
+
lines.push("# 3. Run: omnidev sync");
|
|
92
|
+
lines.push("# 4. Switch profiles: omnidev profile use <name>");
|
|
75
93
|
lines.push("");
|
|
76
94
|
|
|
77
95
|
// Project name
|
|
78
96
|
if (config.project) {
|
|
79
97
|
lines.push(`project = "${config.project}"`);
|
|
98
|
+
lines.push("");
|
|
80
99
|
}
|
|
81
100
|
|
|
82
101
|
// Note: active_profile is stored in .omni/state/active-profile, not in config.toml
|
|
83
102
|
// We still read it from config.toml for backwards compatibility, but don't write it here
|
|
84
103
|
|
|
85
|
-
// Sandbox mode
|
|
86
|
-
if (config.sandbox_enabled !== undefined) {
|
|
87
|
-
lines.push(`sandbox_enabled = ${config.sandbox_enabled}`);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
lines.push("");
|
|
91
|
-
|
|
92
104
|
// Providers
|
|
93
105
|
if (config.providers?.enabled && config.providers.enabled.length > 0) {
|
|
106
|
+
lines.push("# AI providers to enable (claude, codex, or both)");
|
|
94
107
|
lines.push("[providers]");
|
|
95
108
|
lines.push(`enabled = [${config.providers.enabled.map((p) => `"${p}"`).join(", ")}]`);
|
|
96
109
|
lines.push("");
|
|
97
110
|
}
|
|
98
111
|
|
|
99
112
|
// Environment variables
|
|
113
|
+
lines.push("# =============================================================================");
|
|
114
|
+
lines.push("# Environment Variables");
|
|
115
|
+
lines.push("# =============================================================================");
|
|
116
|
+
lines.push("# Global environment variables available to all capabilities.");
|
|
117
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: Example of env var syntax
|
|
118
|
+
lines.push("# Use ${VAR_NAME} syntax to reference shell environment variables.");
|
|
119
|
+
lines.push("#");
|
|
100
120
|
if (config.env && Object.keys(config.env).length > 0) {
|
|
101
121
|
lines.push("[env]");
|
|
102
122
|
for (const [key, value] of Object.entries(config.env)) {
|
|
103
123
|
lines.push(`${key} = "${value}"`);
|
|
104
124
|
}
|
|
105
|
-
|
|
125
|
+
} else {
|
|
126
|
+
lines.push("# [env]");
|
|
127
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: Example of env var syntax
|
|
128
|
+
lines.push('# DATABASE_URL = "${DATABASE_URL}"');
|
|
129
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: Example of env var syntax
|
|
130
|
+
lines.push('# API_KEY = "${MY_API_KEY}"');
|
|
106
131
|
}
|
|
132
|
+
lines.push("");
|
|
107
133
|
|
|
108
134
|
// Capability sources (commented examples)
|
|
109
135
|
lines.push("# =============================================================================");
|
|
110
136
|
lines.push("# Capability Sources");
|
|
111
137
|
lines.push("# =============================================================================");
|
|
112
|
-
lines.push("# Fetch capabilities from Git repositories. On sync, these are
|
|
113
|
-
lines.push("# and
|
|
138
|
+
lines.push("# Fetch capabilities from Git repositories. On sync, these are");
|
|
139
|
+
lines.push("# cloned/updated and made available to your profiles.");
|
|
114
140
|
lines.push("#");
|
|
115
141
|
lines.push("# [capabilities.sources]");
|
|
116
|
-
lines.push("# #
|
|
117
|
-
lines.push('#
|
|
142
|
+
lines.push("# # GitHub shorthand (uses latest commit)");
|
|
143
|
+
lines.push('# tasks = "github:example-org/tasks-capability"');
|
|
144
|
+
lines.push("#");
|
|
145
|
+
lines.push("# # Version pinning (recommended for production)");
|
|
146
|
+
lines.push('# ralph = { source = "github:example-org/ralph", ref = "v1.2.0" }');
|
|
147
|
+
lines.push("#");
|
|
148
|
+
lines.push("# # Other Git sources");
|
|
149
|
+
lines.push('# private = "git@github.com:company/private-cap.git"');
|
|
150
|
+
lines.push('# gitlab = "https://gitlab.com/user/capability.git"');
|
|
151
|
+
lines.push("");
|
|
152
|
+
|
|
153
|
+
// MCP servers (commented examples)
|
|
154
|
+
lines.push("# =============================================================================");
|
|
155
|
+
lines.push("# MCP Servers");
|
|
156
|
+
lines.push("# =============================================================================");
|
|
157
|
+
lines.push("# Define MCP servers that automatically become capabilities.");
|
|
158
|
+
lines.push(
|
|
159
|
+
'# Reference in profiles using the MCP name directly, e.g. capabilities = ["filesystem"]',
|
|
160
|
+
);
|
|
118
161
|
lines.push("#");
|
|
119
|
-
lines.push("#
|
|
120
|
-
lines.push('#
|
|
162
|
+
lines.push("# [mcps.filesystem]");
|
|
163
|
+
lines.push('# command = "npx"');
|
|
164
|
+
lines.push('# args = ["-y", "@modelcontextprotocol/server-filesystem", "/path/to/dir"]');
|
|
165
|
+
lines.push('# transport = "stdio" # stdio (default), sse, or http');
|
|
121
166
|
lines.push("#");
|
|
122
|
-
lines.push("#
|
|
123
|
-
lines.push('#
|
|
167
|
+
lines.push("# [mcps.database]");
|
|
168
|
+
lines.push('# command = "node"');
|
|
169
|
+
lines.push('# args = ["./servers/database.js"]');
|
|
170
|
+
lines.push('# cwd = "./mcp-servers"');
|
|
171
|
+
lines.push("# [mcps.database.env]");
|
|
172
|
+
// biome-ignore lint/suspicious/noTemplateCurlyInString: Example of env var syntax
|
|
173
|
+
lines.push('# DB_URL = "${DATABASE_URL}"');
|
|
174
|
+
lines.push("");
|
|
175
|
+
|
|
176
|
+
// Always enabled capabilities
|
|
177
|
+
lines.push("# =============================================================================");
|
|
178
|
+
lines.push("# Always Enabled Capabilities");
|
|
179
|
+
lines.push("# =============================================================================");
|
|
180
|
+
lines.push("# Capabilities that load in ALL profiles, regardless of profile config.");
|
|
181
|
+
lines.push("# Useful for essential tools needed everywhere.");
|
|
182
|
+
lines.push("#");
|
|
183
|
+
lines.push('# always_enabled_capabilities = ["git-tools", "linting"]');
|
|
124
184
|
lines.push("");
|
|
125
185
|
|
|
126
186
|
// Profiles
|
|
187
|
+
lines.push("# =============================================================================");
|
|
188
|
+
lines.push("# Profiles");
|
|
189
|
+
lines.push("# =============================================================================");
|
|
190
|
+
lines.push("# Define different capability sets for different workflows.");
|
|
191
|
+
lines.push("# Switch profiles with: omnidev profile use <name>");
|
|
192
|
+
lines.push("");
|
|
127
193
|
if (config.profiles && Object.keys(config.profiles).length > 0) {
|
|
128
194
|
for (const [name, profile] of Object.entries(config.profiles)) {
|
|
129
195
|
lines.push(`[profiles.${name}]`);
|
|
130
196
|
const capabilities = profile.capabilities ?? [];
|
|
131
|
-
|
|
197
|
+
if (capabilities.length > 0) {
|
|
198
|
+
lines.push(`capabilities = [${capabilities.map((id) => `"${id}"`).join(", ")}]`);
|
|
199
|
+
} else {
|
|
200
|
+
lines.push("capabilities = []");
|
|
201
|
+
}
|
|
132
202
|
lines.push("");
|
|
133
203
|
}
|
|
134
204
|
}
|
|
@@ -183,31 +183,6 @@ default = "https://api.example.com"
|
|
|
183
183
|
});
|
|
184
184
|
});
|
|
185
185
|
|
|
186
|
-
test("parses capability with MCP config", () => {
|
|
187
|
-
const toml = `
|
|
188
|
-
[capability]
|
|
189
|
-
id = "custom"
|
|
190
|
-
name = "Custom Capability"
|
|
191
|
-
version = "1.0.0"
|
|
192
|
-
description = "Custom MCP"
|
|
193
|
-
|
|
194
|
-
[mcp]
|
|
195
|
-
command = "node"
|
|
196
|
-
args = ["server.js"]
|
|
197
|
-
transport = "stdio"
|
|
198
|
-
|
|
199
|
-
[mcp.env]
|
|
200
|
-
PORT = "3000"
|
|
201
|
-
`;
|
|
202
|
-
|
|
203
|
-
const config = parseCapabilityConfig(toml);
|
|
204
|
-
|
|
205
|
-
expect(config.mcp?.command).toBe("node");
|
|
206
|
-
expect(config.mcp?.args).toEqual(["server.js"]);
|
|
207
|
-
expect(config.mcp?.transport).toBe("stdio");
|
|
208
|
-
expect(config.mcp?.env?.PORT).toBe("3000");
|
|
209
|
-
});
|
|
210
|
-
|
|
211
186
|
test("throws error when capability.id is missing", () => {
|
|
212
187
|
const toml = `
|
|
213
188
|
[capability]
|
|
@@ -1,27 +1,12 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { setupTestDir } from "@omnidev-ai/core/test-utils";
|
|
4
4
|
import { readActiveProfileState } from "../state/active-profile.js";
|
|
5
5
|
import type { OmniConfig } from "../types/index.js";
|
|
6
6
|
import { getActiveProfile, resolveEnabledCapabilities, setActiveProfile } from "./profiles.js";
|
|
7
7
|
|
|
8
8
|
describe("getActiveProfile", () => {
|
|
9
|
-
|
|
10
|
-
let originalCwd: string;
|
|
11
|
-
|
|
12
|
-
beforeEach(() => {
|
|
13
|
-
originalCwd = process.cwd();
|
|
14
|
-
TEST_DIR = tmpdir("profiles-test-");
|
|
15
|
-
process.chdir(TEST_DIR);
|
|
16
|
-
mkdirSync(".omni", { recursive: true });
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
afterEach(() => {
|
|
20
|
-
process.chdir(originalCwd);
|
|
21
|
-
if (existsSync(TEST_DIR)) {
|
|
22
|
-
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
23
|
-
}
|
|
24
|
-
});
|
|
9
|
+
setupTestDir("profiles-test-", { chdir: true, createOmniDir: true });
|
|
25
10
|
|
|
26
11
|
test("returns null when no state file or config exists", async () => {
|
|
27
12
|
const profile = await getActiveProfile();
|
|
@@ -57,26 +42,7 @@ describe("getActiveProfile", () => {
|
|
|
57
42
|
});
|
|
58
43
|
|
|
59
44
|
describe("setActiveProfile", () => {
|
|
60
|
-
|
|
61
|
-
let originalCwd: string;
|
|
62
|
-
|
|
63
|
-
beforeEach(() => {
|
|
64
|
-
if (!existsSync(TEST_DIR)) {
|
|
65
|
-
mkdirSync(TEST_DIR, { recursive: true });
|
|
66
|
-
}
|
|
67
|
-
originalCwd = process.cwd();
|
|
68
|
-
process.chdir(TEST_DIR);
|
|
69
|
-
if (!existsSync(".omni")) {
|
|
70
|
-
mkdirSync(".omni", { recursive: true });
|
|
71
|
-
}
|
|
72
|
-
});
|
|
73
|
-
|
|
74
|
-
afterEach(() => {
|
|
75
|
-
process.chdir(originalCwd);
|
|
76
|
-
if (existsSync(TEST_DIR)) {
|
|
77
|
-
rmSync(TEST_DIR, { recursive: true, force: true });
|
|
78
|
-
}
|
|
79
|
-
});
|
|
45
|
+
setupTestDir("profiles-set-test-", { chdir: true, createOmniDir: true });
|
|
80
46
|
|
|
81
47
|
test("sets active_profile in state file", async () => {
|
|
82
48
|
await setActiveProfile("staging");
|
|
@@ -1,22 +1,8 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import { tmpdir } from "../test-utils/index.js";
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
import { setupTestDir } from "@omnidev-ai/core/test-utils";
|
|
4
3
|
import { parseProviderFlag } from "./provider.js";
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
const originalCwd = process.cwd();
|
|
8
|
-
|
|
9
|
-
beforeEach(() => {
|
|
10
|
-
TEST_DIR = tmpdir("provider-test-");
|
|
11
|
-
process.chdir(TEST_DIR);
|
|
12
|
-
});
|
|
13
|
-
|
|
14
|
-
afterEach(() => {
|
|
15
|
-
process.chdir(originalCwd);
|
|
16
|
-
if (existsSync(TEST_DIR)) {
|
|
17
|
-
rmSync(TEST_DIR, { recursive: true });
|
|
18
|
-
}
|
|
19
|
-
});
|
|
5
|
+
const testDir = setupTestDir("provider-test-", { chdir: true });
|
|
20
6
|
|
|
21
7
|
describe("parseProviderFlag", () => {
|
|
22
8
|
test("parses 'claude' flag", () => {
|
|
@@ -44,7 +30,7 @@ describe("parseProviderFlag", () => {
|
|
|
44
30
|
|
|
45
31
|
describe("writeProviderConfig", () => {
|
|
46
32
|
test("writes single provider config", async () => {
|
|
47
|
-
const testPath = `${
|
|
33
|
+
const testPath = `${testDir.path}/provider.toml`;
|
|
48
34
|
|
|
49
35
|
// Manually write for testing
|
|
50
36
|
const lines: string[] = [];
|
|
@@ -62,7 +48,7 @@ describe("writeProviderConfig", () => {
|
|
|
62
48
|
});
|
|
63
49
|
|
|
64
50
|
test("writes multiple providers config", async () => {
|
|
65
|
-
const testPath = `${
|
|
51
|
+
const testPath = `${testDir.path}/provider.toml`;
|
|
66
52
|
|
|
67
53
|
const lines: string[] = [];
|
|
68
54
|
lines.push("# OmniDev Provider Configuration");
|
package/src/index.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* @omnidev-ai/core - Core functionality for OmniDev
|
|
3
3
|
*
|
|
4
4
|
* This package contains shared types, utilities, and core logic
|
|
5
|
-
* used across the CLI and
|
|
5
|
+
* used across the CLI and capability tooling packages.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
// Re-export @stricli/core for capabilities to use
|
|
@@ -20,8 +20,6 @@ export * from "./capability";
|
|
|
20
20
|
|
|
21
21
|
// Export config functionality
|
|
22
22
|
export * from "./config";
|
|
23
|
-
// Export gitignore management
|
|
24
|
-
export * from "./gitignore/manager";
|
|
25
23
|
// Export MCP JSON management
|
|
26
24
|
export * from "./mcp-json";
|
|
27
25
|
// Export state management
|