@omnidev-ai/core 0.4.0 → 0.5.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 (41) hide show
  1. package/dist/index.d.ts +600 -664
  2. package/dist/index.js +1841 -1915
  3. package/dist/shared/chunk-1dqs11h6.js +20 -0
  4. package/dist/test-utils/index.d.ts +97 -101
  5. package/dist/test-utils/index.js +203 -234
  6. package/package.json +5 -3
  7. package/src/capability/AGENTS.md +58 -0
  8. package/src/capability/commands.ts +72 -0
  9. package/src/capability/docs.ts +48 -0
  10. package/src/capability/index.ts +20 -0
  11. package/src/capability/loader.ts +431 -0
  12. package/src/capability/registry.ts +55 -0
  13. package/src/capability/rules.ts +135 -0
  14. package/src/capability/skills.ts +58 -0
  15. package/src/capability/sources.ts +998 -0
  16. package/src/capability/subagents.ts +105 -0
  17. package/src/capability/yaml-parser.ts +81 -0
  18. package/src/config/AGENTS.md +46 -0
  19. package/src/config/capabilities.ts +54 -0
  20. package/src/config/env.ts +96 -0
  21. package/src/config/index.ts +6 -0
  22. package/src/config/loader.ts +207 -0
  23. package/src/config/parser.ts +55 -0
  24. package/src/config/profiles.ts +75 -0
  25. package/src/config/provider.ts +55 -0
  26. package/src/debug.ts +20 -0
  27. package/src/index.ts +37 -0
  28. package/src/mcp-json/index.ts +1 -0
  29. package/src/mcp-json/manager.ts +106 -0
  30. package/src/state/active-profile.ts +41 -0
  31. package/src/state/index.ts +3 -0
  32. package/src/state/manifest.ts +137 -0
  33. package/src/state/providers.ts +69 -0
  34. package/src/sync.ts +288 -0
  35. package/src/templates/agents.ts +14 -0
  36. package/src/templates/claude.ts +57 -0
  37. package/src/test-utils/helpers.ts +289 -0
  38. package/src/test-utils/index.ts +34 -0
  39. package/src/test-utils/mocks.ts +101 -0
  40. package/src/types/capability-export.ts +157 -0
  41. package/src/types/index.ts +314 -0
@@ -0,0 +1,101 @@
1
+ /**
2
+ * Mock factories for creating test data
3
+ */
4
+
5
+ export interface MockCapability {
6
+ id: string;
7
+ name: string;
8
+ version: string;
9
+ enabled?: boolean;
10
+ metadata?: Record<string, unknown>;
11
+ }
12
+
13
+ export interface MockConfig {
14
+ project: string;
15
+ capabilities: {
16
+ enable: string[];
17
+ disable?: string[];
18
+ };
19
+ profiles?: Record<string, unknown>;
20
+ env?: Record<string, string>;
21
+ }
22
+
23
+ export interface MockSkill {
24
+ id: string;
25
+ name: string;
26
+ description: string;
27
+ instructions: string;
28
+ triggers?: string[];
29
+ }
30
+
31
+ export interface MockRule {
32
+ id: string;
33
+ name: string;
34
+ content: string;
35
+ priority?: number;
36
+ }
37
+
38
+ /**
39
+ * Creates a mock capability with default values
40
+ * @param overrides - Partial capability object to override defaults
41
+ * @returns Mock capability object
42
+ */
43
+ export function createMockCapability(overrides: Partial<MockCapability> = {}): MockCapability {
44
+ return {
45
+ id: "test-capability",
46
+ name: "Test Capability",
47
+ version: "1.0.0",
48
+ enabled: true,
49
+ metadata: {},
50
+ ...overrides,
51
+ };
52
+ }
53
+
54
+ /**
55
+ * Creates a mock config with default values
56
+ * @param overrides - Partial config object to override defaults
57
+ * @returns Mock config object
58
+ */
59
+ export function createMockConfig(overrides: Partial<MockConfig> = {}): MockConfig {
60
+ return {
61
+ project: "test-project",
62
+ capabilities: {
63
+ enable: [],
64
+ disable: [],
65
+ },
66
+ profiles: {},
67
+ env: {},
68
+ ...overrides,
69
+ };
70
+ }
71
+
72
+ /**
73
+ * Creates a mock skill with default values
74
+ * @param overrides - Partial skill object to override defaults
75
+ * @returns Mock skill object
76
+ */
77
+ export function createMockSkill(overrides: Partial<MockSkill> = {}): MockSkill {
78
+ return {
79
+ id: "test-skill",
80
+ name: "Test Skill",
81
+ description: "A test skill for unit testing",
82
+ instructions: "Test instructions",
83
+ triggers: [],
84
+ ...overrides,
85
+ };
86
+ }
87
+
88
+ /**
89
+ * Creates a mock rule with default values
90
+ * @param overrides - Partial rule object to override defaults
91
+ * @returns Mock rule object
92
+ */
93
+ export function createMockRule(overrides: Partial<MockRule> = {}): MockRule {
94
+ return {
95
+ id: "test-rule",
96
+ name: "Test Rule",
97
+ content: "# Test Rule\n\nTest rule content",
98
+ priority: 1,
99
+ ...overrides,
100
+ };
101
+ }
@@ -0,0 +1,157 @@
1
+ /**
2
+ * Capability Export Types
3
+ *
4
+ * These types define the structure that capabilities use to export their features.
5
+ * Capabilities should import these types from @omnidev-ai/core and use them in their index.ts.
6
+ */
7
+
8
+ /**
9
+ * File content structure for programmatic file creation
10
+ */
11
+ export interface FileContent {
12
+ /** File name (relative path within capability) */
13
+ name: string;
14
+
15
+ /** File content */
16
+ content: string;
17
+ }
18
+
19
+ /**
20
+ * Documentation export structure
21
+ */
22
+ export interface DocExport {
23
+ /** Document title */
24
+ title: string;
25
+
26
+ /** Markdown content */
27
+ content: string;
28
+ }
29
+
30
+ /**
31
+ * Skill export structure
32
+ */
33
+ export interface SkillExport {
34
+ /** SKILL.md content (markdown with YAML frontmatter) */
35
+ skillMd: string;
36
+
37
+ /** Optional: Reference files to create (files the skill needs access to) */
38
+ references?: FileContent[];
39
+
40
+ /** Optional: Additional files to create (templates, examples, etc.) */
41
+ additionalFiles?: FileContent[];
42
+ }
43
+
44
+ /**
45
+ * Subagent export structure
46
+ *
47
+ * Defines a subagent that Claude can delegate tasks to.
48
+ * Uses YAML frontmatter in markdown format for configuration.
49
+ *
50
+ * @example
51
+ * ```typescript
52
+ * const codeReviewer: SubagentExport = {
53
+ * subagentMd: `---
54
+ * name: code-reviewer
55
+ * description: Reviews code for quality and best practices
56
+ * tools: Read, Glob, Grep
57
+ * model: sonnet
58
+ * ---
59
+ *
60
+ * You are a code reviewer. When invoked, analyze the code and provide
61
+ * specific, actionable feedback on quality, security, and best practices.`
62
+ * };
63
+ * ```
64
+ */
65
+ export interface SubagentExport {
66
+ /** SUBAGENT.md content (markdown with YAML frontmatter) */
67
+ subagentMd: string;
68
+ }
69
+
70
+ /**
71
+ * Slash command export structure
72
+ *
73
+ * Defines a slash command that can be invoked in Claude Code.
74
+ * Uses YAML frontmatter in markdown format for configuration.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const fixIssue: CommandExport = {
79
+ * commandMd: `---
80
+ * name: fix-issue
81
+ * description: Fix a GitHub issue following coding standards
82
+ * allowed-tools: Bash(git add:*), Bash(git commit:*)
83
+ * ---
84
+ *
85
+ * Fix issue #$ARGUMENTS following our coding standards.
86
+ *
87
+ * 1. Read the issue details
88
+ * 2. Implement the fix
89
+ * 3. Write tests
90
+ * 4. Create a commit`
91
+ * };
92
+ * ```
93
+ */
94
+ export interface CommandExport {
95
+ /** COMMAND.md content (markdown with YAML frontmatter) */
96
+ commandMd: string;
97
+ }
98
+
99
+ /**
100
+ * Complete capability export structure
101
+ *
102
+ * Capabilities export this as their default export from index.ts.
103
+ * All content fields are OPTIONAL and PROGRAMMATIC.
104
+ * Capabilities can also provide content via static files in their directory.
105
+ * Both approaches are supported and will be merged during sync.
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * // Static files approach - just export CLI commands
110
+ * export default {
111
+ * cliCommands: { mycap: myRoutes },
112
+ * gitignore: ["mycap/"],
113
+ * sync
114
+ * } satisfies CapabilityExport;
115
+ * ```
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * // Programmatic approach - generate content dynamically
120
+ * export default {
121
+ * cliCommands: { mycap: myRoutes },
122
+ * docs: [{ title: "Guide", content: "# Guide\n..." }],
123
+ * rules: ["# Rule content..."],
124
+ * skills: [{ skillMd: "...", references: [...] }],
125
+ * gitignore: ["mycap/"],
126
+ * sync
127
+ * } satisfies CapabilityExport;
128
+ * ```
129
+ */
130
+ export interface CapabilityExport {
131
+ /** CLI commands provided by this capability */
132
+ cliCommands?: Record<string, unknown>; // stricli Command type
133
+
134
+ /** Documentation (programmatic - optional, can also use docs/ directory) */
135
+ docs?: DocExport[];
136
+
137
+ /** Rules (programmatic - optional, can also use rules/ directory) */
138
+ rules?: string[]; // Array of markdown content strings
139
+
140
+ /** Skills (programmatic - optional, can also use skills/ directory) */
141
+ skills?: SkillExport[];
142
+
143
+ /** Subagents (programmatic - optional, can also use subagents/ directory) */
144
+ subagents?: SubagentExport[];
145
+
146
+ /** Commands (programmatic - optional, can also use commands/ directory) */
147
+ commands?: CommandExport[];
148
+
149
+ /** Gitignore patterns */
150
+ gitignore?: string[];
151
+
152
+ /** Custom sync hook function */
153
+ sync?: () => Promise<void>;
154
+
155
+ /** Additional exports for extensibility */
156
+ [key: string]: unknown;
157
+ }
@@ -0,0 +1,314 @@
1
+ // Capability Export Types (for capability developers)
2
+ export * from "./capability-export.js";
3
+
4
+ // Capability Types
5
+ export interface CapabilityMetadata {
6
+ id: string;
7
+ name: string;
8
+ version: string;
9
+ description: string;
10
+ /** Optional author information */
11
+ author?: {
12
+ name?: string;
13
+ email?: string;
14
+ };
15
+ /** Optional metadata about the capability author and source */
16
+ metadata?: {
17
+ author?: string;
18
+ repository?: string;
19
+ license?: string;
20
+ /** True if this capability was auto-generated by wrapping a skills repo */
21
+ wrapped?: boolean;
22
+ /** For wrapped capabilities: the full commit hash */
23
+ commit?: string;
24
+ /** True if this capability was auto-generated from omni.toml [mcps] section */
25
+ generated_from_omni_toml?: boolean;
26
+ };
27
+ }
28
+
29
+ export interface CapabilityExports {
30
+ module?: string;
31
+ gitignore?: string[];
32
+ }
33
+
34
+ export interface EnvDeclaration {
35
+ required?: boolean;
36
+ secret?: boolean;
37
+ default?: string;
38
+ }
39
+
40
+ export interface SyncConfig {
41
+ on_sync?: string;
42
+ }
43
+
44
+ export interface CliConfig {
45
+ commands?: string[];
46
+ }
47
+
48
+ export interface CapabilityConfig {
49
+ capability: CapabilityMetadata;
50
+ exports?: CapabilityExports;
51
+ env?: Record<string, EnvDeclaration | Record<string, never>>;
52
+ mcp?: McpConfig;
53
+ sync?: SyncConfig;
54
+ cli?: CliConfig;
55
+ }
56
+
57
+ export type McpTransport = "stdio" | "sse" | "http";
58
+
59
+ export interface McpToolSchema {
60
+ name: string;
61
+ description: string;
62
+ inputSchema: Record<string, unknown>;
63
+ }
64
+
65
+ export interface McpConfig {
66
+ command: string;
67
+ args?: string[];
68
+ env?: Record<string, string>;
69
+ cwd?: string;
70
+ transport?: McpTransport;
71
+ tools?: McpToolSchema[];
72
+ }
73
+
74
+ // Content Types
75
+ export interface Skill {
76
+ name: string;
77
+ description: string;
78
+ instructions: string;
79
+ capabilityId: string;
80
+ }
81
+
82
+ export interface Rule {
83
+ name: string;
84
+ content: string;
85
+ capabilityId: string;
86
+ }
87
+
88
+ export interface Doc {
89
+ name: string;
90
+ content: string;
91
+ capabilityId: string;
92
+ }
93
+
94
+ export type SubagentModel = "sonnet" | "opus" | "haiku" | "inherit";
95
+ export type SubagentPermissionMode =
96
+ | "default"
97
+ | "acceptEdits"
98
+ | "dontAsk"
99
+ | "bypassPermissions"
100
+ | "plan";
101
+
102
+ export interface SubagentHookConfig {
103
+ matcher?: string;
104
+ hooks: {
105
+ type: "command";
106
+ command: string;
107
+ }[];
108
+ }
109
+
110
+ export interface SubagentHooks {
111
+ PreToolUse?: SubagentHookConfig[];
112
+ PostToolUse?: SubagentHookConfig[];
113
+ Stop?: SubagentHookConfig[];
114
+ }
115
+
116
+ export interface Subagent {
117
+ /** Unique identifier using lowercase letters and hyphens */
118
+ name: string;
119
+ /** When Claude should delegate to this subagent */
120
+ description: string;
121
+ /** System prompt that guides the subagent's behavior */
122
+ systemPrompt: string;
123
+ /** Tools the subagent can use (inherits all if omitted) */
124
+ tools?: string[];
125
+ /** Tools to deny (removed from inherited or specified list) */
126
+ disallowedTools?: string[];
127
+ /** Model to use: sonnet, opus, haiku, or inherit */
128
+ model?: SubagentModel;
129
+ /** Permission mode for the subagent */
130
+ permissionMode?: SubagentPermissionMode;
131
+ /** Skills to load into the subagent's context at startup */
132
+ skills?: string[];
133
+ /** Lifecycle hooks scoped to this subagent */
134
+ hooks?: SubagentHooks;
135
+ /** Capability that provides this subagent */
136
+ capabilityId: string;
137
+ }
138
+
139
+ export interface Command {
140
+ /** Command name (used as /command-name) */
141
+ name: string;
142
+ /** Brief description of what this command does */
143
+ description: string;
144
+ /** Optional allowed tools specification (e.g., "Bash(git add:*), Bash(git status:*)") */
145
+ allowedTools?: string;
146
+ /** Command prompt (markdown content with support for $ARGUMENTS, $1, $2, !`commands`, @files) */
147
+ prompt: string;
148
+ /** Capability that provides this command */
149
+ capabilityId: string;
150
+ }
151
+
152
+ // Capability Source Types
153
+ // Sources: local (manual), git (version via package.json)
154
+ export type CapabilitySourceType = "local" | "git";
155
+
156
+ /** Configuration for a Git-sourced capability */
157
+ export interface GitCapabilitySourceConfig {
158
+ /** Source URL or shorthand (e.g., "github:user/repo", "git@github.com:...") */
159
+ source: string;
160
+ /** Git ref to checkout: tag, branch, or commit hash */
161
+ ref?: string;
162
+ /** Subdirectory within the repo containing the capability */
163
+ path?: string;
164
+ }
165
+
166
+ /** Combined type for all capability source configurations */
167
+ export type CapabilitySourceConfig =
168
+ | string // shorthand: "github:user/repo"
169
+ | GitCapabilitySourceConfig;
170
+
171
+ /** Lock file entry for a capability (version tracking) */
172
+ export interface CapabilityLockEntry {
173
+ /** Original source reference */
174
+ source: string;
175
+ /** Version from capability.toml or package.json */
176
+ version: string;
177
+ /** For git sources: exact commit hash */
178
+ commit?: string;
179
+ /** Pinned ref if specified */
180
+ ref?: string;
181
+ /** Last update timestamp (ISO 8601) */
182
+ updated_at: string;
183
+ }
184
+
185
+ /** Lock file structure (omni.lock.toml at project root) */
186
+ export interface CapabilitiesLockFile {
187
+ capabilities: Record<string, CapabilityLockEntry>;
188
+ }
189
+
190
+ /** Capabilities configuration section in omni.toml */
191
+ export interface CapabilitiesConfig {
192
+ /** List of enabled capability IDs */
193
+ enable?: string[];
194
+ /** List of disabled capability IDs */
195
+ disable?: string[];
196
+ /** Capability sources: id -> source string or full config (git or file) */
197
+ sources?: Record<string, CapabilitySourceConfig>;
198
+ }
199
+
200
+ // Config Types
201
+ export interface ProfileConfig {
202
+ capabilities?: string[];
203
+ }
204
+
205
+ export interface OmniConfig {
206
+ project?: string;
207
+ active_profile?: string;
208
+ always_enabled_capabilities?: string[];
209
+ env?: Record<string, string>;
210
+ profiles?: Record<string, ProfileConfig>;
211
+ providers?: {
212
+ enabled?: Provider[];
213
+ };
214
+ /** Capabilities configuration (enable/disable, sources) */
215
+ capabilities?: CapabilitiesConfig;
216
+ /** MCP server definitions that auto-generate capabilities */
217
+ mcps?: Record<string, McpConfig>;
218
+ }
219
+
220
+ // Provider Types
221
+ export type Provider = "claude" | "codex" | "claude-code" | "cursor" | "opencode";
222
+
223
+ export interface ProviderConfig {
224
+ provider?: Provider;
225
+ providers?: Provider[];
226
+ }
227
+
228
+ export function getActiveProviders(config: ProviderConfig): Provider[] {
229
+ if (config.providers) return config.providers;
230
+ if (config.provider) return [config.provider];
231
+ return ["claude"]; // Default
232
+ }
233
+
234
+ /** Runtime info about where a capability came from */
235
+ export interface CapabilitySource {
236
+ type: CapabilitySourceType;
237
+ /** For git-sourced capabilities: the source URL/shorthand */
238
+ gitSource?: string;
239
+ /** For git-sourced capabilities: the pinned ref if any */
240
+ ref?: string;
241
+ /** For git-sourced capabilities: the current commit hash */
242
+ commit?: string;
243
+ /** Version from capability.toml or package.json */
244
+ version?: string;
245
+ }
246
+
247
+ // Loaded Capability
248
+ export interface LoadedCapability {
249
+ id: string;
250
+ path: string;
251
+ config: CapabilityConfig;
252
+ skills: Skill[];
253
+ rules: Rule[];
254
+ docs: Doc[];
255
+ subagents: Subagent[];
256
+ commands: Command[];
257
+ typeDefinitions?: string;
258
+ gitignore?: string[];
259
+ exports: Record<string, unknown>;
260
+ /** Where this capability comes from */
261
+ source?: CapabilitySource;
262
+ }
263
+
264
+ // Adapter Types
265
+ export type ProviderId = Provider | (string & {});
266
+
267
+ export interface SyncBundle {
268
+ capabilities: LoadedCapability[];
269
+ skills: Skill[];
270
+ rules: Rule[];
271
+ docs: Doc[];
272
+ commands: Command[];
273
+ subagents: Subagent[];
274
+ instructionsPath: string; // usually .omni/instructions.md
275
+ instructionsContent: string; // generated by core
276
+ }
277
+
278
+ export interface ProviderContext {
279
+ projectRoot: string;
280
+ config: OmniConfig;
281
+ activeProfile?: string;
282
+ }
283
+
284
+ export interface ProviderInitResult {
285
+ // What did the init action do?
286
+ filesCreated?: string[];
287
+ message?: string;
288
+ }
289
+
290
+ export interface ProviderSyncResult {
291
+ // What did the sync action do?
292
+ filesWritten: string[];
293
+ filesDeleted: string[];
294
+ }
295
+
296
+ export interface ProviderManifest {
297
+ // State for cleanup
298
+ files: string[];
299
+ lastSync: string;
300
+ }
301
+
302
+ export interface ProviderAdapter {
303
+ id: ProviderId;
304
+ displayName: string;
305
+
306
+ // Optional: used by `omnidev init`
307
+ init?(ctx: ProviderContext): Promise<ProviderInitResult>;
308
+
309
+ // Main sync entrypoint
310
+ sync(bundle: SyncBundle, ctx: ProviderContext): Promise<ProviderSyncResult>;
311
+
312
+ // Optional cleanup hook (when provider removed or resources stale)
313
+ cleanup?(manifest: ProviderManifest, ctx: ProviderContext): Promise<void>;
314
+ }