@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.
- package/dist/index.d.ts +65 -59
- package/dist/index.js +350 -319
- package/package.json +1 -1
- package/src/capability/index.ts +5 -1
- package/src/capability/loader.ts +2 -14
- package/src/capability/registry.ts +1 -3
- package/src/capability/rules.ts +2 -100
- package/src/capability/sources.ts +155 -9
- package/src/config/AGENTS.md +0 -11
- package/src/config/config.ts +6 -54
- package/src/config/index.ts +0 -1
- package/src/config/toml-patcher.ts +4 -6
- 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 +24 -13
- package/src/config/env.ts +0 -97
|
@@ -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
|
+
}
|
package/src/templates/claude.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Template for CLAUDE.md (Claude provider)
|
|
3
|
-
* Creates a minimal file
|
|
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
|
-
|
|
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
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -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,
|
|
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
|
-
|
|
323
|
-
instructionsContent: string;
|
|
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
|
-
}
|