@omnidev-ai/core 0.9.0 → 0.10.1

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.
@@ -0,0 +1,167 @@
1
+ /**
2
+ * Templates for bootstrapping new capabilities.
3
+ */
4
+
5
+ export interface CapabilityTemplateOptions {
6
+ id: string;
7
+ name: string;
8
+ description?: string;
9
+ }
10
+
11
+ /**
12
+ * Generate a capability.toml file for a new capability.
13
+ */
14
+ export function generateCapabilityToml(options: CapabilityTemplateOptions): string {
15
+ const description = options.description || "TODO: Add a description for your capability";
16
+ return `[capability]
17
+ id = "${options.id}"
18
+ name = "${options.name}"
19
+ version = "0.1.0"
20
+ description = "${description}"
21
+
22
+ # Optional author information
23
+ # [capability.author]
24
+ # name = "Your Name"
25
+ # email = "you@example.com"
26
+
27
+ # Optional metadata
28
+ # [capability.metadata]
29
+ # repository = "https://github.com/user/repo"
30
+ # license = "MIT"
31
+ `;
32
+ }
33
+
34
+ /**
35
+ * Generate a SKILL.md template file.
36
+ */
37
+ export function generateSkillTemplate(skillName: string): string {
38
+ return `---
39
+ name: ${skillName}
40
+ description: TODO: Add a description for this skill
41
+ ---
42
+
43
+ ## What I do
44
+
45
+ <!-- Describe what this skill helps the AI agent accomplish -->
46
+ - TODO: List the main capabilities of this skill
47
+
48
+ ## When to use me
49
+
50
+ <!-- Describe scenarios when this skill should be invoked -->
51
+ Use this skill when you need to:
52
+ - TODO: Add trigger conditions
53
+
54
+ ## Implementation
55
+
56
+ <!-- Add detailed instructions for the AI agent -->
57
+ ### Steps
58
+
59
+ 1. TODO: Add implementation steps
60
+ 2. Validate inputs and outputs
61
+ 3. Report results to the user
62
+
63
+ ## Examples
64
+
65
+ <!-- Optional: Add examples of how this skill should be used -->
66
+ \`\`\`
67
+ TODO: Add example usage
68
+ \`\`\`
69
+ `;
70
+ }
71
+
72
+ /**
73
+ * Generate a rule markdown template file.
74
+ */
75
+ export function generateRuleTemplate(ruleName: string): string {
76
+ return `# ${formatDisplayName(ruleName)}
77
+
78
+ <!-- Rules are guidelines that the AI agent should follow when working in this project -->
79
+
80
+ ## Overview
81
+
82
+ TODO: Describe what this rule enforces or guides.
83
+
84
+ ## Guidelines
85
+
86
+ - TODO: Add specific guidelines the AI should follow
87
+ - Be specific and actionable
88
+ - Include examples where helpful
89
+
90
+ ## Examples
91
+
92
+ ### Good
93
+
94
+ \`\`\`
95
+ TODO: Add example of correct behavior
96
+ \`\`\`
97
+
98
+ ### Bad
99
+
100
+ \`\`\`
101
+ TODO: Add example of incorrect behavior
102
+ \`\`\`
103
+ `;
104
+ }
105
+
106
+ /**
107
+ * Generate a hooks.toml template file.
108
+ */
109
+ export function generateHooksTemplate(): string {
110
+ return `# Hook configuration for this capability
111
+ # See: https://omnidev.dev/docs/advanced/hooks
112
+
113
+ # Example: Validate bash commands before execution
114
+ # [[PreToolUse]]
115
+ # matcher = "Bash"
116
+ # [[PreToolUse.hooks]]
117
+ # type = "command"
118
+ # command = "\${OMNIDEV_CAPABILITY_ROOT}/hooks/validate-bash.sh"
119
+ # timeout = 30
120
+
121
+ # Example: Run linter after file edits
122
+ # [[PostToolUse]]
123
+ # matcher = "Write|Edit"
124
+ # [[PostToolUse.hooks]]
125
+ # type = "command"
126
+ # command = "\${OMNIDEV_CAPABILITY_ROOT}/hooks/run-linter.sh"
127
+
128
+ # Example: Load context at session start
129
+ # [[SessionStart]]
130
+ # matcher = "startup|resume"
131
+ # [[SessionStart.hooks]]
132
+ # type = "command"
133
+ # command = "\${OMNIDEV_CAPABILITY_ROOT}/hooks/load-context.sh"
134
+ `;
135
+ }
136
+
137
+ /**
138
+ * Generate a sample hook script.
139
+ */
140
+ export function generateHookScript(): string {
141
+ return `#!/bin/bash
142
+ # Sample hook script
143
+ # This script receives JSON input via stdin
144
+
145
+ # Read JSON input from stdin
146
+ INPUT=$(cat)
147
+
148
+ # Example: Extract tool information
149
+ # TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name')
150
+ # COMMAND=$(echo "$INPUT" | jq -r '.tool_input.command // empty')
151
+
152
+ # Add your validation logic here
153
+ # Exit 0 to allow, exit 2 to block
154
+
155
+ exit 0
156
+ `;
157
+ }
158
+
159
+ /**
160
+ * Convert kebab-case to Title Case for display.
161
+ */
162
+ function formatDisplayName(kebabCase: string): string {
163
+ return kebabCase
164
+ .split("-")
165
+ .map((word) => word.charAt(0).toUpperCase() + word.slice(1))
166
+ .join(" ");
167
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Template for CLAUDE.md (Claude provider)
3
- * Creates a minimal file with reference to OmniDev instructions
3
+ * Creates a minimal file - actual content is generated during sync from OMNI.md + instructions
4
4
  */
5
5
  export function generateClaudeTemplate(): string {
6
6
  return `# Project Instructions
@@ -9,49 +9,6 @@ export function generateClaudeTemplate(): string {
9
9
 
10
10
  ## OmniDev
11
11
 
12
- @import .omni/instructions.md
13
- `;
14
- }
15
-
16
- /**
17
- * Template for .omni/instructions.md
18
- * Contains OmniDev-specific instructions and capability rules
19
- */
20
- export function generateInstructionsTemplate(): string {
21
- return `# OmniDev Instructions
22
-
23
- ## Project Description
24
- <!-- TODO: Add 2-3 sentences describing your project -->
25
- [Describe what this project does and its main purpose]
26
-
27
- ## How OmniDev Works
28
-
29
- OmniDev manages capability content for your project. Capabilities can provide:
30
-
31
- - Skills (for agent workflows)
32
- - Rules (for guardrails and conventions)
33
- - Docs (reference material)
34
- - Commands and subagents (optional)
35
-
36
- Enable capabilities with:
37
-
38
- \`\`\`
39
- omnidev capability enable <capability-id>
40
- \`\`\`
41
-
42
- OmniDev will automatically sync enabled capabilities into your workspace. If you want to force a refresh:
43
-
44
- \`\`\`
45
- omnidev sync
46
- \`\`\`
47
-
48
- <!-- BEGIN OMNIDEV GENERATED CONTENT - DO NOT EDIT BELOW THIS LINE -->
49
- <!-- This section is automatically updated by 'omnidev agents sync' -->
50
-
51
- ## Capabilities
52
-
53
- No capabilities enabled yet. Run \`omnidev capability enable <name>\` to enable capabilities.
54
-
55
- <!-- END OMNIDEV GENERATED CONTENT -->
12
+ <!-- This section is populated during sync with capability rules and docs -->
56
13
  `;
57
14
  }
@@ -48,12 +48,6 @@ export interface CapabilityExports {
48
48
  gitignore?: string[];
49
49
  }
50
50
 
51
- export interface EnvDeclaration {
52
- required?: boolean;
53
- secret?: boolean;
54
- default?: string;
55
- }
56
-
57
51
  export interface SyncConfig {
58
52
  on_sync?: string;
59
53
  }
@@ -65,7 +59,6 @@ export interface CliConfig {
65
59
  export interface CapabilityConfig {
66
60
  capability: CapabilityMetadata;
67
61
  exports?: CapabilityExports;
68
- env?: Record<string, EnvDeclaration | Record<string, never>>;
69
62
  mcp?: McpConfig;
70
63
  sync?: SyncConfig;
71
64
  cli?: CliConfig;
@@ -84,7 +77,7 @@ export interface McpToolSchema {
84
77
  *
85
78
  * - **stdio**: Local process using stdin/stdout (default)
86
79
  * - Requires: command
87
- * - Optional: args, env, cwd
80
+ * - Optional: args, cwd
88
81
  *
89
82
  * - **http**: Remote HTTP server (recommended for remote servers)
90
83
  * - Requires: url
@@ -205,10 +198,29 @@ export interface GitCapabilitySourceConfig {
205
198
  path?: string;
206
199
  }
207
200
 
201
+ /** Configuration for a local file-sourced capability */
202
+ export interface FileCapabilitySourceConfig {
203
+ /** Source path with file:// prefix (e.g., "file://./capabilities/my-cap") */
204
+ source: string;
205
+ }
206
+
208
207
  /** Combined type for all capability source configurations */
209
208
  export type CapabilitySourceConfig =
210
- | string // shorthand: "github:user/repo"
211
- | GitCapabilitySourceConfig;
209
+ | string // shorthand: "github:user/repo" or "file://./path"
210
+ | GitCapabilitySourceConfig
211
+ | FileCapabilitySourceConfig;
212
+
213
+ /**
214
+ * Type guard to check if a source config is a FileCapabilitySourceConfig
215
+ */
216
+ export function isFileSourceConfig(
217
+ config: CapabilitySourceConfig,
218
+ ): config is FileCapabilitySourceConfig {
219
+ if (typeof config === "string") {
220
+ return config.startsWith("file://");
221
+ }
222
+ return config.source.startsWith("file://");
223
+ }
212
224
 
213
225
  /** Lock file entry for a capability (version tracking) */
214
226
  export interface CapabilityLockEntry {
@@ -250,7 +262,6 @@ export interface OmniConfig {
250
262
  project?: string;
251
263
  active_profile?: string;
252
264
  always_enabled_capabilities?: string[];
253
- env?: Record<string, string>;
254
265
  profiles?: Record<string, ProfileConfig>;
255
266
  providers?: {
256
267
  enabled?: Provider[];
@@ -319,8 +330,8 @@ export interface SyncBundle {
319
330
  subagents: Subagent[];
320
331
  /** Merged hooks from all capabilities */
321
332
  hooks?: HooksConfig;
322
- instructionsPath: string; // usually .omni/instructions.md
323
- instructionsContent: string; // generated by core
333
+ /** Generated instructions content from rules and docs, embedded directly into provider files */
334
+ instructionsContent: string;
324
335
  }
325
336
 
326
337
  export interface ProviderContext {
package/src/config/env.ts DELETED
@@ -1,97 +0,0 @@
1
- import { existsSync } from "node:fs";
2
- import { readFile } from "node:fs/promises";
3
- import type { EnvDeclaration } from "../types";
4
-
5
- const ENV_FILE = ".omni/.env";
6
-
7
- /**
8
- * Load environment variables from .omni/.env file and merge with process.env.
9
- * Process environment variables take precedence over file values.
10
- *
11
- * @returns Merged environment variables
12
- */
13
- export async function loadEnvironment(): Promise<Record<string, string>> {
14
- const env: Record<string, string> = {};
15
-
16
- // Load from .omni/.env
17
- if (existsSync(ENV_FILE)) {
18
- const content = await readFile(ENV_FILE, "utf-8");
19
- for (const line of content.split("\n")) {
20
- const trimmed = line.trim();
21
- // Skip empty lines and comments
22
- if (trimmed && !trimmed.startsWith("#")) {
23
- const eqIndex = trimmed.indexOf("=");
24
- if (eqIndex > 0) {
25
- const key = trimmed.slice(0, eqIndex).trim();
26
- const value = trimmed.slice(eqIndex + 1).trim();
27
- // Remove quotes if present
28
- const unquotedValue =
29
- (value.startsWith('"') && value.endsWith('"')) ||
30
- (value.startsWith("'") && value.endsWith("'"))
31
- ? value.slice(1, -1)
32
- : value;
33
- env[key] = unquotedValue;
34
- }
35
- }
36
- }
37
- }
38
-
39
- // Process env takes precedence - filter out undefined values
40
- const processEnv: Record<string, string> = {};
41
- for (const [key, value] of Object.entries(process.env)) {
42
- if (value !== undefined) {
43
- processEnv[key] = value;
44
- }
45
- }
46
-
47
- return { ...env, ...processEnv };
48
- }
49
-
50
- /**
51
- * Validate that all required environment variables are present.
52
- * Checks declarations from capability config and throws descriptive errors for missing vars.
53
- *
54
- * @param declarations - Environment variable declarations from capability.toml
55
- * @param env - Loaded environment variables
56
- * @param capabilityId - ID of the capability being validated
57
- * @throws Error if required environment variables are missing
58
- */
59
- export function validateEnv(
60
- declarations: Record<string, EnvDeclaration | Record<string, never>>,
61
- env: Record<string, string | undefined>,
62
- capabilityId: string,
63
- ): void {
64
- const missing: string[] = [];
65
-
66
- for (const [key, decl] of Object.entries(declarations)) {
67
- const declaration = decl as EnvDeclaration;
68
- const value = env[key] ?? declaration.default;
69
-
70
- if (declaration.required && !value) {
71
- missing.push(key);
72
- }
73
- }
74
-
75
- if (missing.length > 0) {
76
- throw new Error(
77
- `Missing required environment variable${missing.length > 1 ? "s" : ""} for capability "${capabilityId}": ${missing.join(", ")}. ` +
78
- `Set ${missing.length > 1 ? "them" : "it"} in .omni/.env or as environment variable${missing.length > 1 ? "s" : ""}.`,
79
- );
80
- }
81
- }
82
-
83
- /**
84
- * Check if an environment variable should be treated as a secret.
85
- * Secrets should be masked in logs and error messages.
86
- *
87
- * @param key - Environment variable name
88
- * @param declarations - Environment variable declarations from capability.toml
89
- * @returns true if the variable is marked as secret
90
- */
91
- export function isSecretEnvVar(
92
- key: string,
93
- declarations: Record<string, EnvDeclaration | Record<string, never>>,
94
- ): boolean {
95
- const decl = declarations[key] as EnvDeclaration | undefined;
96
- return decl?.secret === true;
97
- }