@omnidev-ai/cli 0.18.1 → 0.19.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/dist/index.js +725 -240
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1833,47 +1833,23 @@ function resolveCapabilityRoot(content, capabilityPath) {
|
|
|
1833
1833
|
}
|
|
1834
1834
|
return result;
|
|
1835
1835
|
}
|
|
1836
|
-
function
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
result.description = config.description;
|
|
1836
|
+
function resolveCapabilityRootInValue(value, capabilityPath) {
|
|
1837
|
+
if (typeof value === "string") {
|
|
1838
|
+
return resolveCapabilityRoot(value, capabilityPath);
|
|
1840
1839
|
}
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
"PostToolUse",
|
|
1844
|
-
"PermissionRequest",
|
|
1845
|
-
"UserPromptSubmit",
|
|
1846
|
-
"Stop",
|
|
1847
|
-
"SubagentStop",
|
|
1848
|
-
"Notification",
|
|
1849
|
-
"SessionStart",
|
|
1850
|
-
"SessionEnd",
|
|
1851
|
-
"PreCompact"
|
|
1852
|
-
];
|
|
1853
|
-
for (const event of events) {
|
|
1854
|
-
const matchers = config[event];
|
|
1855
|
-
if (matchers) {
|
|
1856
|
-
result[event] = matchers.map((matcher) => ({
|
|
1857
|
-
...matcher,
|
|
1858
|
-
hooks: matcher.hooks.map((hook) => {
|
|
1859
|
-
if (hook.type === "command") {
|
|
1860
|
-
return {
|
|
1861
|
-
...hook,
|
|
1862
|
-
command: resolveCapabilityRoot(hook.command, capabilityPath)
|
|
1863
|
-
};
|
|
1864
|
-
}
|
|
1865
|
-
if (hook.type === "prompt") {
|
|
1866
|
-
return {
|
|
1867
|
-
...hook,
|
|
1868
|
-
prompt: resolveCapabilityRoot(hook.prompt, capabilityPath)
|
|
1869
|
-
};
|
|
1870
|
-
}
|
|
1871
|
-
return hook;
|
|
1872
|
-
})
|
|
1873
|
-
}));
|
|
1874
|
-
}
|
|
1840
|
+
if (Array.isArray(value)) {
|
|
1841
|
+
return value.map((entry) => resolveCapabilityRootInValue(entry, capabilityPath));
|
|
1875
1842
|
}
|
|
1876
|
-
|
|
1843
|
+
if (value && typeof value === "object") {
|
|
1844
|
+
return Object.fromEntries(Object.entries(value).map(([key, entry]) => [
|
|
1845
|
+
key,
|
|
1846
|
+
resolveCapabilityRootInValue(entry, capabilityPath)
|
|
1847
|
+
]));
|
|
1848
|
+
}
|
|
1849
|
+
return value;
|
|
1850
|
+
}
|
|
1851
|
+
function resolveCapabilityRootInConfig(config, capabilityPath) {
|
|
1852
|
+
return resolveCapabilityRootInValue(config, capabilityPath);
|
|
1877
1853
|
}
|
|
1878
1854
|
var REVERSE_MAPPINGS;
|
|
1879
1855
|
var init_variables = __esm(() => {
|
|
@@ -2183,6 +2159,55 @@ function loadHooksFromCapability(capabilityPath, options) {
|
|
|
2183
2159
|
}
|
|
2184
2160
|
return loadJsonHooksFiles(capabilityPath, hooksJsonInDir, hooksJsonAtRoot, hooksDir, opts);
|
|
2185
2161
|
}
|
|
2162
|
+
function splitHooksTomlConfig(parsed) {
|
|
2163
|
+
const topLevelIssues = [];
|
|
2164
|
+
if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
|
|
2165
|
+
return {
|
|
2166
|
+
sharedConfig: parsed,
|
|
2167
|
+
providerConfigs: undefined,
|
|
2168
|
+
topLevelIssues
|
|
2169
|
+
};
|
|
2170
|
+
}
|
|
2171
|
+
const parsedObj = parsed;
|
|
2172
|
+
const sharedConfig = {};
|
|
2173
|
+
const providerConfigs = {};
|
|
2174
|
+
for (const [key, value] of Object.entries(parsedObj)) {
|
|
2175
|
+
if (key === "description" || HOOK_EVENTS.includes(key)) {
|
|
2176
|
+
sharedConfig[key] = value;
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
2179
|
+
if (PROVIDER_SECTION_KEYS.includes(key)) {
|
|
2180
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
2181
|
+
providerConfigs[key] = value;
|
|
2182
|
+
} else {
|
|
2183
|
+
topLevelIssues.push({
|
|
2184
|
+
severity: "error",
|
|
2185
|
+
code: "HOOKS_INVALID_TOML",
|
|
2186
|
+
message: `[${key}] must be a table`
|
|
2187
|
+
});
|
|
2188
|
+
}
|
|
2189
|
+
continue;
|
|
2190
|
+
}
|
|
2191
|
+
topLevelIssues.push({
|
|
2192
|
+
severity: "error",
|
|
2193
|
+
code: "HOOKS_UNKNOWN_EVENT",
|
|
2194
|
+
message: `Unknown hook event: "${key}"`,
|
|
2195
|
+
suggestion: `Valid events are: ${HOOK_EVENTS.join(", ")}, plus [claude] and [codex] sections`
|
|
2196
|
+
});
|
|
2197
|
+
}
|
|
2198
|
+
return {
|
|
2199
|
+
sharedConfig,
|
|
2200
|
+
providerConfigs: Object.keys(providerConfigs).length > 0 ? providerConfigs : undefined,
|
|
2201
|
+
topLevelIssues
|
|
2202
|
+
};
|
|
2203
|
+
}
|
|
2204
|
+
function prefixValidationIssues(issues, sectionLabel) {
|
|
2205
|
+
return issues.map((issue) => ({
|
|
2206
|
+
...issue,
|
|
2207
|
+
message: `[${sectionLabel}] ${issue.message}`,
|
|
2208
|
+
...issue.suggestion ? { suggestion: `[${sectionLabel}] ${issue.suggestion}` } : {}
|
|
2209
|
+
}));
|
|
2210
|
+
}
|
|
2186
2211
|
function loadTomlHooks(capabilityPath, configPath, hooksDir, opts) {
|
|
2187
2212
|
let rawContent;
|
|
2188
2213
|
try {
|
|
@@ -2234,25 +2259,56 @@ function loadTomlHooks(capabilityPath, configPath, hooksDir, opts) {
|
|
|
2234
2259
|
loadError: `Invalid TOML: ${error instanceof Error ? error.message : String(error)}`
|
|
2235
2260
|
};
|
|
2236
2261
|
}
|
|
2262
|
+
const {
|
|
2263
|
+
sharedConfig,
|
|
2264
|
+
providerConfigs: rawProviderConfigs,
|
|
2265
|
+
topLevelIssues
|
|
2266
|
+
} = splitHooksTomlConfig(parsed);
|
|
2237
2267
|
let validation;
|
|
2238
2268
|
if (opts.validate) {
|
|
2239
|
-
|
|
2269
|
+
const sharedValidation = validateHooksConfig(sharedConfig, {
|
|
2240
2270
|
basePath: hooksDir,
|
|
2241
2271
|
checkScripts: opts.checkScripts ?? false
|
|
2242
2272
|
});
|
|
2273
|
+
const providerErrors = [];
|
|
2274
|
+
const providerWarnings = [];
|
|
2275
|
+
for (const [provider, providerConfig] of Object.entries(rawProviderConfigs ?? {})) {
|
|
2276
|
+
const providerValidation = validateHooksConfig(providerConfig, {
|
|
2277
|
+
basePath: hooksDir,
|
|
2278
|
+
checkScripts: opts.checkScripts ?? false
|
|
2279
|
+
});
|
|
2280
|
+
providerErrors.push(...prefixValidationIssues(providerValidation.errors, provider));
|
|
2281
|
+
providerWarnings.push(...prefixValidationIssues(providerValidation.warnings, provider));
|
|
2282
|
+
}
|
|
2283
|
+
validation = {
|
|
2284
|
+
valid: sharedValidation.valid && topLevelIssues.length === 0 && providerErrors.length === 0,
|
|
2285
|
+
errors: [...topLevelIssues, ...sharedValidation.errors, ...providerErrors],
|
|
2286
|
+
warnings: [...sharedValidation.warnings, ...providerWarnings]
|
|
2287
|
+
};
|
|
2243
2288
|
} else {
|
|
2244
2289
|
validation = createEmptyValidationResult();
|
|
2245
2290
|
}
|
|
2246
|
-
let config = validation.valid ?
|
|
2291
|
+
let config = validation.valid ? sharedConfig : createEmptyHooksConfig();
|
|
2292
|
+
let providerConfigs = validation.valid ? rawProviderConfigs : undefined;
|
|
2247
2293
|
if (opts.resolveCapabilityRoot && validation.valid) {
|
|
2248
2294
|
config = resolveCapabilityRootInConfig(config, capabilityPath);
|
|
2295
|
+
if (providerConfigs) {
|
|
2296
|
+
providerConfigs = Object.fromEntries(Object.entries(providerConfigs).map(([provider, providerConfig]) => [
|
|
2297
|
+
provider,
|
|
2298
|
+
resolveCapabilityRootInValue(providerConfig, capabilityPath)
|
|
2299
|
+
]));
|
|
2300
|
+
}
|
|
2249
2301
|
}
|
|
2250
|
-
|
|
2302
|
+
const result = {
|
|
2251
2303
|
config,
|
|
2252
2304
|
validation,
|
|
2253
2305
|
found: true,
|
|
2254
2306
|
configPath
|
|
2255
2307
|
};
|
|
2308
|
+
if (providerConfigs) {
|
|
2309
|
+
result.providerConfigs = providerConfigs;
|
|
2310
|
+
}
|
|
2311
|
+
return result;
|
|
2256
2312
|
}
|
|
2257
2313
|
function loadJsonHooksFiles(capabilityPath, hooksJsonInDir, hooksJsonAtRoot, hooksDir, opts) {
|
|
2258
2314
|
const configs = [];
|
|
@@ -2348,6 +2404,7 @@ function loadCapabilityHooks(capabilityName, capabilityPath, options) {
|
|
|
2348
2404
|
capabilityName,
|
|
2349
2405
|
capabilityPath,
|
|
2350
2406
|
config: result.config,
|
|
2407
|
+
...result.providerConfigs ? { providerConfigs: result.providerConfigs } : {},
|
|
2351
2408
|
validation: result.validation
|
|
2352
2409
|
};
|
|
2353
2410
|
}
|
|
@@ -2363,6 +2420,7 @@ function getHooksDirectory(capabilityPath) {
|
|
|
2363
2420
|
function getHooksConfigPath(capabilityPath) {
|
|
2364
2421
|
return join3(capabilityPath, HOOKS_DIRECTORY, HOOKS_CONFIG_FILENAME);
|
|
2365
2422
|
}
|
|
2423
|
+
var PROVIDER_SECTION_KEYS;
|
|
2366
2424
|
var init_loader = __esm(() => {
|
|
2367
2425
|
init_dist();
|
|
2368
2426
|
init_constants();
|
|
@@ -2370,6 +2428,7 @@ var init_loader = __esm(() => {
|
|
|
2370
2428
|
init_variables();
|
|
2371
2429
|
init_json_loader();
|
|
2372
2430
|
init_constants();
|
|
2431
|
+
PROVIDER_SECTION_KEYS = ["claude", "codex"];
|
|
2373
2432
|
});
|
|
2374
2433
|
|
|
2375
2434
|
// ../core/src/providers.ts
|
|
@@ -2668,75 +2727,235 @@ import { readFile as readFile6 } from "node:fs/promises";
|
|
|
2668
2727
|
import { basename as basename4, join as join7 } from "node:path";
|
|
2669
2728
|
async function loadSubagents(capabilityPath, capabilityId) {
|
|
2670
2729
|
const subagents = [];
|
|
2671
|
-
const
|
|
2672
|
-
for (const dirName of possibleDirNames) {
|
|
2730
|
+
for (const dirName of POSSIBLE_DIR_NAMES) {
|
|
2673
2731
|
const dir = join7(capabilityPath, dirName);
|
|
2674
2732
|
if (!existsSync9(dir)) {
|
|
2675
2733
|
continue;
|
|
2676
2734
|
}
|
|
2735
|
+
const rootSubagent = await parseSubagentDirectory(dir, capabilityId);
|
|
2736
|
+
if (rootSubagent) {
|
|
2737
|
+
subagents.push(rootSubagent);
|
|
2738
|
+
}
|
|
2677
2739
|
const entries = readdirSync5(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
2678
2740
|
for (const entry of entries) {
|
|
2679
2741
|
if (entry.isDirectory()) {
|
|
2680
|
-
|
|
2681
|
-
if (
|
|
2682
|
-
subagentPath = join7(dir, entry.name, "AGENT.md");
|
|
2683
|
-
}
|
|
2684
|
-
if (existsSync9(subagentPath)) {
|
|
2685
|
-
const subagent = await parseSubagentFile(subagentPath, capabilityId);
|
|
2742
|
+
const subagent = await parseSubagentDirectory(join7(dir, entry.name), capabilityId);
|
|
2743
|
+
if (subagent) {
|
|
2686
2744
|
subagents.push(subagent);
|
|
2687
2745
|
}
|
|
2688
2746
|
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2747
|
+
if (PROMPT_FILE_NAMES.includes(entry.name) || LEGACY_AGENT_FILES.includes(entry.name)) {
|
|
2748
|
+
continue;
|
|
2749
|
+
}
|
|
2689
2750
|
const subagentPath = join7(dir, entry.name);
|
|
2690
|
-
const
|
|
2691
|
-
subagents.push(
|
|
2751
|
+
const content = await readFile6(subagentPath, "utf-8");
|
|
2752
|
+
subagents.push(parseLegacySubagentMarkdown(content, capabilityId, subagentPath, basename4(subagentPath, ".md")));
|
|
2692
2753
|
}
|
|
2693
2754
|
}
|
|
2694
2755
|
}
|
|
2695
2756
|
return subagents;
|
|
2696
2757
|
}
|
|
2697
|
-
|
|
2698
|
-
const content = await readFile6(filePath, "utf-8");
|
|
2758
|
+
function parseLegacySubagentMarkdown(content, capabilityId, sourceLabel, inferredName) {
|
|
2699
2759
|
const parsed = parseFrontmatterWithMarkdown(content);
|
|
2700
2760
|
if (!parsed) {
|
|
2701
|
-
throw new Error(`Invalid SUBAGENT.md format at ${
|
|
2761
|
+
throw new Error(`Invalid SUBAGENT.md format at ${sourceLabel}: missing YAML frontmatter`);
|
|
2702
2762
|
}
|
|
2703
2763
|
const frontmatter = parsed.frontmatter;
|
|
2704
|
-
const
|
|
2705
|
-
const inferredName = basename4(filePath, ".md").replace(/^SUBAGENT$/i, "").replace(/^AGENT$/i, "");
|
|
2706
|
-
const name = frontmatter.name || inferredName;
|
|
2764
|
+
const name = frontmatter.name || inferredName?.replace(/^SUBAGENT$/i, "").replace(/^AGENT$/i, "") || undefined;
|
|
2707
2765
|
if (!name || !frontmatter.description) {
|
|
2708
|
-
throw new Error(`Invalid SUBAGENT.md at ${
|
|
2766
|
+
throw new Error(`Invalid SUBAGENT.md at ${sourceLabel}: name and description required`);
|
|
2709
2767
|
}
|
|
2710
|
-
const
|
|
2711
|
-
name,
|
|
2712
|
-
description: frontmatter.description,
|
|
2713
|
-
systemPrompt: systemPrompt.trim(),
|
|
2714
|
-
capabilityId
|
|
2715
|
-
};
|
|
2768
|
+
const claude = {};
|
|
2716
2769
|
if (frontmatter.tools) {
|
|
2717
|
-
|
|
2770
|
+
claude.tools = parseCommaSeparatedList(frontmatter.tools);
|
|
2718
2771
|
}
|
|
2719
2772
|
if (frontmatter.disallowedTools) {
|
|
2720
|
-
|
|
2773
|
+
claude.disallowedTools = parseCommaSeparatedList(frontmatter.disallowedTools);
|
|
2721
2774
|
}
|
|
2722
2775
|
if (frontmatter.model) {
|
|
2723
|
-
|
|
2776
|
+
claude.model = frontmatter.model;
|
|
2724
2777
|
}
|
|
2725
2778
|
if (frontmatter.permissionMode) {
|
|
2726
|
-
|
|
2779
|
+
claude.permissionMode = frontmatter.permissionMode;
|
|
2727
2780
|
}
|
|
2728
2781
|
if (frontmatter.skills) {
|
|
2729
|
-
|
|
2782
|
+
claude.skills = parseCommaSeparatedList(frontmatter.skills);
|
|
2730
2783
|
}
|
|
2731
2784
|
if (frontmatter.hooks) {
|
|
2732
|
-
|
|
2785
|
+
claude.hooks = frontmatter.hooks;
|
|
2733
2786
|
}
|
|
2734
|
-
|
|
2787
|
+
const subagent = {
|
|
2788
|
+
name,
|
|
2789
|
+
description: frontmatter.description,
|
|
2790
|
+
systemPrompt: parsed.markdown.trim(),
|
|
2791
|
+
capabilityId
|
|
2792
|
+
};
|
|
2793
|
+
if (hasClaudeConfig(claude)) {
|
|
2794
|
+
subagent.claude = claude;
|
|
2795
|
+
}
|
|
2796
|
+
return withClaudeCompatibilityAliases(subagent);
|
|
2797
|
+
}
|
|
2798
|
+
function parseSubagentManifest(agentTomlContent, promptContent, capabilityId, sourceLabel) {
|
|
2799
|
+
let parsed;
|
|
2800
|
+
try {
|
|
2801
|
+
parsed = parse(agentTomlContent);
|
|
2802
|
+
} catch (error) {
|
|
2803
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
2804
|
+
throw new Error(`Invalid agent.toml at ${sourceLabel}: ${message}`);
|
|
2805
|
+
}
|
|
2806
|
+
if (typeof parsed.name !== "string" || parsed.name.trim().length === 0) {
|
|
2807
|
+
throw new Error(`Invalid agent.toml at ${sourceLabel}: name is required`);
|
|
2808
|
+
}
|
|
2809
|
+
if (typeof parsed.description !== "string" || parsed.description.trim().length === 0) {
|
|
2810
|
+
throw new Error(`Invalid agent.toml at ${sourceLabel}: description is required`);
|
|
2811
|
+
}
|
|
2812
|
+
const claude = parseClaudeConfig(parsed.claude, sourceLabel);
|
|
2813
|
+
const codex = parseCodexConfig(parsed.codex, sourceLabel);
|
|
2814
|
+
const subagent = {
|
|
2815
|
+
name: parsed.name.trim(),
|
|
2816
|
+
description: parsed.description.trim(),
|
|
2817
|
+
systemPrompt: promptContent.trim(),
|
|
2818
|
+
capabilityId
|
|
2819
|
+
};
|
|
2820
|
+
if (claude) {
|
|
2821
|
+
subagent.claude = claude;
|
|
2822
|
+
}
|
|
2823
|
+
if (codex) {
|
|
2824
|
+
subagent.codex = codex;
|
|
2825
|
+
}
|
|
2826
|
+
return withClaudeCompatibilityAliases(subagent);
|
|
2827
|
+
}
|
|
2828
|
+
async function parseSubagentDirectory(dirPath, capabilityId) {
|
|
2829
|
+
const manifestPath = findFirstExisting(dirPath, MANIFEST_FILE_NAMES);
|
|
2830
|
+
const promptPath = findFirstExisting(dirPath, PROMPT_FILE_NAMES);
|
|
2831
|
+
if (manifestPath || promptPath) {
|
|
2832
|
+
if (!manifestPath || !promptPath) {
|
|
2833
|
+
throw new Error(`Invalid subagent directory at ${dirPath}: agent.toml and prompt.md must both be present`);
|
|
2834
|
+
}
|
|
2835
|
+
const [agentTomlContent, promptContent] = await Promise.all([
|
|
2836
|
+
readFile6(manifestPath, "utf-8"),
|
|
2837
|
+
readFile6(promptPath, "utf-8")
|
|
2838
|
+
]);
|
|
2839
|
+
return parseSubagentManifest(agentTomlContent, promptContent, capabilityId, manifestPath);
|
|
2840
|
+
}
|
|
2841
|
+
const legacyPath = findFirstExisting(dirPath, LEGACY_AGENT_FILES);
|
|
2842
|
+
if (!legacyPath) {
|
|
2843
|
+
return null;
|
|
2844
|
+
}
|
|
2845
|
+
const content = await readFile6(legacyPath, "utf-8");
|
|
2846
|
+
return parseLegacySubagentMarkdown(content, capabilityId, legacyPath);
|
|
2847
|
+
}
|
|
2848
|
+
function findFirstExisting(dirPath, fileNames) {
|
|
2849
|
+
for (const fileName of fileNames) {
|
|
2850
|
+
const filePath = join7(dirPath, fileName);
|
|
2851
|
+
if (existsSync9(filePath)) {
|
|
2852
|
+
return filePath;
|
|
2853
|
+
}
|
|
2854
|
+
}
|
|
2855
|
+
return null;
|
|
2856
|
+
}
|
|
2857
|
+
function parseClaudeConfig(value, sourceLabel) {
|
|
2858
|
+
if (!value || typeof value !== "object") {
|
|
2859
|
+
return;
|
|
2860
|
+
}
|
|
2861
|
+
const claude = {};
|
|
2862
|
+
if (value.tools !== undefined) {
|
|
2863
|
+
claude.tools = readStringArray(value.tools, `${sourceLabel} [claude].tools`);
|
|
2864
|
+
}
|
|
2865
|
+
if (value.disallowed_tools !== undefined) {
|
|
2866
|
+
claude.disallowedTools = readStringArray(value.disallowed_tools, `${sourceLabel} [claude].disallowed_tools`);
|
|
2867
|
+
}
|
|
2868
|
+
if (value.model !== undefined) {
|
|
2869
|
+
claude.model = readEnum(value.model, ["sonnet", "opus", "haiku", "inherit"], `${sourceLabel} [claude].model`);
|
|
2870
|
+
}
|
|
2871
|
+
if (value.permission_mode !== undefined) {
|
|
2872
|
+
claude.permissionMode = readEnum(value.permission_mode, ["default", "acceptEdits", "dontAsk", "bypassPermissions", "plan"], `${sourceLabel} [claude].permission_mode`);
|
|
2873
|
+
}
|
|
2874
|
+
if (value.skills !== undefined) {
|
|
2875
|
+
claude.skills = readStringArray(value.skills, `${sourceLabel} [claude].skills`);
|
|
2876
|
+
}
|
|
2877
|
+
if (value.hooks !== undefined) {
|
|
2878
|
+
if (typeof value.hooks !== "object" || value.hooks === null) {
|
|
2879
|
+
throw new Error(`Invalid ${sourceLabel} [claude].hooks: expected a table`);
|
|
2880
|
+
}
|
|
2881
|
+
claude.hooks = value.hooks;
|
|
2882
|
+
}
|
|
2883
|
+
return hasClaudeConfig(claude) ? claude : undefined;
|
|
2884
|
+
}
|
|
2885
|
+
function parseCodexConfig(value, sourceLabel) {
|
|
2886
|
+
if (!value || typeof value !== "object") {
|
|
2887
|
+
return;
|
|
2888
|
+
}
|
|
2889
|
+
const codex = {};
|
|
2890
|
+
if (value.model !== undefined) {
|
|
2891
|
+
codex.model = readString(value.model, `${sourceLabel} [codex].model`);
|
|
2892
|
+
}
|
|
2893
|
+
if (value.model_reasoning_effort !== undefined) {
|
|
2894
|
+
codex.modelReasoningEffort = readEnum(value.model_reasoning_effort, ["low", "medium", "high", "xhigh"], `${sourceLabel} [codex].model_reasoning_effort`);
|
|
2895
|
+
}
|
|
2896
|
+
if (value.sandbox_mode !== undefined) {
|
|
2897
|
+
codex.sandboxMode = readEnum(value.sandbox_mode, ["read-only", "workspace-write", "danger-full-access"], `${sourceLabel} [codex].sandbox_mode`);
|
|
2898
|
+
}
|
|
2899
|
+
if (value.nickname_candidates !== undefined) {
|
|
2900
|
+
codex.nicknameCandidates = readStringArray(value.nickname_candidates, `${sourceLabel} [codex].nickname_candidates`);
|
|
2901
|
+
}
|
|
2902
|
+
return Object.keys(codex).length > 0 ? codex : undefined;
|
|
2903
|
+
}
|
|
2904
|
+
function withClaudeCompatibilityAliases(subagent) {
|
|
2905
|
+
if (subagent.claude) {
|
|
2906
|
+
if (subagent.claude.tools) {
|
|
2907
|
+
subagent.tools = subagent.claude.tools;
|
|
2908
|
+
}
|
|
2909
|
+
if (subagent.claude.disallowedTools) {
|
|
2910
|
+
subagent.disallowedTools = subagent.claude.disallowedTools;
|
|
2911
|
+
}
|
|
2912
|
+
if (subagent.claude.model) {
|
|
2913
|
+
subagent.model = subagent.claude.model;
|
|
2914
|
+
}
|
|
2915
|
+
if (subagent.claude.permissionMode) {
|
|
2916
|
+
subagent.permissionMode = subagent.claude.permissionMode;
|
|
2917
|
+
}
|
|
2918
|
+
if (subagent.claude.skills) {
|
|
2919
|
+
subagent.skills = subagent.claude.skills;
|
|
2920
|
+
}
|
|
2921
|
+
if (subagent.claude.hooks) {
|
|
2922
|
+
subagent.hooks = subagent.claude.hooks;
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
return subagent;
|
|
2926
|
+
}
|
|
2927
|
+
function hasClaudeConfig(config) {
|
|
2928
|
+
return Object.keys(config).length > 0;
|
|
2929
|
+
}
|
|
2930
|
+
function readString(value, fieldName) {
|
|
2931
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
2932
|
+
throw new Error(`Invalid ${fieldName}: expected a non-empty string`);
|
|
2933
|
+
}
|
|
2934
|
+
return value.trim();
|
|
2935
|
+
}
|
|
2936
|
+
function readStringArray(value, fieldName) {
|
|
2937
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== "string")) {
|
|
2938
|
+
throw new Error(`Invalid ${fieldName}: expected an array of strings`);
|
|
2939
|
+
}
|
|
2940
|
+
return value.map((item) => item.trim()).filter(Boolean);
|
|
2941
|
+
}
|
|
2942
|
+
function readEnum(value, allowed, fieldName) {
|
|
2943
|
+
if (typeof value !== "string" || !allowed.includes(value)) {
|
|
2944
|
+
throw new Error(`Invalid ${fieldName}: expected one of ${allowed.join(", ")}`);
|
|
2945
|
+
}
|
|
2946
|
+
return value;
|
|
2735
2947
|
}
|
|
2736
2948
|
function parseCommaSeparatedList(value) {
|
|
2737
2949
|
return value.split(",").map((item) => item.trim()).filter(Boolean);
|
|
2738
2950
|
}
|
|
2739
|
-
var
|
|
2951
|
+
var POSSIBLE_DIR_NAMES, LEGACY_AGENT_FILES, MANIFEST_FILE_NAMES, PROMPT_FILE_NAMES;
|
|
2952
|
+
var init_subagents = __esm(() => {
|
|
2953
|
+
init_dist();
|
|
2954
|
+
POSSIBLE_DIR_NAMES = ["subagents", "agents", "agent", "subagent"];
|
|
2955
|
+
LEGACY_AGENT_FILES = ["SUBAGENT.md", "subagent.md", "AGENT.md", "agent.md", "Agent.md"];
|
|
2956
|
+
MANIFEST_FILE_NAMES = ["agent.toml", "AGENT.toml"];
|
|
2957
|
+
PROMPT_FILE_NAMES = ["prompt.md", "PROMPT.md"];
|
|
2958
|
+
});
|
|
2740
2959
|
|
|
2741
2960
|
// ../core/src/capability/loader.ts
|
|
2742
2961
|
import { existsSync as existsSync10, readdirSync as readdirSync6 } from "node:fs";
|
|
@@ -2835,75 +3054,19 @@ function convertDocExports(docExports, capabilityId) {
|
|
|
2835
3054
|
});
|
|
2836
3055
|
}
|
|
2837
3056
|
function convertSubagentExports(subagentExports, capabilityId) {
|
|
2838
|
-
return subagentExports.map((subagentExport) => {
|
|
3057
|
+
return subagentExports.map((subagentExport, index) => {
|
|
2839
3058
|
const exportObj = subagentExport;
|
|
2840
|
-
const
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
let systemPrompt = exportObj.subagentMd;
|
|
2845
|
-
let tools;
|
|
2846
|
-
let disallowedTools;
|
|
2847
|
-
let model;
|
|
2848
|
-
let permissionMode;
|
|
2849
|
-
let skills;
|
|
2850
|
-
if (lines[0]?.trim() === "---") {
|
|
2851
|
-
const endIndex = lines.findIndex((line, i) => i > 0 && line.trim() === "---");
|
|
2852
|
-
if (endIndex > 0) {
|
|
2853
|
-
const frontmatter = lines.slice(1, endIndex);
|
|
2854
|
-
systemPrompt = lines.slice(endIndex + 1).join(`
|
|
2855
|
-
`).trim();
|
|
2856
|
-
for (const line of frontmatter) {
|
|
2857
|
-
const match = line.match(/^(\w+):\s*(.+)$/);
|
|
2858
|
-
if (match?.[1] && match[2]) {
|
|
2859
|
-
const key = match[1];
|
|
2860
|
-
const value = match[2].replace(/^["']|["']$/g, "");
|
|
2861
|
-
switch (key) {
|
|
2862
|
-
case "name":
|
|
2863
|
-
name = value;
|
|
2864
|
-
break;
|
|
2865
|
-
case "description":
|
|
2866
|
-
description = value;
|
|
2867
|
-
break;
|
|
2868
|
-
case "tools":
|
|
2869
|
-
tools = value.split(",").map((t) => t.trim());
|
|
2870
|
-
break;
|
|
2871
|
-
case "disallowedTools":
|
|
2872
|
-
disallowedTools = value.split(",").map((t) => t.trim());
|
|
2873
|
-
break;
|
|
2874
|
-
case "model":
|
|
2875
|
-
model = value;
|
|
2876
|
-
break;
|
|
2877
|
-
case "permissionMode":
|
|
2878
|
-
permissionMode = value;
|
|
2879
|
-
break;
|
|
2880
|
-
case "skills":
|
|
2881
|
-
skills = value.split(",").map((s) => s.trim());
|
|
2882
|
-
break;
|
|
2883
|
-
}
|
|
2884
|
-
}
|
|
2885
|
-
}
|
|
3059
|
+
const sourceLabel = `programmatic subagent export[${index}]`;
|
|
3060
|
+
if (typeof exportObj.agentToml === "string" || typeof exportObj.promptMd === "string") {
|
|
3061
|
+
if (typeof exportObj.agentToml !== "string" || typeof exportObj.promptMd !== "string") {
|
|
3062
|
+
throw new Error(`Invalid ${sourceLabel}: agentToml and promptMd must both be provided`);
|
|
2886
3063
|
}
|
|
3064
|
+
return parseSubagentManifest(exportObj.agentToml, exportObj.promptMd, capabilityId, sourceLabel);
|
|
2887
3065
|
}
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
capabilityId
|
|
2893
|
-
};
|
|
2894
|
-
if (tools)
|
|
2895
|
-
result.tools = tools;
|
|
2896
|
-
if (disallowedTools)
|
|
2897
|
-
result.disallowedTools = disallowedTools;
|
|
2898
|
-
if (model) {
|
|
2899
|
-
result.model = model;
|
|
2900
|
-
}
|
|
2901
|
-
if (permissionMode) {
|
|
2902
|
-
result.permissionMode = permissionMode;
|
|
2903
|
-
}
|
|
2904
|
-
if (skills)
|
|
2905
|
-
result.skills = skills;
|
|
2906
|
-
return result;
|
|
3066
|
+
if (typeof exportObj.subagentMd === "string") {
|
|
3067
|
+
return parseLegacySubagentMarkdown(exportObj.subagentMd, capabilityId, sourceLabel, `subagent-${index + 1}`);
|
|
3068
|
+
}
|
|
3069
|
+
throw new Error(`Invalid ${sourceLabel}: expected agentToml + promptMd or subagentMd`);
|
|
2907
3070
|
});
|
|
2908
3071
|
}
|
|
2909
3072
|
function convertCommandExports(commandExports, capabilityId) {
|
|
@@ -4761,7 +4924,15 @@ var init_sources = __esm(() => {
|
|
|
4761
4924
|
/^copying(?:\..+)?$/i
|
|
4762
4925
|
];
|
|
4763
4926
|
SKILL_FILES = ["SKILL.md", "skill.md", "Skill.md"];
|
|
4764
|
-
AGENT_FILES = [
|
|
4927
|
+
AGENT_FILES = [
|
|
4928
|
+
"AGENT.md",
|
|
4929
|
+
"agent.md",
|
|
4930
|
+
"Agent.md",
|
|
4931
|
+
"SUBAGENT.md",
|
|
4932
|
+
"subagent.md",
|
|
4933
|
+
"agent.toml",
|
|
4934
|
+
"AGENT.toml"
|
|
4935
|
+
];
|
|
4765
4936
|
COMMAND_FILES = ["COMMAND.md", "command.md", "Command.md"];
|
|
4766
4937
|
CONTENT_HASH_EXCLUDES = [
|
|
4767
4938
|
".git",
|
|
@@ -4789,6 +4960,211 @@ var init_capability = __esm(() => {
|
|
|
4789
4960
|
init_subagents();
|
|
4790
4961
|
});
|
|
4791
4962
|
|
|
4963
|
+
// ../core/src/hooks/provider-config.ts
|
|
4964
|
+
function getProviderDisplayName(providerId) {
|
|
4965
|
+
switch (providerId) {
|
|
4966
|
+
case "claude-code":
|
|
4967
|
+
return "Claude Code";
|
|
4968
|
+
case "codex":
|
|
4969
|
+
return "Codex";
|
|
4970
|
+
case "cursor":
|
|
4971
|
+
return "Cursor";
|
|
4972
|
+
case "opencode":
|
|
4973
|
+
return "OpenCode";
|
|
4974
|
+
}
|
|
4975
|
+
}
|
|
4976
|
+
function hasOwnKey(value, key) {
|
|
4977
|
+
return Object.hasOwn(value, key);
|
|
4978
|
+
}
|
|
4979
|
+
function hasHooksInConfig(config) {
|
|
4980
|
+
if (!config) {
|
|
4981
|
+
return false;
|
|
4982
|
+
}
|
|
4983
|
+
for (const event of HOOK_EVENTS) {
|
|
4984
|
+
const matchers = config[event];
|
|
4985
|
+
if (Array.isArray(matchers) && matchers.length > 0) {
|
|
4986
|
+
return true;
|
|
4987
|
+
}
|
|
4988
|
+
}
|
|
4989
|
+
return false;
|
|
4990
|
+
}
|
|
4991
|
+
function matcherMatchesAny(matcher, values) {
|
|
4992
|
+
if (matcher === undefined || matcher === "" || matcher === "*") {
|
|
4993
|
+
return true;
|
|
4994
|
+
}
|
|
4995
|
+
try {
|
|
4996
|
+
const regex = new RegExp(matcher);
|
|
4997
|
+
return values.some((value) => regex.test(value));
|
|
4998
|
+
} catch {
|
|
4999
|
+
return false;
|
|
5000
|
+
}
|
|
5001
|
+
}
|
|
5002
|
+
function cloneMatcher(matcher) {
|
|
5003
|
+
return {
|
|
5004
|
+
...matcher.matcher !== undefined ? { matcher: matcher.matcher } : {},
|
|
5005
|
+
hooks: matcher.hooks.map((hook) => ({ ...hook }))
|
|
5006
|
+
};
|
|
5007
|
+
}
|
|
5008
|
+
function filterSharedHooksForCodex(config, capabilityName) {
|
|
5009
|
+
const warnings = [];
|
|
5010
|
+
if (process.platform === "win32") {
|
|
5011
|
+
if (hasHooksInConfig(config)) {
|
|
5012
|
+
warnings.push(`[hooks] Warning: Capability "${capabilityName}" has shared hooks, but Codex hooks are currently disabled on Windows. Skipping Codex hook output.`);
|
|
5013
|
+
}
|
|
5014
|
+
return { config: {}, warnings };
|
|
5015
|
+
}
|
|
5016
|
+
const filtered = {};
|
|
5017
|
+
for (const event of HOOK_EVENTS) {
|
|
5018
|
+
const matchers = config[event];
|
|
5019
|
+
if (!matchers || matchers.length === 0) {
|
|
5020
|
+
continue;
|
|
5021
|
+
}
|
|
5022
|
+
if (!CODEX_SUPPORTED_EVENTS.has(event)) {
|
|
5023
|
+
warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared event "${event}" is not supported by Codex and was skipped.`);
|
|
5024
|
+
continue;
|
|
5025
|
+
}
|
|
5026
|
+
const filteredMatchers = [];
|
|
5027
|
+
for (const matcher of matchers) {
|
|
5028
|
+
const nextMatcher = cloneMatcher(matcher);
|
|
5029
|
+
const originalHookCount = nextMatcher.hooks.length;
|
|
5030
|
+
nextMatcher.hooks = nextMatcher.hooks.filter((hook, hookIndex) => {
|
|
5031
|
+
if (hook.type === "command") {
|
|
5032
|
+
return true;
|
|
5033
|
+
}
|
|
5034
|
+
warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared ${event} hook ${hookIndex + 1} uses prompt hooks, which Codex does not support. It was skipped.`);
|
|
5035
|
+
return false;
|
|
5036
|
+
});
|
|
5037
|
+
if (nextMatcher.hooks.length === 0) {
|
|
5038
|
+
continue;
|
|
5039
|
+
}
|
|
5040
|
+
if (event === "UserPromptSubmit" || event === "Stop") {
|
|
5041
|
+
if (nextMatcher.matcher !== undefined && nextMatcher.matcher !== "" && nextMatcher.matcher !== "*") {
|
|
5042
|
+
warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared ${event} matcher "${nextMatcher.matcher}" is ignored by Codex. The matcher was dropped.`);
|
|
5043
|
+
delete nextMatcher.matcher;
|
|
5044
|
+
}
|
|
5045
|
+
filteredMatchers.push(nextMatcher);
|
|
5046
|
+
continue;
|
|
5047
|
+
}
|
|
5048
|
+
if (event === "PreToolUse" || event === "PostToolUse") {
|
|
5049
|
+
if (!matcherMatchesAny(nextMatcher.matcher, ["Bash"])) {
|
|
5050
|
+
warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared ${event} matcher "${nextMatcher.matcher ?? ""}" does not match Codex's current tool runtime ("Bash") and was skipped.`);
|
|
5051
|
+
continue;
|
|
5052
|
+
}
|
|
5053
|
+
filteredMatchers.push(nextMatcher);
|
|
5054
|
+
continue;
|
|
5055
|
+
}
|
|
5056
|
+
if (event === "SessionStart") {
|
|
5057
|
+
if (!matcherMatchesAny(nextMatcher.matcher, ["startup", "resume"])) {
|
|
5058
|
+
warnings.push(`[hooks] Warning: Capability "${capabilityName}" shared SessionStart matcher "${nextMatcher.matcher ?? ""}" does not match Codex's current sources ("startup" or "resume") and was skipped.`);
|
|
5059
|
+
continue;
|
|
5060
|
+
}
|
|
5061
|
+
}
|
|
5062
|
+
if (nextMatcher.hooks.length !== originalHookCount || nextMatcher.matcher !== matcher.matcher) {
|
|
5063
|
+
filteredMatchers.push(nextMatcher);
|
|
5064
|
+
} else {
|
|
5065
|
+
filteredMatchers.push(matcher);
|
|
5066
|
+
}
|
|
5067
|
+
}
|
|
5068
|
+
if (filteredMatchers.length > 0) {
|
|
5069
|
+
filtered[event] = filteredMatchers;
|
|
5070
|
+
}
|
|
5071
|
+
}
|
|
5072
|
+
return { config: filtered, warnings };
|
|
5073
|
+
}
|
|
5074
|
+
function getProviderOverrideWarnings(providerId, capabilityName, providerConfigs) {
|
|
5075
|
+
if (!providerConfigs) {
|
|
5076
|
+
return [];
|
|
5077
|
+
}
|
|
5078
|
+
if (providerId === "claude-code" && providerConfigs.codex) {
|
|
5079
|
+
return [
|
|
5080
|
+
`[hooks] Warning: Capability "${capabilityName}" defines [codex] hooks; they are not used by Claude Code.`
|
|
5081
|
+
];
|
|
5082
|
+
}
|
|
5083
|
+
if (providerId === "codex" && providerConfigs.claude) {
|
|
5084
|
+
return [
|
|
5085
|
+
`[hooks] Warning: Capability "${capabilityName}" defines [claude] hooks; they are not used by Codex.`
|
|
5086
|
+
];
|
|
5087
|
+
}
|
|
5088
|
+
return [];
|
|
5089
|
+
}
|
|
5090
|
+
function applyProviderOverrides(baseConfig, providerId, capabilityName, providerConfigs) {
|
|
5091
|
+
const warnings = getProviderOverrideWarnings(providerId, capabilityName, providerConfigs);
|
|
5092
|
+
const providerSection = PROVIDER_SECTION_BY_ID[providerId];
|
|
5093
|
+
if (!providerSection) {
|
|
5094
|
+
return { config: baseConfig, warnings };
|
|
5095
|
+
}
|
|
5096
|
+
const overrideConfig = providerConfigs?.[providerSection];
|
|
5097
|
+
if (!overrideConfig) {
|
|
5098
|
+
return { config: baseConfig, warnings };
|
|
5099
|
+
}
|
|
5100
|
+
const result = { ...baseConfig };
|
|
5101
|
+
for (const event of HOOK_EVENTS) {
|
|
5102
|
+
if (!hasOwnKey(overrideConfig, event)) {
|
|
5103
|
+
continue;
|
|
5104
|
+
}
|
|
5105
|
+
const eventValue = overrideConfig[event];
|
|
5106
|
+
if (!Array.isArray(eventValue)) {
|
|
5107
|
+
warnings.push(`[hooks] Warning: Capability "${capabilityName}" [${providerSection}].${event} must be an array to be emitted for ${getProviderDisplayName(providerId)}. The override was skipped.`);
|
|
5108
|
+
continue;
|
|
5109
|
+
}
|
|
5110
|
+
result[event] = eventValue;
|
|
5111
|
+
}
|
|
5112
|
+
return { config: result, warnings };
|
|
5113
|
+
}
|
|
5114
|
+
function mergeCapabilityHookConfig(target, capabilityConfig) {
|
|
5115
|
+
for (const event of HOOK_EVENTS) {
|
|
5116
|
+
const eventValue = capabilityConfig[event];
|
|
5117
|
+
if (!Array.isArray(eventValue) || eventValue.length === 0) {
|
|
5118
|
+
continue;
|
|
5119
|
+
}
|
|
5120
|
+
const existing = target[event];
|
|
5121
|
+
target[event] = Array.isArray(existing) ? [...existing, ...eventValue] : [...eventValue];
|
|
5122
|
+
}
|
|
5123
|
+
}
|
|
5124
|
+
function composeHooksForProvider(capabilityHooks, providerId) {
|
|
5125
|
+
if (providerId !== "claude-code" && providerId !== "codex") {
|
|
5126
|
+
return { config: {}, warnings: [] };
|
|
5127
|
+
}
|
|
5128
|
+
const warnings = [];
|
|
5129
|
+
const mergedConfig = {};
|
|
5130
|
+
for (const capHooks of capabilityHooks) {
|
|
5131
|
+
if (providerId === "codex" && process.platform === "win32") {
|
|
5132
|
+
if (hasHooksInConfig(capHooks.config) || hasHooksInConfig(capHooks.providerConfigs?.codex)) {
|
|
5133
|
+
warnings.push(`[hooks] Warning: Capability "${capHooks.capabilityName}" has Codex hooks configured, but Codex hooks are currently disabled on Windows. Skipping Codex hook output.`);
|
|
5134
|
+
}
|
|
5135
|
+
continue;
|
|
5136
|
+
}
|
|
5137
|
+
let capabilityConfig = capHooks.config;
|
|
5138
|
+
if (providerId === "codex") {
|
|
5139
|
+
const filtered = filterSharedHooksForCodex(capabilityConfig, capHooks.capabilityName);
|
|
5140
|
+
capabilityConfig = filtered.config;
|
|
5141
|
+
warnings.push(...filtered.warnings);
|
|
5142
|
+
}
|
|
5143
|
+
const withOverrides = applyProviderOverrides(capabilityConfig, providerId, capHooks.capabilityName, capHooks.providerConfigs);
|
|
5144
|
+
warnings.push(...withOverrides.warnings);
|
|
5145
|
+
mergeCapabilityHookConfig(mergedConfig, withOverrides.config);
|
|
5146
|
+
}
|
|
5147
|
+
return {
|
|
5148
|
+
config: mergedConfig,
|
|
5149
|
+
warnings
|
|
5150
|
+
};
|
|
5151
|
+
}
|
|
5152
|
+
var CODEX_SUPPORTED_EVENTS, PROVIDER_SECTION_BY_ID;
|
|
5153
|
+
var init_provider_config = __esm(() => {
|
|
5154
|
+
init_constants();
|
|
5155
|
+
CODEX_SUPPORTED_EVENTS = new Set([
|
|
5156
|
+
"SessionStart",
|
|
5157
|
+
"PreToolUse",
|
|
5158
|
+
"PostToolUse",
|
|
5159
|
+
"UserPromptSubmit",
|
|
5160
|
+
"Stop"
|
|
5161
|
+
]);
|
|
5162
|
+
PROVIDER_SECTION_BY_ID = {
|
|
5163
|
+
"claude-code": "claude",
|
|
5164
|
+
codex: "codex"
|
|
5165
|
+
};
|
|
5166
|
+
});
|
|
5167
|
+
|
|
4792
5168
|
// ../core/src/hooks/index.ts
|
|
4793
5169
|
var init_hooks = __esm(() => {
|
|
4794
5170
|
init_constants();
|
|
@@ -4797,6 +5173,7 @@ var init_hooks = __esm(() => {
|
|
|
4797
5173
|
init_variables();
|
|
4798
5174
|
init_loader();
|
|
4799
5175
|
init_merger();
|
|
5176
|
+
init_provider_config();
|
|
4800
5177
|
init_json_loader();
|
|
4801
5178
|
});
|
|
4802
5179
|
|
|
@@ -6569,6 +6946,7 @@ __export(exports_src, {
|
|
|
6569
6946
|
saveManifest: () => saveManifest,
|
|
6570
6947
|
saveLockFile: () => saveLockFile,
|
|
6571
6948
|
resolveEnabledCapabilities: () => resolveEnabledCapabilities,
|
|
6949
|
+
resolveCapabilityRootInValue: () => resolveCapabilityRootInValue,
|
|
6572
6950
|
resolveCapabilityRootInConfig: () => resolveCapabilityRootInConfig,
|
|
6573
6951
|
resolveCapabilityRoot: () => resolveCapabilityRoot,
|
|
6574
6952
|
resolveCapabilityInstallCommand: () => resolveCapabilityInstallCommand,
|
|
@@ -6619,6 +6997,7 @@ __export(exports_src, {
|
|
|
6619
6997
|
isFileSourceConfig: () => isFileSourceConfig,
|
|
6620
6998
|
isFileSource: () => isFileSource,
|
|
6621
6999
|
installCapabilityDependencies: () => installCapabilityDependencies,
|
|
7000
|
+
hasHooksInConfig: () => hasHooksInConfig,
|
|
6622
7001
|
hasHooks: () => hasHooks,
|
|
6623
7002
|
hasAnyHooks: () => hasAnyHooks,
|
|
6624
7003
|
getVersion: () => getVersion,
|
|
@@ -6657,6 +7036,7 @@ __export(exports_src, {
|
|
|
6657
7036
|
countHooks: () => countHooks,
|
|
6658
7037
|
containsOmnidevVariables: () => containsOmnidevVariables,
|
|
6659
7038
|
containsClaudeVariables: () => containsClaudeVariables,
|
|
7039
|
+
composeHooksForProvider: () => composeHooksForProvider,
|
|
6660
7040
|
clearCapabilityAllows: () => clearCapabilityAllows,
|
|
6661
7041
|
clearAllSecurityAllows: () => clearAllSecurityAllows,
|
|
6662
7042
|
clearActiveProfileState: () => clearActiveProfileState,
|
|
@@ -6707,7 +7087,7 @@ import { run } from "@stricli/core";
|
|
|
6707
7087
|
// src/lib/dynamic-app.ts
|
|
6708
7088
|
import { existsSync as existsSync32 } from "node:fs";
|
|
6709
7089
|
import { createRequire as createRequire2 } from "node:module";
|
|
6710
|
-
import { join as
|
|
7090
|
+
import { join as join31 } from "node:path";
|
|
6711
7091
|
import { buildApplication, buildRouteMap as buildRouteMap7 } from "@stricli/core";
|
|
6712
7092
|
|
|
6713
7093
|
// src/commands/add.ts
|
|
@@ -6774,10 +7154,10 @@ var HooksWriter = {
|
|
|
6774
7154
|
if (!bundle.hooks) {
|
|
6775
7155
|
return { filesWritten: [] };
|
|
6776
7156
|
}
|
|
7157
|
+
const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
|
|
6777
7158
|
const settingsPath = join13(ctx.projectRoot, ctx.outputPath);
|
|
6778
7159
|
const parentDir = dirname2(settingsPath);
|
|
6779
7160
|
await mkdir2(parentDir, { recursive: true });
|
|
6780
|
-
const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
|
|
6781
7161
|
let existingSettings = {};
|
|
6782
7162
|
if (existsSync22(settingsPath)) {
|
|
6783
7163
|
try {
|
|
@@ -7011,9 +7391,12 @@ function createProviderScopedBundle(bundle, providerId) {
|
|
|
7011
7391
|
subagents,
|
|
7012
7392
|
instructionsContent: generateInstructionsContent2(rules, docs)
|
|
7013
7393
|
};
|
|
7014
|
-
const
|
|
7015
|
-
|
|
7016
|
-
|
|
7394
|
+
const composedHooks = composeHooksForProvider(capabilities2.flatMap((capability3) => capability3.hooks ? [capability3.hooks] : []), providerId);
|
|
7395
|
+
for (const warning of composedHooks.warnings) {
|
|
7396
|
+
console.warn(warning);
|
|
7397
|
+
}
|
|
7398
|
+
if (hasHooksInConfig(composedHooks.config)) {
|
|
7399
|
+
scopedBundle.hooks = composedHooks.config;
|
|
7017
7400
|
}
|
|
7018
7401
|
return scopedBundle;
|
|
7019
7402
|
}
|
|
@@ -7021,24 +7404,34 @@ function createProviderScopedBundle(bundle, providerId) {
|
|
|
7021
7404
|
// ../adapters/src/writers/claude/agents.ts
|
|
7022
7405
|
import { mkdir as mkdir6, writeFile as writeFile14 } from "node:fs/promises";
|
|
7023
7406
|
import { join as join17 } from "node:path";
|
|
7407
|
+
function getClaudeConfig(agent) {
|
|
7408
|
+
return {
|
|
7409
|
+
tools: agent.claude?.tools ?? agent.tools,
|
|
7410
|
+
disallowedTools: agent.claude?.disallowedTools ?? agent.disallowedTools,
|
|
7411
|
+
model: agent.claude?.model ?? agent.model,
|
|
7412
|
+
permissionMode: agent.claude?.permissionMode ?? agent.permissionMode,
|
|
7413
|
+
skills: agent.claude?.skills ?? agent.skills
|
|
7414
|
+
};
|
|
7415
|
+
}
|
|
7024
7416
|
function generateFrontmatter(agent) {
|
|
7417
|
+
const claude2 = getClaudeConfig(agent);
|
|
7025
7418
|
const lines = ["---"];
|
|
7026
7419
|
lines.push(`name: ${agent.name}`);
|
|
7027
7420
|
lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
|
|
7028
|
-
if (
|
|
7029
|
-
lines.push(`tools: ${
|
|
7421
|
+
if (claude2.tools && claude2.tools.length > 0) {
|
|
7422
|
+
lines.push(`tools: ${claude2.tools.join(", ")}`);
|
|
7030
7423
|
}
|
|
7031
|
-
if (
|
|
7032
|
-
lines.push(`disallowedTools: ${
|
|
7424
|
+
if (claude2.disallowedTools && claude2.disallowedTools.length > 0) {
|
|
7425
|
+
lines.push(`disallowedTools: ${claude2.disallowedTools.join(", ")}`);
|
|
7033
7426
|
}
|
|
7034
|
-
if (
|
|
7035
|
-
lines.push(`model: ${
|
|
7427
|
+
if (claude2.model && claude2.model !== "inherit") {
|
|
7428
|
+
lines.push(`model: ${claude2.model}`);
|
|
7036
7429
|
}
|
|
7037
|
-
if (
|
|
7038
|
-
lines.push(`permissionMode: ${
|
|
7430
|
+
if (claude2.permissionMode && claude2.permissionMode !== "default") {
|
|
7431
|
+
lines.push(`permissionMode: ${claude2.permissionMode}`);
|
|
7039
7432
|
}
|
|
7040
|
-
if (
|
|
7041
|
-
lines.push(`skills: ${
|
|
7433
|
+
if (claude2.skills && claude2.skills.length > 0) {
|
|
7434
|
+
lines.push(`skills: ${claude2.skills.join(", ")}`);
|
|
7042
7435
|
}
|
|
7043
7436
|
lines.push("---");
|
|
7044
7437
|
return lines.join(`
|
|
@@ -7098,12 +7491,82 @@ var claudeCodeAdapter = {
|
|
|
7098
7491
|
};
|
|
7099
7492
|
// ../adapters/src/codex/index.ts
|
|
7100
7493
|
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
7101
|
-
import { join as
|
|
7494
|
+
import { join as join21 } from "node:path";
|
|
7102
7495
|
|
|
7103
|
-
// ../adapters/src/writers/codex/
|
|
7496
|
+
// ../adapters/src/writers/codex/agents.ts
|
|
7104
7497
|
init_dist();
|
|
7105
7498
|
import { mkdir as mkdir7, writeFile as writeFile15 } from "node:fs/promises";
|
|
7106
|
-
import {
|
|
7499
|
+
import { join as join18 } from "node:path";
|
|
7500
|
+
function buildCodexAgentFile(agent) {
|
|
7501
|
+
const codex = agent.codex ?? {};
|
|
7502
|
+
const file = {
|
|
7503
|
+
name: agent.name,
|
|
7504
|
+
description: agent.description,
|
|
7505
|
+
developer_instructions: agent.systemPrompt
|
|
7506
|
+
};
|
|
7507
|
+
if (codex.model) {
|
|
7508
|
+
file.model = codex.model;
|
|
7509
|
+
}
|
|
7510
|
+
if (codex.modelReasoningEffort) {
|
|
7511
|
+
file.model_reasoning_effort = codex.modelReasoningEffort;
|
|
7512
|
+
}
|
|
7513
|
+
if (codex.sandboxMode) {
|
|
7514
|
+
file.sandbox_mode = codex.sandboxMode;
|
|
7515
|
+
}
|
|
7516
|
+
if (codex.nicknameCandidates && codex.nicknameCandidates.length > 0) {
|
|
7517
|
+
file.nickname_candidates = codex.nicknameCandidates;
|
|
7518
|
+
}
|
|
7519
|
+
return file;
|
|
7520
|
+
}
|
|
7521
|
+
var CodexAgentsWriter = {
|
|
7522
|
+
id: "codex-agents",
|
|
7523
|
+
async write(bundle, ctx) {
|
|
7524
|
+
if (bundle.subagents.length === 0) {
|
|
7525
|
+
return { filesWritten: [] };
|
|
7526
|
+
}
|
|
7527
|
+
const agentsDir = join18(ctx.projectRoot, ctx.outputPath);
|
|
7528
|
+
await mkdir7(agentsDir, { recursive: true });
|
|
7529
|
+
const filesWritten = [];
|
|
7530
|
+
const managedOutputs = [];
|
|
7531
|
+
for (const agent of bundle.subagents) {
|
|
7532
|
+
const content = stringify(buildCodexAgentFile(agent));
|
|
7533
|
+
const relativePath = join18(ctx.outputPath, `${agent.name}.toml`);
|
|
7534
|
+
const filePath = join18(ctx.projectRoot, relativePath);
|
|
7535
|
+
await writeFile15(filePath, content, "utf-8");
|
|
7536
|
+
filesWritten.push(relativePath);
|
|
7537
|
+
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
7538
|
+
}
|
|
7539
|
+
return {
|
|
7540
|
+
filesWritten,
|
|
7541
|
+
managedOutputs
|
|
7542
|
+
};
|
|
7543
|
+
}
|
|
7544
|
+
};
|
|
7545
|
+
// ../adapters/src/writers/codex/hooks.ts
|
|
7546
|
+
import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
|
|
7547
|
+
import { dirname as dirname4, join as join19 } from "node:path";
|
|
7548
|
+
var CodexHooksWriter = {
|
|
7549
|
+
id: "codex-hooks",
|
|
7550
|
+
async write(bundle, ctx) {
|
|
7551
|
+
if (!bundle.hooks) {
|
|
7552
|
+
return { filesWritten: [] };
|
|
7553
|
+
}
|
|
7554
|
+
const hooksPath = join19(ctx.projectRoot, ctx.outputPath);
|
|
7555
|
+
await mkdir8(dirname4(hooksPath), { recursive: true });
|
|
7556
|
+
const content = `${JSON.stringify({ hooks: bundle.hooks }, null, 2)}
|
|
7557
|
+
`;
|
|
7558
|
+
await writeFile16(hooksPath, content, "utf-8");
|
|
7559
|
+
return {
|
|
7560
|
+
filesWritten: [ctx.outputPath],
|
|
7561
|
+
managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
|
|
7562
|
+
};
|
|
7563
|
+
}
|
|
7564
|
+
};
|
|
7565
|
+
// ../adapters/src/writers/codex/toml.ts
|
|
7566
|
+
init_src();
|
|
7567
|
+
init_dist();
|
|
7568
|
+
import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
|
|
7569
|
+
import { dirname as dirname5, join as join20 } from "node:path";
|
|
7107
7570
|
var FILE_HEADER = `# Generated by OmniDev - DO NOT EDIT
|
|
7108
7571
|
# Run \`omnidev sync\` to regenerate
|
|
7109
7572
|
|
|
@@ -7151,12 +7614,13 @@ var CodexTomlWriter = {
|
|
|
7151
7614
|
id: "codex-toml",
|
|
7152
7615
|
async write(bundle, ctx) {
|
|
7153
7616
|
const mcps = collectMcps(bundle);
|
|
7154
|
-
|
|
7617
|
+
const hasHooks2 = hasHooksInConfig(bundle.hooks);
|
|
7618
|
+
if (mcps.size === 0 && !hasHooks2) {
|
|
7155
7619
|
return { filesWritten: [] };
|
|
7156
7620
|
}
|
|
7157
|
-
const configPath =
|
|
7158
|
-
const parentDir =
|
|
7159
|
-
await
|
|
7621
|
+
const configPath = join20(ctx.projectRoot, ctx.outputPath);
|
|
7622
|
+
const parentDir = dirname5(configPath);
|
|
7623
|
+
await mkdir9(parentDir, { recursive: true });
|
|
7160
7624
|
const mcpServers = {};
|
|
7161
7625
|
for (const [id, mcp] of mcps) {
|
|
7162
7626
|
const converted = buildCodexMcpConfig(id, mcp);
|
|
@@ -7164,14 +7628,18 @@ var CodexTomlWriter = {
|
|
|
7164
7628
|
mcpServers[id] = converted;
|
|
7165
7629
|
}
|
|
7166
7630
|
}
|
|
7167
|
-
if (Object.keys(mcpServers).length === 0) {
|
|
7631
|
+
if (Object.keys(mcpServers).length === 0 && !hasHooks2) {
|
|
7168
7632
|
return { filesWritten: [] };
|
|
7169
7633
|
}
|
|
7170
|
-
const codexConfig = {
|
|
7171
|
-
|
|
7172
|
-
|
|
7634
|
+
const codexConfig = {};
|
|
7635
|
+
if (hasHooks2) {
|
|
7636
|
+
codexConfig.features = { codex_hooks: true };
|
|
7637
|
+
}
|
|
7638
|
+
if (Object.keys(mcpServers).length > 0) {
|
|
7639
|
+
codexConfig.mcp_servers = mcpServers;
|
|
7640
|
+
}
|
|
7173
7641
|
const tomlContent = FILE_HEADER + stringify(codexConfig);
|
|
7174
|
-
await
|
|
7642
|
+
await writeFile17(configPath, tomlContent, "utf-8");
|
|
7175
7643
|
return {
|
|
7176
7644
|
filesWritten: [ctx.outputPath],
|
|
7177
7645
|
managedOutputs: [createManagedOutput(ctx.outputPath, this.id, tomlContent)]
|
|
@@ -7186,10 +7654,12 @@ var codexAdapter = {
|
|
|
7186
7654
|
{ writer: InstructionsMdWriter, outputPath: "AGENTS.md" },
|
|
7187
7655
|
{ writer: SkillsWriter, outputPath: ".codex/skills/" },
|
|
7188
7656
|
{ writer: CommandsAsSkillsWriter, outputPath: ".codex/skills/" },
|
|
7657
|
+
{ writer: CodexAgentsWriter, outputPath: ".codex/agents/" },
|
|
7658
|
+
{ writer: CodexHooksWriter, outputPath: ".codex/hooks.json" },
|
|
7189
7659
|
{ writer: CodexTomlWriter, outputPath: ".codex/config.toml" }
|
|
7190
7660
|
],
|
|
7191
7661
|
async init(ctx) {
|
|
7192
|
-
const codexDir =
|
|
7662
|
+
const codexDir = join21(ctx.projectRoot, ".codex");
|
|
7193
7663
|
mkdirSync6(codexDir, { recursive: true });
|
|
7194
7664
|
return {
|
|
7195
7665
|
filesCreated: [".codex/"],
|
|
@@ -7209,11 +7679,17 @@ var codexAdapter = {
|
|
|
7209
7679
|
};
|
|
7210
7680
|
// ../adapters/src/cursor/index.ts
|
|
7211
7681
|
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
7212
|
-
import { join as
|
|
7682
|
+
import { join as join26 } from "node:path";
|
|
7213
7683
|
|
|
7214
7684
|
// ../adapters/src/writers/cursor/agents.ts
|
|
7215
|
-
import { mkdir as
|
|
7216
|
-
import { join as
|
|
7685
|
+
import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
|
|
7686
|
+
import { join as join22 } from "node:path";
|
|
7687
|
+
function getClaudeConfig2(agent) {
|
|
7688
|
+
return {
|
|
7689
|
+
model: agent.claude?.model ?? agent.model,
|
|
7690
|
+
permissionMode: agent.claude?.permissionMode ?? agent.permissionMode
|
|
7691
|
+
};
|
|
7692
|
+
}
|
|
7217
7693
|
function mapModelToCursor(model) {
|
|
7218
7694
|
if (!model || model === "inherit")
|
|
7219
7695
|
return "inherit";
|
|
@@ -7225,14 +7701,15 @@ function mapModelToCursor(model) {
|
|
|
7225
7701
|
return modelMap[model] ?? "inherit";
|
|
7226
7702
|
}
|
|
7227
7703
|
function generateFrontmatter2(agent) {
|
|
7704
|
+
const claude2 = getClaudeConfig2(agent);
|
|
7228
7705
|
const lines = ["---"];
|
|
7229
7706
|
lines.push(`name: ${agent.name}`);
|
|
7230
7707
|
lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
|
|
7231
|
-
const model = mapModelToCursor(
|
|
7708
|
+
const model = mapModelToCursor(claude2.model);
|
|
7232
7709
|
if (model) {
|
|
7233
7710
|
lines.push(`model: ${model}`);
|
|
7234
7711
|
}
|
|
7235
|
-
if (
|
|
7712
|
+
if (claude2.permissionMode === "plan") {
|
|
7236
7713
|
lines.push("readonly: true");
|
|
7237
7714
|
}
|
|
7238
7715
|
if (agent.isBackground) {
|
|
@@ -7245,8 +7722,8 @@ function generateFrontmatter2(agent) {
|
|
|
7245
7722
|
var CursorAgentsWriter = {
|
|
7246
7723
|
id: "cursor-agents",
|
|
7247
7724
|
async write(bundle, ctx) {
|
|
7248
|
-
const agentsDir =
|
|
7249
|
-
await
|
|
7725
|
+
const agentsDir = join22(ctx.projectRoot, ctx.outputPath);
|
|
7726
|
+
await mkdir10(agentsDir, { recursive: true });
|
|
7250
7727
|
const filesWritten = [];
|
|
7251
7728
|
const managedOutputs = [];
|
|
7252
7729
|
for (const agent of bundle.subagents) {
|
|
@@ -7254,9 +7731,9 @@ var CursorAgentsWriter = {
|
|
|
7254
7731
|
const content = `${frontmatter}
|
|
7255
7732
|
|
|
7256
7733
|
${agent.systemPrompt}`;
|
|
7257
|
-
const agentPath =
|
|
7258
|
-
await
|
|
7259
|
-
const relativePath =
|
|
7734
|
+
const agentPath = join22(agentsDir, `${agent.name}.md`);
|
|
7735
|
+
await writeFile18(agentPath, content, "utf-8");
|
|
7736
|
+
const relativePath = join22(ctx.outputPath, `${agent.name}.md`);
|
|
7260
7737
|
filesWritten.push(relativePath);
|
|
7261
7738
|
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
7262
7739
|
}
|
|
@@ -7267,13 +7744,13 @@ ${agent.systemPrompt}`;
|
|
|
7267
7744
|
}
|
|
7268
7745
|
};
|
|
7269
7746
|
// ../adapters/src/writers/cursor/commands.ts
|
|
7270
|
-
import { mkdir as
|
|
7271
|
-
import { join as
|
|
7747
|
+
import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
|
|
7748
|
+
import { join as join23 } from "node:path";
|
|
7272
7749
|
var CursorCommandsWriter = {
|
|
7273
7750
|
id: "cursor-commands",
|
|
7274
7751
|
async write(bundle, ctx) {
|
|
7275
|
-
const commandsDir =
|
|
7276
|
-
await
|
|
7752
|
+
const commandsDir = join23(ctx.projectRoot, ctx.outputPath);
|
|
7753
|
+
await mkdir11(commandsDir, { recursive: true });
|
|
7277
7754
|
const filesWritten = [];
|
|
7278
7755
|
const managedOutputs = [];
|
|
7279
7756
|
for (const command of bundle.commands) {
|
|
@@ -7282,9 +7759,9 @@ var CursorCommandsWriter = {
|
|
|
7282
7759
|
${command.description}
|
|
7283
7760
|
|
|
7284
7761
|
${command.prompt}`;
|
|
7285
|
-
const commandPath =
|
|
7286
|
-
await
|
|
7287
|
-
const relativePath =
|
|
7762
|
+
const commandPath = join23(commandsDir, `${command.name}.md`);
|
|
7763
|
+
await writeFile19(commandPath, content, "utf-8");
|
|
7764
|
+
const relativePath = join23(ctx.outputPath, `${command.name}.md`);
|
|
7288
7765
|
filesWritten.push(relativePath);
|
|
7289
7766
|
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
7290
7767
|
}
|
|
@@ -7295,8 +7772,8 @@ ${command.prompt}`;
|
|
|
7295
7772
|
}
|
|
7296
7773
|
};
|
|
7297
7774
|
// ../adapters/src/writers/cursor/mcp-json.ts
|
|
7298
|
-
import { mkdir as
|
|
7299
|
-
import { dirname as
|
|
7775
|
+
import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
|
|
7776
|
+
import { dirname as dirname6, join as join24 } from "node:path";
|
|
7300
7777
|
function buildCursorMcpConfig(mcp) {
|
|
7301
7778
|
const transport = mcp.transport ?? "stdio";
|
|
7302
7779
|
if (transport === "http" || transport === "sse") {
|
|
@@ -7341,9 +7818,9 @@ var CursorMcpJsonWriter = {
|
|
|
7341
7818
|
if (mcps.size === 0) {
|
|
7342
7819
|
return { filesWritten: [] };
|
|
7343
7820
|
}
|
|
7344
|
-
const configPath =
|
|
7345
|
-
const parentDir =
|
|
7346
|
-
await
|
|
7821
|
+
const configPath = join24(ctx.projectRoot, ctx.outputPath);
|
|
7822
|
+
const parentDir = dirname6(configPath);
|
|
7823
|
+
await mkdir12(parentDir, { recursive: true });
|
|
7347
7824
|
const mcpServers = {};
|
|
7348
7825
|
for (const [id, mcp] of mcps) {
|
|
7349
7826
|
const converted = buildCursorMcpConfig(mcp);
|
|
@@ -7359,7 +7836,7 @@ var CursorMcpJsonWriter = {
|
|
|
7359
7836
|
};
|
|
7360
7837
|
const content = `${JSON.stringify(cursorMcpJson, null, 2)}
|
|
7361
7838
|
`;
|
|
7362
|
-
await
|
|
7839
|
+
await writeFile20(configPath, content, "utf-8");
|
|
7363
7840
|
return {
|
|
7364
7841
|
filesWritten: [ctx.outputPath],
|
|
7365
7842
|
managedOutputs: [createManagedOutput(ctx.outputPath, this.id, content)]
|
|
@@ -7367,19 +7844,19 @@ var CursorMcpJsonWriter = {
|
|
|
7367
7844
|
}
|
|
7368
7845
|
};
|
|
7369
7846
|
// ../adapters/src/writers/cursor/rules.ts
|
|
7370
|
-
import { mkdir as
|
|
7371
|
-
import { join as
|
|
7847
|
+
import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
|
|
7848
|
+
import { join as join25 } from "node:path";
|
|
7372
7849
|
var CursorRulesWriter = {
|
|
7373
7850
|
id: "cursor-rules",
|
|
7374
7851
|
async write(bundle, ctx) {
|
|
7375
|
-
const rulesDir =
|
|
7376
|
-
await
|
|
7852
|
+
const rulesDir = join25(ctx.projectRoot, ctx.outputPath);
|
|
7853
|
+
await mkdir13(rulesDir, { recursive: true });
|
|
7377
7854
|
const filesWritten = [];
|
|
7378
7855
|
const managedOutputs = [];
|
|
7379
7856
|
for (const rule of bundle.rules) {
|
|
7380
|
-
const rulePath =
|
|
7381
|
-
await
|
|
7382
|
-
const relativePath =
|
|
7857
|
+
const rulePath = join25(rulesDir, `omnidev-${rule.name}.mdc`);
|
|
7858
|
+
await writeFile21(rulePath, rule.content, "utf-8");
|
|
7859
|
+
const relativePath = join25(ctx.outputPath, `omnidev-${rule.name}.mdc`);
|
|
7383
7860
|
filesWritten.push(relativePath);
|
|
7384
7861
|
managedOutputs.push(createManagedOutput(relativePath, this.id, rule.content));
|
|
7385
7862
|
}
|
|
@@ -7402,7 +7879,7 @@ var cursorAdapter = {
|
|
|
7402
7879
|
{ writer: CursorMcpJsonWriter, outputPath: ".cursor/mcp.json" }
|
|
7403
7880
|
],
|
|
7404
7881
|
async init(ctx) {
|
|
7405
|
-
const rulesDir =
|
|
7882
|
+
const rulesDir = join26(ctx.projectRoot, ".cursor", "rules");
|
|
7406
7883
|
mkdirSync7(rulesDir, { recursive: true });
|
|
7407
7884
|
return {
|
|
7408
7885
|
filesCreated: [".cursor/rules/"],
|
|
@@ -7429,11 +7906,18 @@ var cursorAdapter = {
|
|
|
7429
7906
|
};
|
|
7430
7907
|
// ../adapters/src/opencode/index.ts
|
|
7431
7908
|
import { mkdirSync as mkdirSync8 } from "node:fs";
|
|
7432
|
-
import { join as
|
|
7909
|
+
import { join as join29 } from "node:path";
|
|
7433
7910
|
|
|
7434
7911
|
// ../adapters/src/writers/opencode/agents.ts
|
|
7435
|
-
import { mkdir as
|
|
7436
|
-
import { join as
|
|
7912
|
+
import { mkdir as mkdir14, writeFile as writeFile22 } from "node:fs/promises";
|
|
7913
|
+
import { join as join27 } from "node:path";
|
|
7914
|
+
function getClaudeConfig3(agent) {
|
|
7915
|
+
return {
|
|
7916
|
+
tools: agent.claude?.tools ?? agent.tools,
|
|
7917
|
+
model: agent.claude?.model ?? agent.model,
|
|
7918
|
+
permissionMode: agent.claude?.permissionMode ?? agent.permissionMode
|
|
7919
|
+
};
|
|
7920
|
+
}
|
|
7437
7921
|
function mapModelToOpenCode(model) {
|
|
7438
7922
|
if (!model || model === "inherit")
|
|
7439
7923
|
return;
|
|
@@ -7465,9 +7949,10 @@ function mapToolsToOpenCode(tools) {
|
|
|
7465
7949
|
return toolsObject;
|
|
7466
7950
|
}
|
|
7467
7951
|
function generateFrontmatter3(agent) {
|
|
7952
|
+
const claude2 = getClaudeConfig3(agent);
|
|
7468
7953
|
const lines = ["---"];
|
|
7469
7954
|
lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
|
|
7470
|
-
const modelId = agent.modelId ?? mapModelToOpenCode(
|
|
7955
|
+
const modelId = agent.modelId ?? mapModelToOpenCode(claude2.model);
|
|
7471
7956
|
if (modelId) {
|
|
7472
7957
|
lines.push(`model: ${modelId}`);
|
|
7473
7958
|
}
|
|
@@ -7483,14 +7968,14 @@ function generateFrontmatter3(agent) {
|
|
|
7483
7968
|
if (agent.hidden !== undefined) {
|
|
7484
7969
|
lines.push(`hidden: ${agent.hidden}`);
|
|
7485
7970
|
}
|
|
7486
|
-
const toolsObj = agent.toolPermissions ?? mapToolsToOpenCode(
|
|
7971
|
+
const toolsObj = agent.toolPermissions ?? mapToolsToOpenCode(claude2.tools);
|
|
7487
7972
|
if (toolsObj) {
|
|
7488
7973
|
lines.push("tools:");
|
|
7489
7974
|
for (const [tool, enabled] of Object.entries(toolsObj)) {
|
|
7490
7975
|
lines.push(` ${tool}: ${enabled}`);
|
|
7491
7976
|
}
|
|
7492
7977
|
}
|
|
7493
|
-
const permissions = agent.permissions ?? mapPermissionsToOpenCode(
|
|
7978
|
+
const permissions = agent.permissions ?? mapPermissionsToOpenCode(claude2.permissionMode);
|
|
7494
7979
|
if (permissions) {
|
|
7495
7980
|
lines.push("permissions:");
|
|
7496
7981
|
for (const [key, value] of Object.entries(permissions)) {
|
|
@@ -7511,8 +7996,8 @@ function generateFrontmatter3(agent) {
|
|
|
7511
7996
|
var OpenCodeAgentsWriter = {
|
|
7512
7997
|
id: "opencode-agents",
|
|
7513
7998
|
async write(bundle, ctx) {
|
|
7514
|
-
const agentsDir =
|
|
7515
|
-
await
|
|
7999
|
+
const agentsDir = join27(ctx.projectRoot, ctx.outputPath);
|
|
8000
|
+
await mkdir14(agentsDir, { recursive: true });
|
|
7516
8001
|
const filesWritten = [];
|
|
7517
8002
|
const managedOutputs = [];
|
|
7518
8003
|
for (const agent of bundle.subagents) {
|
|
@@ -7520,9 +8005,9 @@ var OpenCodeAgentsWriter = {
|
|
|
7520
8005
|
const content = `${frontmatter}
|
|
7521
8006
|
|
|
7522
8007
|
${agent.systemPrompt}`;
|
|
7523
|
-
const agentPath =
|
|
7524
|
-
await
|
|
7525
|
-
const relativePath =
|
|
8008
|
+
const agentPath = join27(agentsDir, `${agent.name}.md`);
|
|
8009
|
+
await writeFile22(agentPath, content, "utf-8");
|
|
8010
|
+
const relativePath = join27(ctx.outputPath, `${agent.name}.md`);
|
|
7526
8011
|
filesWritten.push(relativePath);
|
|
7527
8012
|
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
7528
8013
|
}
|
|
@@ -7533,8 +8018,8 @@ ${agent.systemPrompt}`;
|
|
|
7533
8018
|
}
|
|
7534
8019
|
};
|
|
7535
8020
|
// ../adapters/src/writers/opencode/commands.ts
|
|
7536
|
-
import { mkdir as
|
|
7537
|
-
import { join as
|
|
8021
|
+
import { mkdir as mkdir15, writeFile as writeFile23 } from "node:fs/promises";
|
|
8022
|
+
import { join as join28 } from "node:path";
|
|
7538
8023
|
function generateFrontmatter4(command) {
|
|
7539
8024
|
const lines = ["---"];
|
|
7540
8025
|
lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
|
|
@@ -7551,8 +8036,8 @@ function generateFrontmatter4(command) {
|
|
|
7551
8036
|
var OpenCodeCommandsWriter = {
|
|
7552
8037
|
id: "opencode-commands",
|
|
7553
8038
|
async write(bundle, ctx) {
|
|
7554
|
-
const commandsDir =
|
|
7555
|
-
await
|
|
8039
|
+
const commandsDir = join28(ctx.projectRoot, ctx.outputPath);
|
|
8040
|
+
await mkdir15(commandsDir, { recursive: true });
|
|
7556
8041
|
const filesWritten = [];
|
|
7557
8042
|
const managedOutputs = [];
|
|
7558
8043
|
for (const command of bundle.commands) {
|
|
@@ -7560,9 +8045,9 @@ var OpenCodeCommandsWriter = {
|
|
|
7560
8045
|
const content = `${frontmatter}
|
|
7561
8046
|
|
|
7562
8047
|
${command.prompt}`;
|
|
7563
|
-
const commandPath =
|
|
7564
|
-
await
|
|
7565
|
-
const relativePath =
|
|
8048
|
+
const commandPath = join28(commandsDir, `${command.name}.md`);
|
|
8049
|
+
await writeFile23(commandPath, content, "utf-8");
|
|
8050
|
+
const relativePath = join28(ctx.outputPath, `${command.name}.md`);
|
|
7566
8051
|
filesWritten.push(relativePath);
|
|
7567
8052
|
managedOutputs.push(createManagedOutput(relativePath, this.id, content));
|
|
7568
8053
|
}
|
|
@@ -7583,7 +8068,7 @@ var opencodeAdapter = {
|
|
|
7583
8068
|
{ writer: OpenCodeCommandsWriter, outputPath: ".opencode/commands/" }
|
|
7584
8069
|
],
|
|
7585
8070
|
async init(ctx) {
|
|
7586
|
-
const opencodeDir =
|
|
8071
|
+
const opencodeDir = join29(ctx.projectRoot, ".opencode");
|
|
7587
8072
|
mkdirSync8(opencodeDir, { recursive: true });
|
|
7588
8073
|
return {
|
|
7589
8074
|
filesCreated: [".opencode/"],
|
|
@@ -7885,7 +8370,7 @@ If the capability name is omitted, it will be inferred from:
|
|
|
7885
8370
|
- For GitHub sources: the repository name or last path segment
|
|
7886
8371
|
|
|
7887
8372
|
Claude plugins (.claude-plugin/plugin.json) are automatically wrapped as OmniDev capabilities.
|
|
7888
|
-
Hooks defined in hooks.json are also supported and will be synced
|
|
8373
|
+
Hooks defined in hooks.json are also supported and will be synced into OmniDev's hook pipeline.
|
|
7889
8374
|
|
|
7890
8375
|
Examples:
|
|
7891
8376
|
omnidev add cap my-cap --github expo/skills # Uses version = "latest"
|
|
@@ -8041,8 +8526,8 @@ var addRoutes = buildRouteMap({
|
|
|
8041
8526
|
|
|
8042
8527
|
// src/commands/capability.ts
|
|
8043
8528
|
import { existsSync as existsSync25, mkdirSync as mkdirSync9 } from "node:fs";
|
|
8044
|
-
import { writeFile as
|
|
8045
|
-
import { join as
|
|
8529
|
+
import { writeFile as writeFile24 } from "node:fs/promises";
|
|
8530
|
+
import { join as join30 } from "node:path";
|
|
8046
8531
|
import { input } from "@inquirer/prompts";
|
|
8047
8532
|
init_src();
|
|
8048
8533
|
import { buildCommand as buildCommand2, buildRouteMap as buildRouteMap2 } from "@stricli/core";
|
|
@@ -8262,21 +8747,21 @@ async function runCapabilityNew(flags, capabilityId) {
|
|
|
8262
8747
|
const name = toTitleCase(id);
|
|
8263
8748
|
mkdirSync9(capabilityDir, { recursive: true });
|
|
8264
8749
|
const capabilityToml = generateCapabilityToml2({ id, name });
|
|
8265
|
-
await
|
|
8266
|
-
const skillDir =
|
|
8750
|
+
await writeFile24(join30(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
|
|
8751
|
+
const skillDir = join30(capabilityDir, "skills", "getting-started");
|
|
8267
8752
|
mkdirSync9(skillDir, { recursive: true });
|
|
8268
|
-
await
|
|
8269
|
-
const rulesDir =
|
|
8753
|
+
await writeFile24(join30(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
|
|
8754
|
+
const rulesDir = join30(capabilityDir, "rules");
|
|
8270
8755
|
mkdirSync9(rulesDir, { recursive: true });
|
|
8271
|
-
await
|
|
8272
|
-
const hooksDir =
|
|
8756
|
+
await writeFile24(join30(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
|
|
8757
|
+
const hooksDir = join30(capabilityDir, "hooks");
|
|
8273
8758
|
mkdirSync9(hooksDir, { recursive: true });
|
|
8274
|
-
await
|
|
8275
|
-
await
|
|
8276
|
-
await
|
|
8759
|
+
await writeFile24(join30(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
|
|
8760
|
+
await writeFile24(join30(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
|
|
8761
|
+
await writeFile24(join30(capabilityDir, ".gitignore"), generateGitignore(Boolean(flags.programmatic)), "utf-8");
|
|
8277
8762
|
if (flags.programmatic) {
|
|
8278
|
-
await
|
|
8279
|
-
await
|
|
8763
|
+
await writeFile24(join30(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
|
|
8764
|
+
await writeFile24(join30(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
|
|
8280
8765
|
}
|
|
8281
8766
|
console.log(`✓ Created capability: ${name}`);
|
|
8282
8767
|
console.log(` Location: ${capabilityDir}`);
|
|
@@ -8619,7 +9104,7 @@ async function checkCapabilitiesDir() {
|
|
|
8619
9104
|
// src/commands/init.ts
|
|
8620
9105
|
import { exec } from "node:child_process";
|
|
8621
9106
|
import { existsSync as existsSync27, mkdirSync as mkdirSync10 } from "node:fs";
|
|
8622
|
-
import { readFile as readFile21, writeFile as
|
|
9107
|
+
import { readFile as readFile21, writeFile as writeFile25 } from "node:fs/promises";
|
|
8623
9108
|
import { promisify as promisify2 } from "node:util";
|
|
8624
9109
|
init_src();
|
|
8625
9110
|
import { buildCommand as buildCommand4 } from "@stricli/core";
|
|
@@ -8705,7 +9190,7 @@ async function runInit(_flags, providerArg) {
|
|
|
8705
9190
|
await setActiveProfile("default");
|
|
8706
9191
|
}
|
|
8707
9192
|
if (!existsSync27("OMNI.md")) {
|
|
8708
|
-
await
|
|
9193
|
+
await writeFile25("OMNI.md", generateOmniMdTemplate(), "utf-8");
|
|
8709
9194
|
}
|
|
8710
9195
|
const config3 = await loadConfig();
|
|
8711
9196
|
const ctx = {
|
|
@@ -8798,7 +9283,7 @@ async function addToGitignore(entriesToAdd, sectionHeader) {
|
|
|
8798
9283
|
${missingEntries.join(`
|
|
8799
9284
|
`)}
|
|
8800
9285
|
`;
|
|
8801
|
-
await
|
|
9286
|
+
await writeFile25(gitignorePath, content + section, "utf-8");
|
|
8802
9287
|
}
|
|
8803
9288
|
async function getTrackedProviderFiles(files) {
|
|
8804
9289
|
const tracked = [];
|
|
@@ -9675,7 +10160,7 @@ async function buildDynamicApp() {
|
|
|
9675
10160
|
security: securityRoutes
|
|
9676
10161
|
};
|
|
9677
10162
|
debug("Core routes registered", Object.keys(routes));
|
|
9678
|
-
const configPath =
|
|
10163
|
+
const configPath = join31(process.cwd(), "omni.toml");
|
|
9679
10164
|
debug("Checking for config", { configPath, exists: existsSync32(configPath), cwd: process.cwd() });
|
|
9680
10165
|
if (existsSync32(configPath)) {
|
|
9681
10166
|
try {
|
|
@@ -9752,10 +10237,10 @@ async function loadCapabilityCommands() {
|
|
|
9752
10237
|
return commands;
|
|
9753
10238
|
}
|
|
9754
10239
|
async function loadCapabilityExport(capability3) {
|
|
9755
|
-
const capabilityPath =
|
|
9756
|
-
const builtIndexPath =
|
|
9757
|
-
const jsIndexPath =
|
|
9758
|
-
const tsIndexPath =
|
|
10240
|
+
const capabilityPath = join31(process.cwd(), capability3.path);
|
|
10241
|
+
const builtIndexPath = join31(capabilityPath, "dist", "index.js");
|
|
10242
|
+
const jsIndexPath = join31(capabilityPath, "index.js");
|
|
10243
|
+
const tsIndexPath = join31(capabilityPath, "index.ts");
|
|
9759
10244
|
debug(`Checking entry points for '${capability3.id}'`, {
|
|
9760
10245
|
capabilityPath,
|
|
9761
10246
|
builtIndexPath,
|