@omnidev-ai/core 0.3.0 → 0.4.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 (64) hide show
  1. package/dist/index.d.ts +889 -0
  2. package/dist/index.js +2173 -0
  3. package/dist/test-utils/index.d.ts +142 -0
  4. package/dist/test-utils/index.js +261 -0
  5. package/package.json +16 -6
  6. package/src/capability/AGENTS.md +0 -58
  7. package/src/capability/commands.test.ts +0 -410
  8. package/src/capability/commands.ts +0 -72
  9. package/src/capability/docs.test.ts +0 -192
  10. package/src/capability/docs.ts +0 -48
  11. package/src/capability/index.ts +0 -20
  12. package/src/capability/loader.test.ts +0 -668
  13. package/src/capability/loader.ts +0 -431
  14. package/src/capability/registry.test.ts +0 -455
  15. package/src/capability/registry.ts +0 -55
  16. package/src/capability/rules.test.ts +0 -135
  17. package/src/capability/rules.ts +0 -135
  18. package/src/capability/skills.test.ts +0 -312
  19. package/src/capability/skills.ts +0 -58
  20. package/src/capability/sources.test.ts +0 -439
  21. package/src/capability/sources.ts +0 -998
  22. package/src/capability/subagents.test.ts +0 -474
  23. package/src/capability/subagents.ts +0 -105
  24. package/src/capability/wrapping-integration.test.ts +0 -412
  25. package/src/capability/yaml-parser.ts +0 -81
  26. package/src/config/AGENTS.md +0 -46
  27. package/src/config/capabilities.ts +0 -54
  28. package/src/config/env.test.ts +0 -270
  29. package/src/config/env.ts +0 -96
  30. package/src/config/index.ts +0 -6
  31. package/src/config/loader.test.ts +0 -198
  32. package/src/config/loader.ts +0 -207
  33. package/src/config/parser.test.ts +0 -256
  34. package/src/config/parser.ts +0 -55
  35. package/src/config/profiles.test.ts +0 -222
  36. package/src/config/profiles.ts +0 -75
  37. package/src/config/provider.test.ts +0 -66
  38. package/src/config/provider.ts +0 -55
  39. package/src/debug.ts +0 -20
  40. package/src/index.test.ts +0 -26
  41. package/src/index.ts +0 -37
  42. package/src/mcp-json/index.ts +0 -1
  43. package/src/mcp-json/manager.test.ts +0 -310
  44. package/src/mcp-json/manager.ts +0 -106
  45. package/src/state/active-profile.test.ts +0 -117
  46. package/src/state/active-profile.ts +0 -41
  47. package/src/state/index.ts +0 -3
  48. package/src/state/manifest.test.ts +0 -411
  49. package/src/state/manifest.ts +0 -137
  50. package/src/state/providers.test.ts +0 -125
  51. package/src/state/providers.ts +0 -69
  52. package/src/sync.ts +0 -288
  53. package/src/templates/agents.test.ts +0 -23
  54. package/src/templates/agents.ts +0 -14
  55. package/src/templates/claude.test.ts +0 -48
  56. package/src/templates/claude.ts +0 -57
  57. package/src/test-utils/helpers.test.ts +0 -214
  58. package/src/test-utils/helpers.ts +0 -284
  59. package/src/test-utils/index.ts +0 -34
  60. package/src/test-utils/mocks.test.ts +0 -83
  61. package/src/test-utils/mocks.ts +0 -101
  62. package/src/types/capability-export.ts +0 -157
  63. package/src/types/index.test.ts +0 -28
  64. package/src/types/index.ts +0 -314
@@ -1,207 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import type { OmniConfig } from "../types";
3
- import { parseOmniConfig } from "./parser";
4
-
5
- const CONFIG_PATH = "omni.toml";
6
- const LOCAL_CONFIG = "omni.local.toml";
7
-
8
- /**
9
- * Deep merge two config objects, with override taking precedence
10
- * @param base - The base config object
11
- * @param override - The override config object
12
- * @returns Merged config with override values taking precedence
13
- */
14
- function mergeConfigs(base: OmniConfig, override: OmniConfig): OmniConfig {
15
- const merged: OmniConfig = { ...base, ...override };
16
-
17
- // Deep merge env
18
- merged.env = { ...base.env, ...override.env };
19
-
20
- // Deep merge profiles
21
- merged.profiles = { ...base.profiles };
22
- for (const [name, profile] of Object.entries(override.profiles || {})) {
23
- merged.profiles[name] = {
24
- ...(base.profiles?.[name] || {}),
25
- ...profile,
26
- };
27
- }
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
-
34
- return merged;
35
- }
36
-
37
- /**
38
- * Load and merge config and local configuration files
39
- * @returns Merged OmniConfig object
40
- *
41
- * Reads omni.toml (main config) and omni.local.toml (local overrides).
42
- * Local config takes precedence over main config. Missing files are treated as empty configs.
43
- */
44
- export async function loadConfig(): Promise<OmniConfig> {
45
- let baseConfig: OmniConfig = {};
46
- let localConfig: OmniConfig = {};
47
-
48
- if (existsSync(CONFIG_PATH)) {
49
- const content = await Bun.file(CONFIG_PATH).text();
50
- baseConfig = parseOmniConfig(content);
51
- }
52
-
53
- if (existsSync(LOCAL_CONFIG)) {
54
- const content = await Bun.file(LOCAL_CONFIG).text();
55
- localConfig = parseOmniConfig(content);
56
- }
57
-
58
- return mergeConfigs(baseConfig, localConfig);
59
- }
60
-
61
- /**
62
- * Write config to omni.toml at project root
63
- * @param config - The config object to write
64
- */
65
- export async function writeConfig(config: OmniConfig): Promise<void> {
66
- const content = generateConfigToml(config);
67
- await Bun.write(CONFIG_PATH, content);
68
- }
69
-
70
- /**
71
- * Generate TOML content for OmniConfig
72
- * @param config - The config object
73
- * @returns TOML string
74
- */
75
- function generateConfigToml(config: OmniConfig): string {
76
- const lines: string[] = [];
77
-
78
- lines.push("# =============================================================================");
79
- lines.push("# OmniDev Configuration");
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>");
93
- lines.push("");
94
-
95
- // Project name
96
- if (config.project) {
97
- lines.push(`project = "${config.project}"`);
98
- lines.push("");
99
- }
100
-
101
- // Note: active_profile is stored in .omni/state/active-profile, not in config.toml
102
- // We still read it from config.toml for backwards compatibility, but don't write it here
103
-
104
- // Providers
105
- if (config.providers?.enabled && config.providers.enabled.length > 0) {
106
- lines.push("# AI providers to enable (claude, codex, or both)");
107
- lines.push("[providers]");
108
- lines.push(`enabled = [${config.providers.enabled.map((p) => `"${p}"`).join(", ")}]`);
109
- lines.push("");
110
- }
111
-
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("#");
120
- if (config.env && Object.keys(config.env).length > 0) {
121
- lines.push("[env]");
122
- for (const [key, value] of Object.entries(config.env)) {
123
- lines.push(`${key} = "${value}"`);
124
- }
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}"');
131
- }
132
- lines.push("");
133
-
134
- // Capability sources (commented examples)
135
- lines.push("# =============================================================================");
136
- lines.push("# Capability Sources");
137
- lines.push("# =============================================================================");
138
- lines.push("# Fetch capabilities from Git repositories. On sync, these are");
139
- lines.push("# cloned/updated and made available to your profiles.");
140
- lines.push("#");
141
- lines.push("# [capabilities.sources]");
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
- );
161
- 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');
166
- 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"]');
184
- lines.push("");
185
-
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("");
193
- if (config.profiles && Object.keys(config.profiles).length > 0) {
194
- for (const [name, profile] of Object.entries(config.profiles)) {
195
- lines.push(`[profiles.${name}]`);
196
- const capabilities = profile.capabilities ?? [];
197
- if (capabilities.length > 0) {
198
- lines.push(`capabilities = [${capabilities.map((id) => `"${id}"`).join(", ")}]`);
199
- } else {
200
- lines.push("capabilities = []");
201
- }
202
- lines.push("");
203
- }
204
- }
205
-
206
- return lines.join("\n");
207
- }
@@ -1,256 +0,0 @@
1
- import { describe, expect, test } from "bun:test";
2
- import { parseCapabilityConfig, parseOmniConfig } from "./parser";
3
-
4
- describe("parseOmniConfig", () => {
5
- test("parses valid TOML with all fields", () => {
6
- const toml = `
7
- project = "my-project"
8
- default_profile = "dev"
9
-
10
- [capabilities]
11
- enable = ["tasks", "git"]
12
- disable = ["docker"]
13
-
14
- [env]
15
- API_URL = "https://api.example.com"
16
-
17
- [profiles.dev]
18
- enable = ["debug"]
19
- disable = []
20
-
21
- [profiles.prod]
22
- enable = []
23
- disable = ["debug"]
24
- `;
25
-
26
- const config = parseOmniConfig(toml);
27
-
28
- expect(config.project).toBe("my-project");
29
- expect(config.default_profile).toBe("dev");
30
- expect(config.capabilities?.enable).toEqual(["tasks", "git"]);
31
- expect(config.capabilities?.disable).toEqual(["docker"]);
32
- expect(config.env?.API_URL).toBe("https://api.example.com");
33
- expect(config.profiles?.dev?.enable).toEqual(["debug"]);
34
- expect(config.profiles?.prod?.disable).toEqual(["debug"]);
35
- });
36
-
37
- test("parses minimal TOML", () => {
38
- const toml = `
39
- project = "minimal"
40
- `;
41
-
42
- const config = parseOmniConfig(toml);
43
-
44
- expect(config.project).toBe("minimal");
45
- expect(config.capabilities).toBeUndefined();
46
- expect(config.profiles).toBeUndefined();
47
- });
48
-
49
- test("parses empty TOML", () => {
50
- const config = parseOmniConfig("");
51
-
52
- expect(config).toEqual({});
53
- });
54
-
55
- test("parses TOML with arrays", () => {
56
- const toml = `
57
- [capabilities]
58
- enable = ["cap1", "cap2", "cap3"]
59
- `;
60
-
61
- const config = parseOmniConfig(toml);
62
-
63
- expect(config.capabilities?.enable).toEqual(["cap1", "cap2", "cap3"]);
64
- });
65
-
66
- test("parses TOML with nested tables", () => {
67
- const toml = `
68
- [profiles.dev]
69
- enable = ["debug"]
70
-
71
- [profiles.prod]
72
- disable = ["debug"]
73
- `;
74
-
75
- const config = parseOmniConfig(toml);
76
-
77
- expect(config.profiles?.dev?.enable).toEqual(["debug"]);
78
- expect(config.profiles?.prod?.disable).toEqual(["debug"]);
79
- });
80
-
81
- test("throws error for invalid TOML syntax", () => {
82
- const toml = `
83
- project = "test
84
- [invalid
85
- `;
86
-
87
- expect(() => parseOmniConfig(toml)).toThrow(/Invalid TOML in config:/);
88
- });
89
-
90
- test("throws error for duplicate keys", () => {
91
- const toml = `
92
- project = "test"
93
- project = "duplicate"
94
- `;
95
-
96
- expect(() => parseOmniConfig(toml)).toThrow(/Invalid TOML in config:/);
97
- });
98
-
99
- test("handles boolean values", () => {
100
- const toml = `
101
- [capabilities]
102
- debug = true
103
- production = false
104
- `;
105
-
106
- const config = parseOmniConfig(toml);
107
-
108
- expect((config.capabilities as Record<string, unknown>)?.debug).toBe(true);
109
- expect((config.capabilities as Record<string, unknown>)?.production).toBe(false);
110
- });
111
-
112
- test("handles numeric values", () => {
113
- const toml = `
114
- timeout = 30
115
- max_retries = 5
116
- `;
117
-
118
- const config = parseOmniConfig(toml);
119
-
120
- expect((config as Record<string, unknown>).timeout).toBe(30);
121
- expect((config as Record<string, unknown>).max_retries).toBe(5);
122
- });
123
- });
124
-
125
- describe("parseCapabilityConfig", () => {
126
- test("parses valid capability.toml with all required fields", () => {
127
- const toml = `
128
- [capability]
129
- id = "tasks"
130
- name = "Task Management"
131
- version = "1.0.0"
132
- description = "Manage tasks and workflows"
133
- `;
134
-
135
- const config = parseCapabilityConfig(toml);
136
-
137
- expect(config.capability.id).toBe("tasks");
138
- expect(config.capability.name).toBe("Task Management");
139
- expect(config.capability.version).toBe("1.0.0");
140
- expect(config.capability.description).toBe("Manage tasks and workflows");
141
- });
142
-
143
- test("parses capability with exports", () => {
144
- const toml = `
145
- [capability]
146
- id = "tasks"
147
- name = "Task Management"
148
- version = "1.0.0"
149
- description = "Manage tasks"
150
-
151
- [exports]
152
- module = "index.ts"
153
- `;
154
-
155
- const config = parseCapabilityConfig(toml);
156
-
157
- expect(config.exports?.module).toBe("index.ts");
158
- });
159
-
160
- test("parses capability with env declarations", () => {
161
- const toml = `
162
- [capability]
163
- id = "api"
164
- name = "API Client"
165
- version = "1.0.0"
166
- description = "API access"
167
-
168
- [env.API_KEY]
169
- required = true
170
- secret = true
171
-
172
- [env.API_URL]
173
- required = false
174
- default = "https://api.example.com"
175
- `;
176
-
177
- const config = parseCapabilityConfig(toml);
178
-
179
- expect(config.env?.API_KEY).toEqual({ required: true, secret: true });
180
- expect(config.env?.API_URL).toEqual({
181
- required: false,
182
- default: "https://api.example.com",
183
- });
184
- });
185
-
186
- test("throws error when capability.id is missing", () => {
187
- const toml = `
188
- [capability]
189
- name = "Test"
190
- version = "1.0.0"
191
- `;
192
-
193
- expect(() => parseCapabilityConfig(toml)).toThrow(
194
- /capability.id is required in capability.toml/,
195
- );
196
- });
197
-
198
- test("throws error when capability.name is missing", () => {
199
- const toml = `
200
- [capability]
201
- id = "test"
202
- version = "1.0.0"
203
- `;
204
-
205
- expect(() => parseCapabilityConfig(toml)).toThrow(
206
- /capability.name is required in capability.toml/,
207
- );
208
- });
209
-
210
- test("throws error when capability.version is missing", () => {
211
- const toml = `
212
- [capability]
213
- id = "test"
214
- name = "Test"
215
- `;
216
-
217
- expect(() => parseCapabilityConfig(toml)).toThrow(
218
- /capability.version is required in capability.toml/,
219
- );
220
- });
221
-
222
- test("throws error when capability table is missing", () => {
223
- const toml = `
224
- project = "test"
225
- `;
226
-
227
- expect(() => parseCapabilityConfig(toml)).toThrow(
228
- /capability.id is required in capability.toml/,
229
- );
230
- });
231
-
232
- test("throws error for invalid TOML syntax", () => {
233
- const toml = `
234
- [capability
235
- id = "test"
236
- `;
237
-
238
- expect(() => parseCapabilityConfig(toml)).toThrow(/Invalid capability.toml:/);
239
- });
240
-
241
- test("handles empty env declarations", () => {
242
- const toml = `
243
- [capability]
244
- id = "test"
245
- name = "Test"
246
- version = "1.0.0"
247
- description = "Test"
248
-
249
- [env.SIMPLE_VAR]
250
- `;
251
-
252
- const config = parseCapabilityConfig(toml);
253
-
254
- expect(config.env?.SIMPLE_VAR).toEqual({});
255
- });
256
- });
@@ -1,55 +0,0 @@
1
- import { parse } from "smol-toml";
2
- import type { CapabilityConfig, OmniConfig } from "../types";
3
-
4
- /**
5
- * Parse a TOML string into an OmniConfig object
6
- * @param tomlContent - The TOML content to parse
7
- * @returns Parsed OmniConfig object
8
- * @throws Error if TOML is invalid
9
- */
10
- export function parseOmniConfig(tomlContent: string): OmniConfig {
11
- try {
12
- return parse(tomlContent) as OmniConfig;
13
- } catch (error) {
14
- const message = error instanceof Error ? error.message : String(error);
15
- throw new Error(`Invalid TOML in config: ${message}`);
16
- }
17
- }
18
-
19
- /**
20
- * Validate that parsed TOML has required capability fields
21
- */
22
- function validateCapabilityConfig(parsed: Record<string, unknown>): void {
23
- const cap = parsed["capability"];
24
- if (typeof cap !== "object" || cap === null) {
25
- throw new Error("capability.id is required in capability.toml");
26
- }
27
- const capability = cap as Record<string, unknown>;
28
- if (typeof capability["id"] !== "string") {
29
- throw new Error("capability.id is required in capability.toml");
30
- }
31
- if (typeof capability["name"] !== "string") {
32
- throw new Error("capability.name is required in capability.toml");
33
- }
34
- if (typeof capability["version"] !== "string") {
35
- throw new Error("capability.version is required in capability.toml");
36
- }
37
- }
38
-
39
- /**
40
- * Parse a TOML string into a CapabilityConfig object
41
- * @param tomlContent - The TOML content to parse
42
- * @returns Parsed CapabilityConfig object
43
- * @throws Error if TOML is invalid or required fields are missing
44
- */
45
- export function parseCapabilityConfig(tomlContent: string): CapabilityConfig {
46
- try {
47
- const parsed = parse(tomlContent) as Record<string, unknown>;
48
- validateCapabilityConfig(parsed);
49
- // After validation, we know the structure matches CapabilityConfig
50
- return parsed as unknown as CapabilityConfig;
51
- } catch (error) {
52
- const message = error instanceof Error ? error.message : String(error);
53
- throw new Error(`Invalid capability.toml: ${message}`);
54
- }
55
- }