@omnidev-ai/cli 0.13.4 → 0.14.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 +1556 -367
- package/package.json +5 -2
package/dist/index.js
CHANGED
|
@@ -64,18 +64,25 @@ function parseFrontmatterWithMarkdown(content) {
|
|
|
64
64
|
// ../core/src/capability/commands.ts
|
|
65
65
|
import { existsSync, readdirSync } from "node:fs";
|
|
66
66
|
import { readFile } from "node:fs/promises";
|
|
67
|
-
import { join
|
|
67
|
+
import { basename, join } from "node:path";
|
|
68
68
|
async function loadCommands(capabilityPath, capabilityId) {
|
|
69
|
-
const commandsDir = join2(capabilityPath, "commands");
|
|
70
|
-
if (!existsSync(commandsDir)) {
|
|
71
|
-
return [];
|
|
72
|
-
}
|
|
73
69
|
const commands = [];
|
|
74
|
-
const
|
|
75
|
-
for (const
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
70
|
+
const possibleDirNames = ["commands", "command"];
|
|
71
|
+
for (const dirName of possibleDirNames) {
|
|
72
|
+
const dir = join(capabilityPath, dirName);
|
|
73
|
+
if (!existsSync(dir)) {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
const entries = readdirSync(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
77
|
+
for (const entry of entries) {
|
|
78
|
+
if (entry.isDirectory()) {
|
|
79
|
+
const commandPath = join(dir, entry.name, "COMMAND.md");
|
|
80
|
+
if (existsSync(commandPath)) {
|
|
81
|
+
const command = await parseCommandFile(commandPath, capabilityId);
|
|
82
|
+
commands.push(command);
|
|
83
|
+
}
|
|
84
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
85
|
+
const commandPath = join(dir, entry.name);
|
|
79
86
|
const command = await parseCommandFile(commandPath, capabilityId);
|
|
80
87
|
commands.push(command);
|
|
81
88
|
}
|
|
@@ -91,11 +98,13 @@ async function parseCommandFile(filePath, capabilityId) {
|
|
|
91
98
|
}
|
|
92
99
|
const frontmatter = parsed.frontmatter;
|
|
93
100
|
const prompt = parsed.markdown;
|
|
94
|
-
|
|
101
|
+
const inferredName = basename(filePath, ".md").replace(/^COMMAND$/i, "");
|
|
102
|
+
const name = frontmatter.name || inferredName;
|
|
103
|
+
if (!name || !frontmatter.description) {
|
|
95
104
|
throw new Error(`Invalid COMMAND.md at ${filePath}: name and description required`);
|
|
96
105
|
}
|
|
97
106
|
const result = {
|
|
98
|
-
name
|
|
107
|
+
name,
|
|
99
108
|
description: frontmatter.description,
|
|
100
109
|
prompt: prompt.trim(),
|
|
101
110
|
capabilityId
|
|
@@ -110,10 +119,10 @@ var init_commands = () => {};
|
|
|
110
119
|
// ../core/src/capability/docs.ts
|
|
111
120
|
import { existsSync as existsSync2, readdirSync as readdirSync2 } from "node:fs";
|
|
112
121
|
import { readFile as readFile2 } from "node:fs/promises";
|
|
113
|
-
import { basename, join as
|
|
122
|
+
import { basename as basename2, join as join2 } from "node:path";
|
|
114
123
|
async function loadDocs(capabilityPath, capabilityId) {
|
|
115
124
|
const docs = [];
|
|
116
|
-
const definitionPath =
|
|
125
|
+
const definitionPath = join2(capabilityPath, "definition.md");
|
|
117
126
|
if (existsSync2(definitionPath)) {
|
|
118
127
|
const content = await readFile2(definitionPath, "utf-8");
|
|
119
128
|
docs.push({
|
|
@@ -122,15 +131,15 @@ async function loadDocs(capabilityPath, capabilityId) {
|
|
|
122
131
|
capabilityId
|
|
123
132
|
});
|
|
124
133
|
}
|
|
125
|
-
const docsDir =
|
|
134
|
+
const docsDir = join2(capabilityPath, "docs");
|
|
126
135
|
if (existsSync2(docsDir)) {
|
|
127
136
|
const entries = readdirSync2(docsDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
128
137
|
for (const entry of entries) {
|
|
129
138
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
130
|
-
const docPath =
|
|
139
|
+
const docPath = join2(docsDir, entry.name);
|
|
131
140
|
const content = await readFile2(docPath, "utf-8");
|
|
132
141
|
docs.push({
|
|
133
|
-
name:
|
|
142
|
+
name: basename2(entry.name, ".md"),
|
|
134
143
|
content: content.trim(),
|
|
135
144
|
capabilityId
|
|
136
145
|
});
|
|
@@ -1057,6 +1066,151 @@ var init_parse = __esm(() => {
|
|
|
1057
1066
|
});
|
|
1058
1067
|
|
|
1059
1068
|
// ../../node_modules/.bun/smol-toml@1.6.0/node_modules/smol-toml/dist/stringify.js
|
|
1069
|
+
function extendedTypeOf(obj) {
|
|
1070
|
+
let type = typeof obj;
|
|
1071
|
+
if (type === "object") {
|
|
1072
|
+
if (Array.isArray(obj))
|
|
1073
|
+
return "array";
|
|
1074
|
+
if (obj instanceof Date)
|
|
1075
|
+
return "date";
|
|
1076
|
+
}
|
|
1077
|
+
return type;
|
|
1078
|
+
}
|
|
1079
|
+
function isArrayOfTables(obj) {
|
|
1080
|
+
for (let i = 0;i < obj.length; i++) {
|
|
1081
|
+
if (extendedTypeOf(obj[i]) !== "object")
|
|
1082
|
+
return false;
|
|
1083
|
+
}
|
|
1084
|
+
return obj.length != 0;
|
|
1085
|
+
}
|
|
1086
|
+
function formatString(s) {
|
|
1087
|
+
return JSON.stringify(s).replace(/\x7f/g, "\\u007f");
|
|
1088
|
+
}
|
|
1089
|
+
function stringifyValue(val, type, depth, numberAsFloat) {
|
|
1090
|
+
if (depth === 0) {
|
|
1091
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
1092
|
+
}
|
|
1093
|
+
if (type === "number") {
|
|
1094
|
+
if (isNaN(val))
|
|
1095
|
+
return "nan";
|
|
1096
|
+
if (val === Infinity)
|
|
1097
|
+
return "inf";
|
|
1098
|
+
if (val === -Infinity)
|
|
1099
|
+
return "-inf";
|
|
1100
|
+
if (numberAsFloat && Number.isInteger(val))
|
|
1101
|
+
return val.toFixed(1);
|
|
1102
|
+
return val.toString();
|
|
1103
|
+
}
|
|
1104
|
+
if (type === "bigint" || type === "boolean") {
|
|
1105
|
+
return val.toString();
|
|
1106
|
+
}
|
|
1107
|
+
if (type === "string") {
|
|
1108
|
+
return formatString(val);
|
|
1109
|
+
}
|
|
1110
|
+
if (type === "date") {
|
|
1111
|
+
if (isNaN(val.getTime())) {
|
|
1112
|
+
throw new TypeError("cannot serialize invalid date");
|
|
1113
|
+
}
|
|
1114
|
+
return val.toISOString();
|
|
1115
|
+
}
|
|
1116
|
+
if (type === "object") {
|
|
1117
|
+
return stringifyInlineTable(val, depth, numberAsFloat);
|
|
1118
|
+
}
|
|
1119
|
+
if (type === "array") {
|
|
1120
|
+
return stringifyArray(val, depth, numberAsFloat);
|
|
1121
|
+
}
|
|
1122
|
+
}
|
|
1123
|
+
function stringifyInlineTable(obj, depth, numberAsFloat) {
|
|
1124
|
+
let keys = Object.keys(obj);
|
|
1125
|
+
if (keys.length === 0)
|
|
1126
|
+
return "{}";
|
|
1127
|
+
let res = "{ ";
|
|
1128
|
+
for (let i = 0;i < keys.length; i++) {
|
|
1129
|
+
let k = keys[i];
|
|
1130
|
+
if (i)
|
|
1131
|
+
res += ", ";
|
|
1132
|
+
res += BARE_KEY.test(k) ? k : formatString(k);
|
|
1133
|
+
res += " = ";
|
|
1134
|
+
res += stringifyValue(obj[k], extendedTypeOf(obj[k]), depth - 1, numberAsFloat);
|
|
1135
|
+
}
|
|
1136
|
+
return res + " }";
|
|
1137
|
+
}
|
|
1138
|
+
function stringifyArray(array, depth, numberAsFloat) {
|
|
1139
|
+
if (array.length === 0)
|
|
1140
|
+
return "[]";
|
|
1141
|
+
let res = "[ ";
|
|
1142
|
+
for (let i = 0;i < array.length; i++) {
|
|
1143
|
+
if (i)
|
|
1144
|
+
res += ", ";
|
|
1145
|
+
if (array[i] === null || array[i] === undefined) {
|
|
1146
|
+
throw new TypeError("arrays cannot contain null or undefined values");
|
|
1147
|
+
}
|
|
1148
|
+
res += stringifyValue(array[i], extendedTypeOf(array[i]), depth - 1, numberAsFloat);
|
|
1149
|
+
}
|
|
1150
|
+
return res + " ]";
|
|
1151
|
+
}
|
|
1152
|
+
function stringifyArrayTable(array, key, depth, numberAsFloat) {
|
|
1153
|
+
if (depth === 0) {
|
|
1154
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
1155
|
+
}
|
|
1156
|
+
let res = "";
|
|
1157
|
+
for (let i = 0;i < array.length; i++) {
|
|
1158
|
+
res += `${res && `
|
|
1159
|
+
`}[[${key}]]
|
|
1160
|
+
`;
|
|
1161
|
+
res += stringifyTable(0, array[i], key, depth, numberAsFloat);
|
|
1162
|
+
}
|
|
1163
|
+
return res;
|
|
1164
|
+
}
|
|
1165
|
+
function stringifyTable(tableKey, obj, prefix, depth, numberAsFloat) {
|
|
1166
|
+
if (depth === 0) {
|
|
1167
|
+
throw new Error("Could not stringify the object: maximum object depth exceeded");
|
|
1168
|
+
}
|
|
1169
|
+
let preamble = "";
|
|
1170
|
+
let tables = "";
|
|
1171
|
+
let keys = Object.keys(obj);
|
|
1172
|
+
for (let i = 0;i < keys.length; i++) {
|
|
1173
|
+
let k = keys[i];
|
|
1174
|
+
if (obj[k] !== null && obj[k] !== undefined) {
|
|
1175
|
+
let type = extendedTypeOf(obj[k]);
|
|
1176
|
+
if (type === "symbol" || type === "function") {
|
|
1177
|
+
throw new TypeError(`cannot serialize values of type '${type}'`);
|
|
1178
|
+
}
|
|
1179
|
+
let key = BARE_KEY.test(k) ? k : formatString(k);
|
|
1180
|
+
if (type === "array" && isArrayOfTables(obj[k])) {
|
|
1181
|
+
tables += (tables && `
|
|
1182
|
+
`) + stringifyArrayTable(obj[k], prefix ? `${prefix}.${key}` : key, depth - 1, numberAsFloat);
|
|
1183
|
+
} else if (type === "object") {
|
|
1184
|
+
let tblKey = prefix ? `${prefix}.${key}` : key;
|
|
1185
|
+
tables += (tables && `
|
|
1186
|
+
`) + stringifyTable(tblKey, obj[k], tblKey, depth - 1, numberAsFloat);
|
|
1187
|
+
} else {
|
|
1188
|
+
preamble += key;
|
|
1189
|
+
preamble += " = ";
|
|
1190
|
+
preamble += stringifyValue(obj[k], type, depth, numberAsFloat);
|
|
1191
|
+
preamble += `
|
|
1192
|
+
`;
|
|
1193
|
+
}
|
|
1194
|
+
}
|
|
1195
|
+
}
|
|
1196
|
+
if (tableKey && (preamble || !tables))
|
|
1197
|
+
preamble = preamble ? `[${tableKey}]
|
|
1198
|
+
${preamble}` : `[${tableKey}]`;
|
|
1199
|
+
return preamble && tables ? `${preamble}
|
|
1200
|
+
${tables}` : preamble || tables;
|
|
1201
|
+
}
|
|
1202
|
+
function stringify(obj, { maxDepth = 1000, numbersAsFloat = false } = {}) {
|
|
1203
|
+
if (extendedTypeOf(obj) !== "object") {
|
|
1204
|
+
throw new TypeError("stringify can only be called with an object");
|
|
1205
|
+
}
|
|
1206
|
+
let str = stringifyTable(0, obj, "", maxDepth, numbersAsFloat);
|
|
1207
|
+
if (str[str.length - 1] !== `
|
|
1208
|
+
`)
|
|
1209
|
+
return str + `
|
|
1210
|
+
`;
|
|
1211
|
+
return str;
|
|
1212
|
+
}
|
|
1213
|
+
var BARE_KEY;
|
|
1060
1214
|
var init_stringify = __esm(() => {
|
|
1061
1215
|
/*!
|
|
1062
1216
|
* Copyright (c) Squirrel Chat et al., All rights reserved.
|
|
@@ -1085,6 +1239,7 @@ var init_stringify = __esm(() => {
|
|
|
1085
1239
|
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
1086
1240
|
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
1087
1241
|
*/
|
|
1242
|
+
BARE_KEY = /^[a-z0-9-_]+$/i;
|
|
1088
1243
|
});
|
|
1089
1244
|
|
|
1090
1245
|
// ../../node_modules/.bun/smol-toml@1.6.0/node_modules/smol-toml/dist/index.js
|
|
@@ -1162,7 +1317,7 @@ var init_parser = __esm(() => {
|
|
|
1162
1317
|
});
|
|
1163
1318
|
|
|
1164
1319
|
// ../core/src/hooks/constants.ts
|
|
1165
|
-
var HOOK_EVENTS, MATCHER_EVENTS, PROMPT_HOOK_EVENTS, HOOK_TYPES, COMMON_TOOL_MATCHERS, NOTIFICATION_MATCHERS, SESSION_START_MATCHERS, PRE_COMPACT_MATCHERS, DEFAULT_COMMAND_TIMEOUT = 60, DEFAULT_PROMPT_TIMEOUT = 30, VARIABLE_MAPPINGS, HOOKS_CONFIG_FILENAME = "hooks.toml", HOOKS_DIRECTORY = "hooks";
|
|
1320
|
+
var HOOK_EVENTS, MATCHER_EVENTS, PROMPT_HOOK_EVENTS, HOOK_TYPES, COMMON_TOOL_MATCHERS, NOTIFICATION_MATCHERS, SESSION_START_MATCHERS, PRE_COMPACT_MATCHERS, DEFAULT_COMMAND_TIMEOUT = 60, DEFAULT_PROMPT_TIMEOUT = 30, VARIABLE_MAPPINGS, HOOKS_CONFIG_FILENAME = "hooks.toml", CLAUDE_HOOKS_CONFIG_FILENAME = "hooks.json", HOOKS_DIRECTORY = "hooks";
|
|
1166
1321
|
var init_constants = __esm(() => {
|
|
1167
1322
|
HOOK_EVENTS = [
|
|
1168
1323
|
"PreToolUse",
|
|
@@ -1698,34 +1853,369 @@ function containsOmnidevVariables(content) {
|
|
|
1698
1853
|
}
|
|
1699
1854
|
return false;
|
|
1700
1855
|
}
|
|
1856
|
+
function resolveCapabilityRoot(content, capabilityPath) {
|
|
1857
|
+
let result = content;
|
|
1858
|
+
const variables = ["OMNIDEV_CAPABILITY_ROOT", "CLAUDE_PLUGIN_ROOT"];
|
|
1859
|
+
for (const varName of variables) {
|
|
1860
|
+
result = result.replace(new RegExp(`\\$\\{${varName}\\}`, "g"), capabilityPath);
|
|
1861
|
+
result = result.replace(new RegExp(`\\$${varName}(?![A-Za-z0-9_])`, "g"), capabilityPath);
|
|
1862
|
+
}
|
|
1863
|
+
return result;
|
|
1864
|
+
}
|
|
1865
|
+
function resolveCapabilityRootInConfig(config, capabilityPath) {
|
|
1866
|
+
const result = {};
|
|
1867
|
+
if (config.description !== undefined) {
|
|
1868
|
+
result.description = config.description;
|
|
1869
|
+
}
|
|
1870
|
+
const events = [
|
|
1871
|
+
"PreToolUse",
|
|
1872
|
+
"PostToolUse",
|
|
1873
|
+
"PermissionRequest",
|
|
1874
|
+
"UserPromptSubmit",
|
|
1875
|
+
"Stop",
|
|
1876
|
+
"SubagentStop",
|
|
1877
|
+
"Notification",
|
|
1878
|
+
"SessionStart",
|
|
1879
|
+
"SessionEnd",
|
|
1880
|
+
"PreCompact"
|
|
1881
|
+
];
|
|
1882
|
+
for (const event of events) {
|
|
1883
|
+
const matchers = config[event];
|
|
1884
|
+
if (matchers) {
|
|
1885
|
+
result[event] = matchers.map((matcher) => ({
|
|
1886
|
+
...matcher,
|
|
1887
|
+
hooks: matcher.hooks.map((hook) => {
|
|
1888
|
+
if (hook.type === "command") {
|
|
1889
|
+
return {
|
|
1890
|
+
...hook,
|
|
1891
|
+
command: resolveCapabilityRoot(hook.command, capabilityPath)
|
|
1892
|
+
};
|
|
1893
|
+
}
|
|
1894
|
+
if (hook.type === "prompt") {
|
|
1895
|
+
return {
|
|
1896
|
+
...hook,
|
|
1897
|
+
prompt: resolveCapabilityRoot(hook.prompt, capabilityPath)
|
|
1898
|
+
};
|
|
1899
|
+
}
|
|
1900
|
+
return hook;
|
|
1901
|
+
})
|
|
1902
|
+
}));
|
|
1903
|
+
}
|
|
1904
|
+
}
|
|
1905
|
+
return result;
|
|
1906
|
+
}
|
|
1701
1907
|
var REVERSE_MAPPINGS;
|
|
1702
1908
|
var init_variables = __esm(() => {
|
|
1703
1909
|
init_constants();
|
|
1704
1910
|
REVERSE_MAPPINGS = Object.fromEntries(Object.entries(VARIABLE_MAPPINGS).map(([omni, claude]) => [claude, omni]));
|
|
1705
1911
|
});
|
|
1706
1912
|
|
|
1707
|
-
// ../core/src/hooks/loader.ts
|
|
1913
|
+
// ../core/src/hooks/json-loader.ts
|
|
1708
1914
|
import { existsSync as existsSync4, readFileSync } from "node:fs";
|
|
1709
|
-
|
|
1915
|
+
function loadHooksJson(configPath) {
|
|
1916
|
+
const unknownFieldWarnings = [];
|
|
1917
|
+
if (!existsSync4(configPath)) {
|
|
1918
|
+
return {
|
|
1919
|
+
config: createEmptyHooksConfig(),
|
|
1920
|
+
validation: createEmptyValidationResult(),
|
|
1921
|
+
found: false,
|
|
1922
|
+
configPath,
|
|
1923
|
+
unknownFieldWarnings: []
|
|
1924
|
+
};
|
|
1925
|
+
}
|
|
1926
|
+
let rawContent;
|
|
1927
|
+
try {
|
|
1928
|
+
rawContent = readFileSync(configPath, "utf-8");
|
|
1929
|
+
} catch (error) {
|
|
1930
|
+
return {
|
|
1931
|
+
config: createEmptyHooksConfig(),
|
|
1932
|
+
validation: {
|
|
1933
|
+
valid: false,
|
|
1934
|
+
errors: [
|
|
1935
|
+
{
|
|
1936
|
+
severity: "error",
|
|
1937
|
+
code: "HOOKS_INVALID_TOML",
|
|
1938
|
+
message: `Failed to read hooks.json: ${error instanceof Error ? error.message : String(error)}`,
|
|
1939
|
+
path: configPath
|
|
1940
|
+
}
|
|
1941
|
+
],
|
|
1942
|
+
warnings: []
|
|
1943
|
+
},
|
|
1944
|
+
found: true,
|
|
1945
|
+
configPath,
|
|
1946
|
+
loadError: `Failed to read: ${error instanceof Error ? error.message : String(error)}`,
|
|
1947
|
+
unknownFieldWarnings: []
|
|
1948
|
+
};
|
|
1949
|
+
}
|
|
1950
|
+
let parsed;
|
|
1951
|
+
try {
|
|
1952
|
+
parsed = JSON.parse(rawContent);
|
|
1953
|
+
} catch (error) {
|
|
1954
|
+
return {
|
|
1955
|
+
config: createEmptyHooksConfig(),
|
|
1956
|
+
validation: {
|
|
1957
|
+
valid: false,
|
|
1958
|
+
errors: [
|
|
1959
|
+
{
|
|
1960
|
+
severity: "error",
|
|
1961
|
+
code: "HOOKS_INVALID_TOML",
|
|
1962
|
+
message: `Invalid JSON syntax: ${error instanceof Error ? error.message : String(error)}`,
|
|
1963
|
+
path: configPath
|
|
1964
|
+
}
|
|
1965
|
+
],
|
|
1966
|
+
warnings: []
|
|
1967
|
+
},
|
|
1968
|
+
found: true,
|
|
1969
|
+
configPath,
|
|
1970
|
+
loadError: `Invalid JSON: ${error instanceof Error ? error.message : String(error)}`,
|
|
1971
|
+
unknownFieldWarnings: []
|
|
1972
|
+
};
|
|
1973
|
+
}
|
|
1974
|
+
const result = convertClaudeHooksToConfig(parsed, unknownFieldWarnings);
|
|
1975
|
+
return {
|
|
1976
|
+
config: result.config,
|
|
1977
|
+
validation: result.validation,
|
|
1978
|
+
found: true,
|
|
1979
|
+
configPath,
|
|
1980
|
+
unknownFieldWarnings
|
|
1981
|
+
};
|
|
1982
|
+
}
|
|
1983
|
+
function convertClaudeHooksToConfig(claudeHooks, unknownFieldWarnings) {
|
|
1984
|
+
const config = {};
|
|
1985
|
+
const errors = [];
|
|
1986
|
+
const warnings = [];
|
|
1987
|
+
if (typeof claudeHooks !== "object" || claudeHooks === null || Array.isArray(claudeHooks)) {
|
|
1988
|
+
errors.push({
|
|
1989
|
+
severity: "error",
|
|
1990
|
+
code: "HOOKS_INVALID_TOML",
|
|
1991
|
+
message: "hooks.json must be an object"
|
|
1992
|
+
});
|
|
1993
|
+
return { config: createEmptyHooksConfig(), validation: { valid: false, errors, warnings } };
|
|
1994
|
+
}
|
|
1995
|
+
for (const [eventName, matchers] of Object.entries(claudeHooks)) {
|
|
1996
|
+
if (!isHookEvent(eventName)) {
|
|
1997
|
+
unknownFieldWarnings.push(`Unknown event "${eventName}" in hooks.json. Valid events: ${HOOK_EVENTS.join(", ")}`);
|
|
1998
|
+
continue;
|
|
1999
|
+
}
|
|
2000
|
+
const event = eventName;
|
|
2001
|
+
if (!Array.isArray(matchers)) {
|
|
2002
|
+
errors.push({
|
|
2003
|
+
severity: "error",
|
|
2004
|
+
code: "HOOKS_INVALID_TOML",
|
|
2005
|
+
event,
|
|
2006
|
+
message: `${event} must be an array of matchers`
|
|
2007
|
+
});
|
|
2008
|
+
continue;
|
|
2009
|
+
}
|
|
2010
|
+
const convertedMatchers = [];
|
|
2011
|
+
for (let i = 0;i < matchers.length; i++) {
|
|
2012
|
+
const matcher = matchers[i];
|
|
2013
|
+
if (!matcher)
|
|
2014
|
+
continue;
|
|
2015
|
+
if (typeof matcher === "object" && matcher !== null) {
|
|
2016
|
+
for (const key of Object.keys(matcher)) {
|
|
2017
|
+
if (!KNOWN_MATCHER_FIELDS.has(key)) {
|
|
2018
|
+
unknownFieldWarnings.push(`Unknown field "${key}" in ${event}[${i}]. Known fields: ${[...KNOWN_MATCHER_FIELDS].join(", ")}`);
|
|
2019
|
+
}
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
const convertedMatcher = convertMatcher(matcher, event, i, errors, unknownFieldWarnings);
|
|
2023
|
+
if (convertedMatcher) {
|
|
2024
|
+
convertedMatchers.push(convertedMatcher);
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
if (convertedMatchers.length > 0) {
|
|
2028
|
+
config[event] = convertedMatchers;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
return {
|
|
2032
|
+
config,
|
|
2033
|
+
validation: {
|
|
2034
|
+
valid: errors.length === 0,
|
|
2035
|
+
errors,
|
|
2036
|
+
warnings
|
|
2037
|
+
}
|
|
2038
|
+
};
|
|
2039
|
+
}
|
|
2040
|
+
function convertMatcher(matcher, event, matcherIndex, errors, unknownFieldWarnings) {
|
|
2041
|
+
if (typeof matcher !== "object" || matcher === null || Array.isArray(matcher)) {
|
|
2042
|
+
errors.push({
|
|
2043
|
+
severity: "error",
|
|
2044
|
+
code: "HOOKS_INVALID_TOML",
|
|
2045
|
+
event,
|
|
2046
|
+
matcherIndex,
|
|
2047
|
+
message: `Matcher at index ${matcherIndex} must be an object`
|
|
2048
|
+
});
|
|
2049
|
+
return null;
|
|
2050
|
+
}
|
|
2051
|
+
const hooks = [];
|
|
2052
|
+
const hooksArray = matcher.hooks;
|
|
2053
|
+
if (!hooksArray) {
|
|
2054
|
+
errors.push({
|
|
2055
|
+
severity: "error",
|
|
2056
|
+
code: "HOOKS_INVALID_HOOKS_ARRAY",
|
|
2057
|
+
event,
|
|
2058
|
+
matcherIndex,
|
|
2059
|
+
message: "Matcher must have a 'hooks' array"
|
|
2060
|
+
});
|
|
2061
|
+
return null;
|
|
2062
|
+
}
|
|
2063
|
+
if (!Array.isArray(hooksArray)) {
|
|
2064
|
+
errors.push({
|
|
2065
|
+
severity: "error",
|
|
2066
|
+
code: "HOOKS_INVALID_HOOKS_ARRAY",
|
|
2067
|
+
event,
|
|
2068
|
+
matcherIndex,
|
|
2069
|
+
message: "'hooks' must be an array"
|
|
2070
|
+
});
|
|
2071
|
+
return null;
|
|
2072
|
+
}
|
|
2073
|
+
for (let i = 0;i < hooksArray.length; i++) {
|
|
2074
|
+
const hookEntry = hooksArray[i];
|
|
2075
|
+
if (!hookEntry)
|
|
2076
|
+
continue;
|
|
2077
|
+
if (typeof hookEntry === "object" && hookEntry !== null) {
|
|
2078
|
+
for (const key of Object.keys(hookEntry)) {
|
|
2079
|
+
if (!KNOWN_HOOK_FIELDS.has(key)) {
|
|
2080
|
+
unknownFieldWarnings.push(`Unknown field "${key}" in ${event}[${matcherIndex}].hooks[${i}]. Known fields: ${[...KNOWN_HOOK_FIELDS].join(", ")}`);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
}
|
|
2084
|
+
const hook = convertHook(hookEntry, event, matcherIndex, i, errors);
|
|
2085
|
+
if (hook) {
|
|
2086
|
+
hooks.push(hook);
|
|
2087
|
+
}
|
|
2088
|
+
}
|
|
2089
|
+
if (hooks.length === 0) {
|
|
2090
|
+
return null;
|
|
2091
|
+
}
|
|
2092
|
+
const result = { hooks };
|
|
2093
|
+
if (matcher.matcher !== undefined) {
|
|
2094
|
+
result.matcher = matcher.matcher;
|
|
2095
|
+
}
|
|
2096
|
+
return result;
|
|
2097
|
+
}
|
|
2098
|
+
function convertHook(hookEntry, event, matcherIndex, hookIndex, errors) {
|
|
2099
|
+
if (typeof hookEntry !== "object" || hookEntry === null || Array.isArray(hookEntry)) {
|
|
2100
|
+
errors.push({
|
|
2101
|
+
severity: "error",
|
|
2102
|
+
code: "HOOKS_INVALID_TOML",
|
|
2103
|
+
event,
|
|
2104
|
+
matcherIndex,
|
|
2105
|
+
hookIndex,
|
|
2106
|
+
message: "Hook must be an object"
|
|
2107
|
+
});
|
|
2108
|
+
return null;
|
|
2109
|
+
}
|
|
2110
|
+
const hookType = hookEntry.type;
|
|
2111
|
+
if (!hookType) {
|
|
2112
|
+
errors.push({
|
|
2113
|
+
severity: "error",
|
|
2114
|
+
code: "HOOKS_INVALID_TYPE",
|
|
2115
|
+
event,
|
|
2116
|
+
matcherIndex,
|
|
2117
|
+
hookIndex,
|
|
2118
|
+
message: "Hook must have a 'type' field"
|
|
2119
|
+
});
|
|
2120
|
+
return null;
|
|
2121
|
+
}
|
|
2122
|
+
if (!isHookType(hookType)) {
|
|
2123
|
+
errors.push({
|
|
2124
|
+
severity: "error",
|
|
2125
|
+
code: "HOOKS_INVALID_TYPE",
|
|
2126
|
+
event,
|
|
2127
|
+
matcherIndex,
|
|
2128
|
+
hookIndex,
|
|
2129
|
+
message: `Invalid hook type: "${hookType}". Must be "command" or "prompt"`
|
|
2130
|
+
});
|
|
2131
|
+
return null;
|
|
2132
|
+
}
|
|
2133
|
+
if (hookType === "command") {
|
|
2134
|
+
if (typeof hookEntry.command !== "string") {
|
|
2135
|
+
errors.push({
|
|
2136
|
+
severity: "error",
|
|
2137
|
+
code: "HOOKS_MISSING_COMMAND",
|
|
2138
|
+
event,
|
|
2139
|
+
matcherIndex,
|
|
2140
|
+
hookIndex,
|
|
2141
|
+
message: "Command hook must have a 'command' string field"
|
|
2142
|
+
});
|
|
2143
|
+
return null;
|
|
2144
|
+
}
|
|
2145
|
+
const hook = {
|
|
2146
|
+
type: "command",
|
|
2147
|
+
command: hookEntry.command
|
|
2148
|
+
};
|
|
2149
|
+
if (typeof hookEntry.timeout === "number") {
|
|
2150
|
+
hook.timeout = hookEntry.timeout;
|
|
2151
|
+
}
|
|
2152
|
+
return hook;
|
|
2153
|
+
}
|
|
2154
|
+
if (hookType === "prompt") {
|
|
2155
|
+
if (typeof hookEntry.prompt !== "string") {
|
|
2156
|
+
errors.push({
|
|
2157
|
+
severity: "error",
|
|
2158
|
+
code: "HOOKS_MISSING_PROMPT",
|
|
2159
|
+
event,
|
|
2160
|
+
matcherIndex,
|
|
2161
|
+
hookIndex,
|
|
2162
|
+
message: "Prompt hook must have a 'prompt' string field"
|
|
2163
|
+
});
|
|
2164
|
+
return null;
|
|
2165
|
+
}
|
|
2166
|
+
const hook = {
|
|
2167
|
+
type: "prompt",
|
|
2168
|
+
prompt: hookEntry.prompt
|
|
2169
|
+
};
|
|
2170
|
+
if (typeof hookEntry.timeout === "number") {
|
|
2171
|
+
hook.timeout = hookEntry.timeout;
|
|
2172
|
+
}
|
|
2173
|
+
return hook;
|
|
2174
|
+
}
|
|
2175
|
+
return null;
|
|
2176
|
+
}
|
|
2177
|
+
var KNOWN_HOOK_FIELDS, KNOWN_MATCHER_FIELDS;
|
|
2178
|
+
var init_json_loader = __esm(() => {
|
|
2179
|
+
init_constants();
|
|
2180
|
+
init_types();
|
|
2181
|
+
init_validation();
|
|
2182
|
+
KNOWN_HOOK_FIELDS = new Set(["type", "command", "prompt", "timeout"]);
|
|
2183
|
+
KNOWN_MATCHER_FIELDS = new Set(["matcher", "hooks"]);
|
|
2184
|
+
});
|
|
2185
|
+
|
|
2186
|
+
// ../core/src/hooks/loader.ts
|
|
2187
|
+
import { existsSync as existsSync5, readFileSync as readFileSync2 } from "node:fs";
|
|
2188
|
+
import { join as join3 } from "node:path";
|
|
1710
2189
|
function loadHooksFromCapability(capabilityPath, options) {
|
|
1711
2190
|
const opts = {
|
|
1712
2191
|
transformVariables: true,
|
|
1713
2192
|
validate: true,
|
|
1714
2193
|
checkScripts: false,
|
|
2194
|
+
resolveCapabilityRoot: false,
|
|
1715
2195
|
...options
|
|
1716
2196
|
};
|
|
1717
|
-
const hooksDir =
|
|
1718
|
-
const
|
|
1719
|
-
if (
|
|
2197
|
+
const hooksDir = join3(capabilityPath, HOOKS_DIRECTORY);
|
|
2198
|
+
const tomlConfigPath = join3(hooksDir, HOOKS_CONFIG_FILENAME);
|
|
2199
|
+
if (existsSync5(tomlConfigPath)) {
|
|
2200
|
+
return loadTomlHooks(capabilityPath, tomlConfigPath, hooksDir, opts);
|
|
2201
|
+
}
|
|
2202
|
+
const hooksJsonInDir = join3(hooksDir, CLAUDE_HOOKS_CONFIG_FILENAME);
|
|
2203
|
+
const hooksJsonAtRoot = join3(capabilityPath, CLAUDE_HOOKS_CONFIG_FILENAME);
|
|
2204
|
+
const hooksJsonDirExists = existsSync5(hooksJsonInDir);
|
|
2205
|
+
const hooksJsonRootExists = existsSync5(hooksJsonAtRoot);
|
|
2206
|
+
if (!hooksJsonDirExists && !hooksJsonRootExists) {
|
|
1720
2207
|
return {
|
|
1721
2208
|
config: createEmptyHooksConfig(),
|
|
1722
2209
|
validation: createEmptyValidationResult(),
|
|
1723
2210
|
found: false
|
|
1724
2211
|
};
|
|
1725
2212
|
}
|
|
2213
|
+
return loadJsonHooksFiles(capabilityPath, hooksJsonInDir, hooksJsonAtRoot, hooksDir, opts);
|
|
2214
|
+
}
|
|
2215
|
+
function loadTomlHooks(capabilityPath, configPath, hooksDir, opts) {
|
|
1726
2216
|
let rawContent;
|
|
1727
2217
|
try {
|
|
1728
|
-
rawContent =
|
|
2218
|
+
rawContent = readFileSync2(configPath, "utf-8");
|
|
1729
2219
|
} catch (error) {
|
|
1730
2220
|
return {
|
|
1731
2221
|
config: createEmptyHooksConfig(),
|
|
@@ -1782,13 +2272,102 @@ function loadHooksFromCapability(capabilityPath, options) {
|
|
|
1782
2272
|
} else {
|
|
1783
2273
|
validation = createEmptyValidationResult();
|
|
1784
2274
|
}
|
|
2275
|
+
let config = validation.valid ? parsed : createEmptyHooksConfig();
|
|
2276
|
+
if (opts.resolveCapabilityRoot && validation.valid) {
|
|
2277
|
+
config = resolveCapabilityRootInConfig(config, capabilityPath);
|
|
2278
|
+
}
|
|
1785
2279
|
return {
|
|
1786
|
-
config
|
|
2280
|
+
config,
|
|
1787
2281
|
validation,
|
|
1788
2282
|
found: true,
|
|
1789
2283
|
configPath
|
|
1790
2284
|
};
|
|
1791
2285
|
}
|
|
2286
|
+
function loadJsonHooksFiles(capabilityPath, hooksJsonInDir, hooksJsonAtRoot, hooksDir, opts) {
|
|
2287
|
+
const configs = [];
|
|
2288
|
+
const allErrors = [];
|
|
2289
|
+
const allWarnings = [];
|
|
2290
|
+
const unknownFieldWarnings = [];
|
|
2291
|
+
let foundPath;
|
|
2292
|
+
if (existsSync5(hooksJsonInDir)) {
|
|
2293
|
+
const result2 = loadHooksJson(hooksJsonInDir);
|
|
2294
|
+
if (result2.found) {
|
|
2295
|
+
foundPath = result2.configPath;
|
|
2296
|
+
if (result2.loadError) {
|
|
2297
|
+
allErrors.push(...result2.validation.errors);
|
|
2298
|
+
} else {
|
|
2299
|
+
configs.push(result2.config);
|
|
2300
|
+
allErrors.push(...result2.validation.errors);
|
|
2301
|
+
allWarnings.push(...result2.validation.warnings);
|
|
2302
|
+
}
|
|
2303
|
+
unknownFieldWarnings.push(...result2.unknownFieldWarnings);
|
|
2304
|
+
}
|
|
2305
|
+
}
|
|
2306
|
+
if (existsSync5(hooksJsonAtRoot)) {
|
|
2307
|
+
const result2 = loadHooksJson(hooksJsonAtRoot);
|
|
2308
|
+
if (result2.found) {
|
|
2309
|
+
if (!foundPath) {
|
|
2310
|
+
foundPath = result2.configPath;
|
|
2311
|
+
}
|
|
2312
|
+
if (result2.loadError) {
|
|
2313
|
+
allErrors.push(...result2.validation.errors);
|
|
2314
|
+
} else {
|
|
2315
|
+
configs.push(result2.config);
|
|
2316
|
+
allErrors.push(...result2.validation.errors);
|
|
2317
|
+
allWarnings.push(...result2.validation.warnings);
|
|
2318
|
+
}
|
|
2319
|
+
unknownFieldWarnings.push(...result2.unknownFieldWarnings);
|
|
2320
|
+
}
|
|
2321
|
+
}
|
|
2322
|
+
for (const warning of unknownFieldWarnings) {
|
|
2323
|
+
console.warn(`[hooks] Warning: ${warning}`);
|
|
2324
|
+
}
|
|
2325
|
+
let mergedConfig = createEmptyHooksConfig();
|
|
2326
|
+
if (configs.length > 0) {
|
|
2327
|
+
mergedConfig = mergeRawHooksConfigs(configs);
|
|
2328
|
+
}
|
|
2329
|
+
let validation;
|
|
2330
|
+
if (opts.validate && allErrors.length === 0) {
|
|
2331
|
+
validation = validateHooksConfig(mergedConfig, {
|
|
2332
|
+
basePath: hooksDir,
|
|
2333
|
+
checkScripts: opts.checkScripts ?? false
|
|
2334
|
+
});
|
|
2335
|
+
} else {
|
|
2336
|
+
validation = {
|
|
2337
|
+
valid: allErrors.length === 0,
|
|
2338
|
+
errors: allErrors,
|
|
2339
|
+
warnings: allWarnings
|
|
2340
|
+
};
|
|
2341
|
+
}
|
|
2342
|
+
if (opts.resolveCapabilityRoot && validation.valid) {
|
|
2343
|
+
mergedConfig = resolveCapabilityRootInConfig(mergedConfig, capabilityPath);
|
|
2344
|
+
}
|
|
2345
|
+
const result = {
|
|
2346
|
+
config: validation.valid ? mergedConfig : createEmptyHooksConfig(),
|
|
2347
|
+
validation,
|
|
2348
|
+
found: true
|
|
2349
|
+
};
|
|
2350
|
+
if (foundPath) {
|
|
2351
|
+
result.configPath = foundPath;
|
|
2352
|
+
}
|
|
2353
|
+
return result;
|
|
2354
|
+
}
|
|
2355
|
+
function mergeRawHooksConfigs(configs) {
|
|
2356
|
+
const result = {};
|
|
2357
|
+
for (const event of HOOK_EVENTS) {
|
|
2358
|
+
const allMatchers = [];
|
|
2359
|
+
for (const config of configs) {
|
|
2360
|
+
const matchers = config[event];
|
|
2361
|
+
if (matchers && matchers.length > 0) {
|
|
2362
|
+
allMatchers.push(...matchers);
|
|
2363
|
+
}
|
|
2364
|
+
}
|
|
2365
|
+
if (allMatchers.length > 0) {
|
|
2366
|
+
result[event] = allMatchers;
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
return result;
|
|
2370
|
+
}
|
|
1792
2371
|
function loadCapabilityHooks(capabilityName, capabilityPath, options) {
|
|
1793
2372
|
const result = loadHooksFromCapability(capabilityPath, options);
|
|
1794
2373
|
if (!result.found) {
|
|
@@ -1802,39 +2381,43 @@ function loadCapabilityHooks(capabilityName, capabilityPath, options) {
|
|
|
1802
2381
|
};
|
|
1803
2382
|
}
|
|
1804
2383
|
function hasHooks(capabilityPath) {
|
|
1805
|
-
const
|
|
1806
|
-
|
|
2384
|
+
const tomlPath = join3(capabilityPath, HOOKS_DIRECTORY, HOOKS_CONFIG_FILENAME);
|
|
2385
|
+
const jsonInDir = join3(capabilityPath, HOOKS_DIRECTORY, CLAUDE_HOOKS_CONFIG_FILENAME);
|
|
2386
|
+
const jsonAtRoot = join3(capabilityPath, CLAUDE_HOOKS_CONFIG_FILENAME);
|
|
2387
|
+
return existsSync5(tomlPath) || existsSync5(jsonInDir) || existsSync5(jsonAtRoot);
|
|
1807
2388
|
}
|
|
1808
2389
|
function getHooksDirectory(capabilityPath) {
|
|
1809
|
-
return
|
|
2390
|
+
return join3(capabilityPath, HOOKS_DIRECTORY);
|
|
1810
2391
|
}
|
|
1811
2392
|
function getHooksConfigPath(capabilityPath) {
|
|
1812
|
-
return
|
|
2393
|
+
return join3(capabilityPath, HOOKS_DIRECTORY, HOOKS_CONFIG_FILENAME);
|
|
1813
2394
|
}
|
|
1814
2395
|
var init_loader = __esm(() => {
|
|
1815
2396
|
init_dist();
|
|
1816
2397
|
init_constants();
|
|
1817
2398
|
init_validation();
|
|
1818
2399
|
init_variables();
|
|
2400
|
+
init_json_loader();
|
|
2401
|
+
init_constants();
|
|
1819
2402
|
});
|
|
1820
2403
|
|
|
1821
2404
|
// ../core/src/capability/rules.ts
|
|
1822
|
-
import { existsSync as
|
|
2405
|
+
import { existsSync as existsSync6, readdirSync as readdirSync3 } from "node:fs";
|
|
1823
2406
|
import { readFile as readFile3 } from "node:fs/promises";
|
|
1824
|
-
import { basename as
|
|
2407
|
+
import { basename as basename3, join as join4 } from "node:path";
|
|
1825
2408
|
async function loadRules(capabilityPath, capabilityId) {
|
|
1826
|
-
const rulesDir =
|
|
1827
|
-
if (!
|
|
2409
|
+
const rulesDir = join4(capabilityPath, "rules");
|
|
2410
|
+
if (!existsSync6(rulesDir)) {
|
|
1828
2411
|
return [];
|
|
1829
2412
|
}
|
|
1830
2413
|
const rules = [];
|
|
1831
2414
|
const entries = readdirSync3(rulesDir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1832
2415
|
for (const entry of entries) {
|
|
1833
2416
|
if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
1834
|
-
const rulePath =
|
|
2417
|
+
const rulePath = join4(rulesDir, entry.name);
|
|
1835
2418
|
const content = await readFile3(rulePath, "utf-8");
|
|
1836
2419
|
rules.push({
|
|
1837
|
-
name:
|
|
2420
|
+
name: basename3(entry.name, ".md"),
|
|
1838
2421
|
content: content.trim(),
|
|
1839
2422
|
capabilityId
|
|
1840
2423
|
});
|
|
@@ -1845,22 +2428,25 @@ async function loadRules(capabilityPath, capabilityId) {
|
|
|
1845
2428
|
var init_rules = () => {};
|
|
1846
2429
|
|
|
1847
2430
|
// ../core/src/capability/skills.ts
|
|
1848
|
-
import { existsSync as
|
|
2431
|
+
import { existsSync as existsSync7, readdirSync as readdirSync4 } from "node:fs";
|
|
1849
2432
|
import { readFile as readFile4 } from "node:fs/promises";
|
|
1850
|
-
import { join as
|
|
2433
|
+
import { join as join5 } from "node:path";
|
|
1851
2434
|
async function loadSkills(capabilityPath, capabilityId) {
|
|
1852
|
-
const skillsDir = join6(capabilityPath, "skills");
|
|
1853
|
-
if (!existsSync6(skillsDir)) {
|
|
1854
|
-
return [];
|
|
1855
|
-
}
|
|
1856
2435
|
const skills = [];
|
|
1857
|
-
const
|
|
1858
|
-
for (const
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
2436
|
+
const possibleDirNames = ["skills", "skill"];
|
|
2437
|
+
for (const dirName of possibleDirNames) {
|
|
2438
|
+
const dir = join5(capabilityPath, dirName);
|
|
2439
|
+
if (!existsSync7(dir)) {
|
|
2440
|
+
continue;
|
|
2441
|
+
}
|
|
2442
|
+
const entries = readdirSync4(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
2443
|
+
for (const entry of entries) {
|
|
2444
|
+
if (entry.isDirectory()) {
|
|
2445
|
+
const skillPath = join5(dir, entry.name, "SKILL.md");
|
|
2446
|
+
if (existsSync7(skillPath)) {
|
|
2447
|
+
const skill = await parseSkillFile(skillPath, capabilityId);
|
|
2448
|
+
skills.push(skill);
|
|
2449
|
+
}
|
|
1864
2450
|
}
|
|
1865
2451
|
}
|
|
1866
2452
|
}
|
|
@@ -1875,7 +2461,7 @@ async function parseSkillFile(filePath, capabilityId) {
|
|
|
1875
2461
|
const frontmatter = parsed.frontmatter;
|
|
1876
2462
|
const instructions = parsed.markdown;
|
|
1877
2463
|
if (!frontmatter.name || !frontmatter.description) {
|
|
1878
|
-
throw new Error(`Invalid SKILL.md at ${filePath}: name and description required`);
|
|
2464
|
+
throw new Error(`Invalid SKILL.md at ${filePath}: name and description required in frontmatter`);
|
|
1879
2465
|
}
|
|
1880
2466
|
return {
|
|
1881
2467
|
name: frontmatter.name,
|
|
@@ -1887,20 +2473,30 @@ async function parseSkillFile(filePath, capabilityId) {
|
|
|
1887
2473
|
var init_skills = () => {};
|
|
1888
2474
|
|
|
1889
2475
|
// ../core/src/capability/subagents.ts
|
|
1890
|
-
import { existsSync as
|
|
2476
|
+
import { existsSync as existsSync8, readdirSync as readdirSync5 } from "node:fs";
|
|
1891
2477
|
import { readFile as readFile5 } from "node:fs/promises";
|
|
1892
|
-
import { join as
|
|
2478
|
+
import { basename as basename4, join as join6 } from "node:path";
|
|
1893
2479
|
async function loadSubagents(capabilityPath, capabilityId) {
|
|
1894
|
-
const subagentsDir = join7(capabilityPath, "subagents");
|
|
1895
|
-
if (!existsSync7(subagentsDir)) {
|
|
1896
|
-
return [];
|
|
1897
|
-
}
|
|
1898
2480
|
const subagents = [];
|
|
1899
|
-
const
|
|
1900
|
-
for (const
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
2481
|
+
const possibleDirNames = ["subagents", "agents", "agent", "subagent"];
|
|
2482
|
+
for (const dirName of possibleDirNames) {
|
|
2483
|
+
const dir = join6(capabilityPath, dirName);
|
|
2484
|
+
if (!existsSync8(dir)) {
|
|
2485
|
+
continue;
|
|
2486
|
+
}
|
|
2487
|
+
const entries = readdirSync5(dir, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
2488
|
+
for (const entry of entries) {
|
|
2489
|
+
if (entry.isDirectory()) {
|
|
2490
|
+
let subagentPath = join6(dir, entry.name, "SUBAGENT.md");
|
|
2491
|
+
if (!existsSync8(subagentPath)) {
|
|
2492
|
+
subagentPath = join6(dir, entry.name, "AGENT.md");
|
|
2493
|
+
}
|
|
2494
|
+
if (existsSync8(subagentPath)) {
|
|
2495
|
+
const subagent = await parseSubagentFile(subagentPath, capabilityId);
|
|
2496
|
+
subagents.push(subagent);
|
|
2497
|
+
}
|
|
2498
|
+
} else if (entry.isFile() && entry.name.endsWith(".md")) {
|
|
2499
|
+
const subagentPath = join6(dir, entry.name);
|
|
1904
2500
|
const subagent = await parseSubagentFile(subagentPath, capabilityId);
|
|
1905
2501
|
subagents.push(subagent);
|
|
1906
2502
|
}
|
|
@@ -1916,11 +2512,13 @@ async function parseSubagentFile(filePath, capabilityId) {
|
|
|
1916
2512
|
}
|
|
1917
2513
|
const frontmatter = parsed.frontmatter;
|
|
1918
2514
|
const systemPrompt = parsed.markdown;
|
|
1919
|
-
|
|
2515
|
+
const inferredName = basename4(filePath, ".md").replace(/^SUBAGENT$/i, "").replace(/^AGENT$/i, "");
|
|
2516
|
+
const name = frontmatter.name || inferredName;
|
|
2517
|
+
if (!name || !frontmatter.description) {
|
|
1920
2518
|
throw new Error(`Invalid SUBAGENT.md at ${filePath}: name and description required`);
|
|
1921
2519
|
}
|
|
1922
2520
|
const result = {
|
|
1923
|
-
name
|
|
2521
|
+
name,
|
|
1924
2522
|
description: frontmatter.description,
|
|
1925
2523
|
systemPrompt: systemPrompt.trim(),
|
|
1926
2524
|
capabilityId
|
|
@@ -1951,18 +2549,18 @@ function parseCommaSeparatedList(value) {
|
|
|
1951
2549
|
var init_subagents = () => {};
|
|
1952
2550
|
|
|
1953
2551
|
// ../core/src/capability/loader.ts
|
|
1954
|
-
import { existsSync as
|
|
2552
|
+
import { existsSync as existsSync9, readdirSync as readdirSync6 } from "node:fs";
|
|
1955
2553
|
import { readFile as readFile6 } from "node:fs/promises";
|
|
1956
|
-
import { join as
|
|
2554
|
+
import { join as join7 } from "node:path";
|
|
1957
2555
|
async function discoverCapabilities() {
|
|
1958
2556
|
const capabilities = [];
|
|
1959
|
-
if (
|
|
2557
|
+
if (existsSync9(CAPABILITIES_DIR)) {
|
|
1960
2558
|
const entries = readdirSync6(CAPABILITIES_DIR, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name));
|
|
1961
2559
|
for (const entry of entries) {
|
|
1962
2560
|
if (entry.isDirectory()) {
|
|
1963
|
-
const entryPath =
|
|
1964
|
-
const configPath =
|
|
1965
|
-
if (
|
|
2561
|
+
const entryPath = join7(CAPABILITIES_DIR, entry.name);
|
|
2562
|
+
const configPath = join7(entryPath, "capability.toml");
|
|
2563
|
+
if (existsSync9(configPath)) {
|
|
1966
2564
|
capabilities.push(entryPath);
|
|
1967
2565
|
}
|
|
1968
2566
|
}
|
|
@@ -1971,28 +2569,28 @@ async function discoverCapabilities() {
|
|
|
1971
2569
|
return capabilities;
|
|
1972
2570
|
}
|
|
1973
2571
|
async function loadCapabilityConfig(capabilityPath) {
|
|
1974
|
-
const configPath =
|
|
2572
|
+
const configPath = join7(capabilityPath, "capability.toml");
|
|
1975
2573
|
const content = await readFile6(configPath, "utf-8");
|
|
1976
2574
|
const config = parseCapabilityConfig(content);
|
|
1977
2575
|
return config;
|
|
1978
2576
|
}
|
|
1979
2577
|
async function importCapabilityExports(capabilityPath) {
|
|
1980
|
-
const builtIndexPath =
|
|
1981
|
-
const jsIndexPath =
|
|
1982
|
-
const tsIndexPath =
|
|
2578
|
+
const builtIndexPath = join7(capabilityPath, "dist", "index.js");
|
|
2579
|
+
const jsIndexPath = join7(capabilityPath, "index.js");
|
|
2580
|
+
const tsIndexPath = join7(capabilityPath, "index.ts");
|
|
1983
2581
|
let indexPath = null;
|
|
1984
|
-
if (
|
|
2582
|
+
if (existsSync9(builtIndexPath)) {
|
|
1985
2583
|
indexPath = builtIndexPath;
|
|
1986
|
-
} else if (
|
|
2584
|
+
} else if (existsSync9(jsIndexPath)) {
|
|
1987
2585
|
indexPath = jsIndexPath;
|
|
1988
|
-
} else if (
|
|
2586
|
+
} else if (existsSync9(tsIndexPath)) {
|
|
1989
2587
|
indexPath = tsIndexPath;
|
|
1990
2588
|
}
|
|
1991
2589
|
if (!indexPath) {
|
|
1992
2590
|
return {};
|
|
1993
2591
|
}
|
|
1994
2592
|
try {
|
|
1995
|
-
const absolutePath =
|
|
2593
|
+
const absolutePath = join7(process.cwd(), indexPath);
|
|
1996
2594
|
const module = await import(absolutePath);
|
|
1997
2595
|
return module;
|
|
1998
2596
|
} catch (error) {
|
|
@@ -2012,8 +2610,8 @@ If this is a project-specific capability, install dependencies or remove it from
|
|
|
2012
2610
|
}
|
|
2013
2611
|
}
|
|
2014
2612
|
async function loadTypeDefinitions(capabilityPath) {
|
|
2015
|
-
const typesPath =
|
|
2016
|
-
if (!
|
|
2613
|
+
const typesPath = join7(capabilityPath, "types.d.ts");
|
|
2614
|
+
if (!existsSync9(typesPath)) {
|
|
2017
2615
|
return;
|
|
2018
2616
|
}
|
|
2019
2617
|
return readFile6(typesPath, "utf-8");
|
|
@@ -2206,7 +2804,7 @@ async function loadCapability(capabilityPath) {
|
|
|
2206
2804
|
const typeDefinitionsFromExports = "typeDefinitions" in exports && typeof exportsAny.typeDefinitions === "string" ? exportsAny.typeDefinitions : undefined;
|
|
2207
2805
|
const typeDefinitions = typeDefinitionsFromExports !== undefined ? typeDefinitionsFromExports : await loadTypeDefinitions(capabilityPath);
|
|
2208
2806
|
const gitignore = "gitignore" in exports && Array.isArray(exportsAny.gitignore) ? exportsAny.gitignore : undefined;
|
|
2209
|
-
const hooks = loadCapabilityHooks(id, capabilityPath);
|
|
2807
|
+
const hooks = loadCapabilityHooks(id, capabilityPath, { resolveCapabilityRoot: true });
|
|
2210
2808
|
const result = {
|
|
2211
2809
|
id,
|
|
2212
2810
|
path: capabilityPath,
|
|
@@ -2241,8 +2839,8 @@ var init_loader2 = __esm(() => {
|
|
|
2241
2839
|
});
|
|
2242
2840
|
|
|
2243
2841
|
// ../core/src/config/config.ts
|
|
2244
|
-
import { existsSync as
|
|
2245
|
-
import { readFile as readFile7, writeFile
|
|
2842
|
+
import { existsSync as existsSync10 } from "node:fs";
|
|
2843
|
+
import { readFile as readFile7, writeFile } from "node:fs/promises";
|
|
2246
2844
|
function mergeConfigs(base, override) {
|
|
2247
2845
|
const merged = { ...base, ...override };
|
|
2248
2846
|
merged.profiles = { ...base.profiles };
|
|
@@ -2255,10 +2853,36 @@ function mergeConfigs(base, override) {
|
|
|
2255
2853
|
if (base.mcps || override.mcps) {
|
|
2256
2854
|
merged.mcps = { ...base.mcps, ...override.mcps };
|
|
2257
2855
|
}
|
|
2856
|
+
if (base.capabilities || override.capabilities) {
|
|
2857
|
+
merged.capabilities = {
|
|
2858
|
+
...base.capabilities,
|
|
2859
|
+
...override.capabilities,
|
|
2860
|
+
sources: { ...base.capabilities?.sources, ...override.capabilities?.sources },
|
|
2861
|
+
groups: { ...base.capabilities?.groups, ...override.capabilities?.groups },
|
|
2862
|
+
always_enabled: [
|
|
2863
|
+
...new Set([
|
|
2864
|
+
...base.capabilities?.always_enabled ?? [],
|
|
2865
|
+
...override.capabilities?.always_enabled ?? []
|
|
2866
|
+
])
|
|
2867
|
+
],
|
|
2868
|
+
always_disabled: [
|
|
2869
|
+
...new Set([
|
|
2870
|
+
...base.capabilities?.always_disabled ?? [],
|
|
2871
|
+
...override.capabilities?.always_disabled ?? []
|
|
2872
|
+
])
|
|
2873
|
+
]
|
|
2874
|
+
};
|
|
2875
|
+
if (merged.capabilities.always_enabled?.length === 0) {
|
|
2876
|
+
delete merged.capabilities.always_enabled;
|
|
2877
|
+
}
|
|
2878
|
+
if (merged.capabilities.always_disabled?.length === 0) {
|
|
2879
|
+
delete merged.capabilities.always_disabled;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2258
2882
|
return merged;
|
|
2259
2883
|
}
|
|
2260
2884
|
async function loadBaseConfig() {
|
|
2261
|
-
if (
|
|
2885
|
+
if (existsSync10(CONFIG_PATH)) {
|
|
2262
2886
|
const content = await readFile7(CONFIG_PATH, "utf-8");
|
|
2263
2887
|
return parseOmniConfig(content);
|
|
2264
2888
|
}
|
|
@@ -2267,7 +2891,7 @@ async function loadBaseConfig() {
|
|
|
2267
2891
|
async function loadConfig() {
|
|
2268
2892
|
const baseConfig = await loadBaseConfig();
|
|
2269
2893
|
let localConfig = {};
|
|
2270
|
-
if (
|
|
2894
|
+
if (existsSync10(LOCAL_CONFIG)) {
|
|
2271
2895
|
const content = await readFile7(LOCAL_CONFIG, "utf-8");
|
|
2272
2896
|
localConfig = parseOmniConfig(content);
|
|
2273
2897
|
}
|
|
@@ -2275,7 +2899,7 @@ async function loadConfig() {
|
|
|
2275
2899
|
}
|
|
2276
2900
|
async function writeConfig(config) {
|
|
2277
2901
|
const content = generateConfigToml(config);
|
|
2278
|
-
await
|
|
2902
|
+
await writeFile(CONFIG_PATH, content, "utf-8");
|
|
2279
2903
|
}
|
|
2280
2904
|
function generateConfigToml(config) {
|
|
2281
2905
|
const lines = [];
|
|
@@ -2432,10 +3056,10 @@ var init_config = __esm(() => {
|
|
|
2432
3056
|
});
|
|
2433
3057
|
|
|
2434
3058
|
// ../core/src/state/active-profile.ts
|
|
2435
|
-
import { existsSync as
|
|
2436
|
-
import { readFile as readFile8, unlink, writeFile as
|
|
3059
|
+
import { existsSync as existsSync11, mkdirSync } from "node:fs";
|
|
3060
|
+
import { readFile as readFile8, unlink, writeFile as writeFile2 } from "node:fs/promises";
|
|
2437
3061
|
async function readActiveProfileState() {
|
|
2438
|
-
if (!
|
|
3062
|
+
if (!existsSync11(ACTIVE_PROFILE_PATH)) {
|
|
2439
3063
|
return null;
|
|
2440
3064
|
}
|
|
2441
3065
|
try {
|
|
@@ -2448,10 +3072,10 @@ async function readActiveProfileState() {
|
|
|
2448
3072
|
}
|
|
2449
3073
|
async function writeActiveProfileState(profileName) {
|
|
2450
3074
|
mkdirSync(STATE_DIR, { recursive: true });
|
|
2451
|
-
await
|
|
3075
|
+
await writeFile2(ACTIVE_PROFILE_PATH, profileName, "utf-8");
|
|
2452
3076
|
}
|
|
2453
3077
|
async function clearActiveProfileState() {
|
|
2454
|
-
if (
|
|
3078
|
+
if (existsSync11(ACTIVE_PROFILE_PATH)) {
|
|
2455
3079
|
await unlink(ACTIVE_PROFILE_PATH);
|
|
2456
3080
|
}
|
|
2457
3081
|
}
|
|
@@ -2471,6 +3095,7 @@ function resolveEnabledCapabilities(config, profileName) {
|
|
|
2471
3095
|
const profile = profileName ? config.profiles?.[profileName] : config.profiles?.["default"];
|
|
2472
3096
|
const profileCapabilities = profile?.capabilities ?? [];
|
|
2473
3097
|
const alwaysEnabled = config.capabilities?.always_enabled ?? [];
|
|
3098
|
+
const alwaysDisabled = config.capabilities?.always_disabled ?? [];
|
|
2474
3099
|
const groups = config.capabilities?.groups ?? {};
|
|
2475
3100
|
const expandCapabilities = (caps) => {
|
|
2476
3101
|
return caps.flatMap((cap) => {
|
|
@@ -2488,7 +3113,9 @@ function resolveEnabledCapabilities(config, profileName) {
|
|
|
2488
3113
|
};
|
|
2489
3114
|
const expandedAlways = expandCapabilities(alwaysEnabled);
|
|
2490
3115
|
const expandedProfile = expandCapabilities(profileCapabilities);
|
|
2491
|
-
|
|
3116
|
+
const expandedDisabled = new Set(expandCapabilities(alwaysDisabled));
|
|
3117
|
+
const allEnabled = [...new Set([...expandedAlways, ...expandedProfile])];
|
|
3118
|
+
return allEnabled.filter((cap) => !expandedDisabled.has(cap));
|
|
2492
3119
|
}
|
|
2493
3120
|
async function loadProfileConfig(profileName) {
|
|
2494
3121
|
const config = await loadConfig();
|
|
@@ -2692,10 +3319,10 @@ function getActiveProviders(config) {
|
|
|
2692
3319
|
var init_types2 = () => {};
|
|
2693
3320
|
|
|
2694
3321
|
// ../core/src/capability/sources.ts
|
|
2695
|
-
import { existsSync as
|
|
3322
|
+
import { existsSync as existsSync12 } from "node:fs";
|
|
2696
3323
|
import { spawn } from "node:child_process";
|
|
2697
|
-
import { cp, mkdir
|
|
2698
|
-
import { join as
|
|
3324
|
+
import { cp, mkdir, readdir, readFile as readFile9, rename, rm, stat, writeFile as writeFile3 } from "node:fs/promises";
|
|
3325
|
+
import { join as join8 } from "node:path";
|
|
2699
3326
|
import { createHash } from "node:crypto";
|
|
2700
3327
|
async function spawnCapture(command, args, options) {
|
|
2701
3328
|
const timeout = options?.timeout ?? 60000;
|
|
@@ -2752,8 +3379,8 @@ function parseFileSourcePath(source) {
|
|
|
2752
3379
|
return source.slice(7);
|
|
2753
3380
|
}
|
|
2754
3381
|
async function readCapabilityIdFromPath(capabilityPath) {
|
|
2755
|
-
const tomlPath =
|
|
2756
|
-
if (
|
|
3382
|
+
const tomlPath = join8(capabilityPath, "capability.toml");
|
|
3383
|
+
if (existsSync12(tomlPath)) {
|
|
2757
3384
|
try {
|
|
2758
3385
|
const content = await readFile9(tomlPath, "utf-8");
|
|
2759
3386
|
const parsed = parse(content);
|
|
@@ -2808,14 +3435,14 @@ function sourceToGitUrl(source) {
|
|
|
2808
3435
|
return source;
|
|
2809
3436
|
}
|
|
2810
3437
|
function getSourceCapabilityPath(id) {
|
|
2811
|
-
return
|
|
3438
|
+
return join8(OMNI_LOCAL, "capabilities", id);
|
|
2812
3439
|
}
|
|
2813
3440
|
function getLockFilePath() {
|
|
2814
3441
|
return "omni.lock.toml";
|
|
2815
3442
|
}
|
|
2816
3443
|
async function loadLockFile() {
|
|
2817
3444
|
const lockPath = getLockFilePath();
|
|
2818
|
-
if (!
|
|
3445
|
+
if (!existsSync12(lockPath)) {
|
|
2819
3446
|
return { capabilities: {} };
|
|
2820
3447
|
}
|
|
2821
3448
|
try {
|
|
@@ -2877,14 +3504,14 @@ function stringifyLockFile(lockFile) {
|
|
|
2877
3504
|
}
|
|
2878
3505
|
async function saveLockFile(lockFile) {
|
|
2879
3506
|
const lockPath = getLockFilePath();
|
|
2880
|
-
await
|
|
3507
|
+
await mkdir(join8(OMNI_LOCAL, "capabilities"), { recursive: true });
|
|
2881
3508
|
const header = `# Auto-generated by OmniDev - DO NOT EDIT
|
|
2882
3509
|
# Records installed capability versions for reproducibility
|
|
2883
3510
|
# Last updated: ${new Date().toISOString()}
|
|
2884
3511
|
|
|
2885
3512
|
`;
|
|
2886
3513
|
const content = header + stringifyLockFile(lockFile);
|
|
2887
|
-
await
|
|
3514
|
+
await writeFile3(lockPath, content, "utf-8");
|
|
2888
3515
|
}
|
|
2889
3516
|
async function getRepoCommit(repoPath) {
|
|
2890
3517
|
const { exitCode, stdout, stderr } = await spawnCapture("git", ["rev-parse", "HEAD"], {
|
|
@@ -2908,7 +3535,7 @@ async function computeContentHash(dirPath, excludePatterns = CONTENT_HASH_EXCLUD
|
|
|
2908
3535
|
const entries = await readdir(currentPath, { withFileTypes: true });
|
|
2909
3536
|
entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
2910
3537
|
for (const entry of entries) {
|
|
2911
|
-
const fullPath =
|
|
3538
|
+
const fullPath = join8(currentPath, entry.name);
|
|
2912
3539
|
const relativePath = fullPath.slice(relativeTo.length + 1);
|
|
2913
3540
|
if (excludePatterns.some((pattern) => entry.name === pattern || relativePath.startsWith(`${pattern}/`))) {
|
|
2914
3541
|
continue;
|
|
@@ -2930,8 +3557,8 @@ async function computeContentHash(dirPath, excludePatterns = CONTENT_HASH_EXCLUD
|
|
|
2930
3557
|
return hash.digest("hex");
|
|
2931
3558
|
}
|
|
2932
3559
|
async function detectDisplayVersion(dirPath, fallback, fallbackSource) {
|
|
2933
|
-
const capTomlPath =
|
|
2934
|
-
if (
|
|
3560
|
+
const capTomlPath = join8(dirPath, "capability.toml");
|
|
3561
|
+
if (existsSync12(capTomlPath)) {
|
|
2935
3562
|
try {
|
|
2936
3563
|
const content = await readFile9(capTomlPath, "utf-8");
|
|
2937
3564
|
const parsed = parse(content);
|
|
@@ -2941,8 +3568,8 @@ async function detectDisplayVersion(dirPath, fallback, fallbackSource) {
|
|
|
2941
3568
|
}
|
|
2942
3569
|
} catch {}
|
|
2943
3570
|
}
|
|
2944
|
-
const pluginJsonPath =
|
|
2945
|
-
if (
|
|
3571
|
+
const pluginJsonPath = join8(dirPath, ".claude-plugin", "plugin.json");
|
|
3572
|
+
if (existsSync12(pluginJsonPath)) {
|
|
2946
3573
|
try {
|
|
2947
3574
|
const content = await readFile9(pluginJsonPath, "utf-8");
|
|
2948
3575
|
const parsed = JSON.parse(content);
|
|
@@ -2951,8 +3578,8 @@ async function detectDisplayVersion(dirPath, fallback, fallbackSource) {
|
|
|
2951
3578
|
}
|
|
2952
3579
|
} catch {}
|
|
2953
3580
|
}
|
|
2954
|
-
const pkgJsonPath =
|
|
2955
|
-
if (
|
|
3581
|
+
const pkgJsonPath = join8(dirPath, "package.json");
|
|
3582
|
+
if (existsSync12(pkgJsonPath)) {
|
|
2956
3583
|
try {
|
|
2957
3584
|
const content = await readFile9(pkgJsonPath, "utf-8");
|
|
2958
3585
|
const parsed = JSON.parse(content);
|
|
@@ -2963,20 +3590,111 @@ async function detectDisplayVersion(dirPath, fallback, fallbackSource) {
|
|
|
2963
3590
|
}
|
|
2964
3591
|
return { version: fallback, source: fallbackSource };
|
|
2965
3592
|
}
|
|
3593
|
+
async function validateGitCapability(sourceUrl, subPath) {
|
|
3594
|
+
const gitUrl = sourceToGitUrl(sourceUrl);
|
|
3595
|
+
const tempPath = join8(OMNI_LOCAL, "_temp", `_validate-${Date.now()}`);
|
|
3596
|
+
try {
|
|
3597
|
+
await mkdir(join8(tempPath, ".."), { recursive: true });
|
|
3598
|
+
const args = ["clone", "--depth", "1", gitUrl, tempPath];
|
|
3599
|
+
const { exitCode, stderr } = await spawnCapture("git", args, { timeout: 30000 });
|
|
3600
|
+
if (exitCode !== 0) {
|
|
3601
|
+
const stderrLower = stderr.toLowerCase();
|
|
3602
|
+
if (stderrLower.includes("not found") || stderrLower.includes("repository not found") || stderrLower.includes("does not exist")) {
|
|
3603
|
+
return {
|
|
3604
|
+
valid: false,
|
|
3605
|
+
hasCapabilityToml: false,
|
|
3606
|
+
canBeWrapped: false,
|
|
3607
|
+
error: "Repository not found"
|
|
3608
|
+
};
|
|
3609
|
+
}
|
|
3610
|
+
if (stderrLower.includes("could not resolve host")) {
|
|
3611
|
+
return {
|
|
3612
|
+
valid: false,
|
|
3613
|
+
hasCapabilityToml: false,
|
|
3614
|
+
canBeWrapped: false,
|
|
3615
|
+
error: "Could not resolve host - check your network connection"
|
|
3616
|
+
};
|
|
3617
|
+
}
|
|
3618
|
+
if (stderrLower.includes("authentication") || stderrLower.includes("permission denied")) {
|
|
3619
|
+
return {
|
|
3620
|
+
valid: false,
|
|
3621
|
+
hasCapabilityToml: false,
|
|
3622
|
+
canBeWrapped: false,
|
|
3623
|
+
error: "Authentication failed - repository may be private"
|
|
3624
|
+
};
|
|
3625
|
+
}
|
|
3626
|
+
return {
|
|
3627
|
+
valid: false,
|
|
3628
|
+
hasCapabilityToml: false,
|
|
3629
|
+
canBeWrapped: false,
|
|
3630
|
+
error: `Failed to clone repository: ${stderr.trim()}`
|
|
3631
|
+
};
|
|
3632
|
+
}
|
|
3633
|
+
const checkPath = subPath ? join8(tempPath, subPath) : tempPath;
|
|
3634
|
+
if (subPath && !existsSync12(checkPath)) {
|
|
3635
|
+
return {
|
|
3636
|
+
valid: false,
|
|
3637
|
+
hasCapabilityToml: false,
|
|
3638
|
+
canBeWrapped: false,
|
|
3639
|
+
error: `Path '${subPath}' not found in repository`
|
|
3640
|
+
};
|
|
3641
|
+
}
|
|
3642
|
+
const hasCapToml = hasCapabilityToml(checkPath);
|
|
3643
|
+
let capabilityId;
|
|
3644
|
+
if (hasCapToml) {
|
|
3645
|
+
const tomlPath = join8(checkPath, "capability.toml");
|
|
3646
|
+
try {
|
|
3647
|
+
const content = await readFile9(tomlPath, "utf-8");
|
|
3648
|
+
const parsed = parse(content);
|
|
3649
|
+
const capability = parsed["capability"];
|
|
3650
|
+
if (capability?.["id"] && typeof capability["id"] === "string") {
|
|
3651
|
+
capabilityId = capability["id"];
|
|
3652
|
+
}
|
|
3653
|
+
} catch {}
|
|
3654
|
+
const result = {
|
|
3655
|
+
valid: true,
|
|
3656
|
+
hasCapabilityToml: true,
|
|
3657
|
+
canBeWrapped: true
|
|
3658
|
+
};
|
|
3659
|
+
if (capabilityId) {
|
|
3660
|
+
result.capabilityId = capabilityId;
|
|
3661
|
+
}
|
|
3662
|
+
return result;
|
|
3663
|
+
}
|
|
3664
|
+
const canWrap = await shouldWrapDirectory(checkPath);
|
|
3665
|
+
if (!canWrap) {
|
|
3666
|
+
return {
|
|
3667
|
+
valid: false,
|
|
3668
|
+
hasCapabilityToml: false,
|
|
3669
|
+
canBeWrapped: false,
|
|
3670
|
+
error: "Repository does not contain a capability.toml and cannot be auto-wrapped (no skills, agents, commands, rules, docs, or .claude-plugin found)"
|
|
3671
|
+
};
|
|
3672
|
+
}
|
|
3673
|
+
return {
|
|
3674
|
+
valid: true,
|
|
3675
|
+
hasCapabilityToml: false,
|
|
3676
|
+
canBeWrapped: true
|
|
3677
|
+
};
|
|
3678
|
+
} finally {
|
|
3679
|
+
if (existsSync12(tempPath)) {
|
|
3680
|
+
await rm(tempPath, { recursive: true });
|
|
3681
|
+
}
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
2966
3684
|
async function detectPinVersion(sourceUrl, subPath) {
|
|
2967
3685
|
const gitUrl = sourceToGitUrl(sourceUrl);
|
|
2968
|
-
const tempPath =
|
|
3686
|
+
const tempPath = join8(OMNI_LOCAL, "_temp", `_pin-detect-${Date.now()}`);
|
|
2969
3687
|
try {
|
|
2970
|
-
await
|
|
3688
|
+
await mkdir(join8(tempPath, ".."), { recursive: true });
|
|
2971
3689
|
const args = ["clone", "--depth", "1", gitUrl, tempPath];
|
|
2972
3690
|
const { exitCode, stderr } = await spawnCapture("git", args);
|
|
2973
3691
|
if (exitCode !== 0) {
|
|
2974
3692
|
throw new Error(`Failed to clone ${gitUrl}: ${stderr.trim()}`);
|
|
2975
3693
|
}
|
|
2976
3694
|
const commit = await getRepoCommit(tempPath);
|
|
2977
|
-
const checkPath = subPath ?
|
|
2978
|
-
const capTomlPath =
|
|
2979
|
-
if (
|
|
3695
|
+
const checkPath = subPath ? join8(tempPath, subPath) : tempPath;
|
|
3696
|
+
const capTomlPath = join8(checkPath, "capability.toml");
|
|
3697
|
+
if (existsSync12(capTomlPath)) {
|
|
2980
3698
|
try {
|
|
2981
3699
|
const content = await readFile9(capTomlPath, "utf-8");
|
|
2982
3700
|
const parsed = parse(content);
|
|
@@ -2986,8 +3704,8 @@ async function detectPinVersion(sourceUrl, subPath) {
|
|
|
2986
3704
|
}
|
|
2987
3705
|
} catch {}
|
|
2988
3706
|
}
|
|
2989
|
-
const pluginJsonPath =
|
|
2990
|
-
if (
|
|
3707
|
+
const pluginJsonPath = join8(checkPath, ".claude-plugin", "plugin.json");
|
|
3708
|
+
if (existsSync12(pluginJsonPath)) {
|
|
2991
3709
|
try {
|
|
2992
3710
|
const content = await readFile9(pluginJsonPath, "utf-8");
|
|
2993
3711
|
const parsed = JSON.parse(content);
|
|
@@ -2998,13 +3716,13 @@ async function detectPinVersion(sourceUrl, subPath) {
|
|
|
2998
3716
|
}
|
|
2999
3717
|
return commit;
|
|
3000
3718
|
} finally {
|
|
3001
|
-
if (
|
|
3719
|
+
if (existsSync12(tempPath)) {
|
|
3002
3720
|
await rm(tempPath, { recursive: true });
|
|
3003
3721
|
}
|
|
3004
3722
|
}
|
|
3005
3723
|
}
|
|
3006
3724
|
async function cloneRepo(gitUrl, targetPath, ref) {
|
|
3007
|
-
await
|
|
3725
|
+
await mkdir(join8(targetPath, ".."), { recursive: true });
|
|
3008
3726
|
const args = ["clone", "--depth", "1"];
|
|
3009
3727
|
if (ref) {
|
|
3010
3728
|
args.push("--branch", ref);
|
|
@@ -3041,16 +3759,16 @@ async function fetchRepo(repoPath, ref) {
|
|
|
3041
3759
|
return true;
|
|
3042
3760
|
}
|
|
3043
3761
|
function hasCapabilityToml(dirPath) {
|
|
3044
|
-
return
|
|
3762
|
+
return existsSync12(join8(dirPath, "capability.toml"));
|
|
3045
3763
|
}
|
|
3046
3764
|
async function shouldWrapDirectory(dirPath) {
|
|
3047
|
-
if (
|
|
3765
|
+
if (existsSync12(join8(dirPath, ".claude-plugin", "plugin.json"))) {
|
|
3048
3766
|
return true;
|
|
3049
3767
|
}
|
|
3050
3768
|
const allDirs = [...SKILL_DIRS, ...AGENT_DIRS, ...COMMAND_DIRS, ...RULE_DIRS, ...DOC_DIRS];
|
|
3051
3769
|
for (const dirName of allDirs) {
|
|
3052
|
-
const checkPath =
|
|
3053
|
-
if (
|
|
3770
|
+
const checkPath = join8(dirPath, dirName);
|
|
3771
|
+
if (existsSync12(checkPath)) {
|
|
3054
3772
|
const stats = await stat(checkPath);
|
|
3055
3773
|
if (stats.isDirectory()) {
|
|
3056
3774
|
return true;
|
|
@@ -3061,8 +3779,8 @@ async function shouldWrapDirectory(dirPath) {
|
|
|
3061
3779
|
}
|
|
3062
3780
|
async function findMatchingDirs(basePath, names) {
|
|
3063
3781
|
for (const name of names) {
|
|
3064
|
-
const dirPath =
|
|
3065
|
-
if (
|
|
3782
|
+
const dirPath = join8(basePath, name);
|
|
3783
|
+
if (existsSync12(dirPath)) {
|
|
3066
3784
|
const stats = await stat(dirPath);
|
|
3067
3785
|
if (stats.isDirectory()) {
|
|
3068
3786
|
return dirPath;
|
|
@@ -3073,15 +3791,15 @@ async function findMatchingDirs(basePath, names) {
|
|
|
3073
3791
|
}
|
|
3074
3792
|
async function findContentItems(dirPath, filePatterns) {
|
|
3075
3793
|
const items = [];
|
|
3076
|
-
if (!
|
|
3794
|
+
if (!existsSync12(dirPath)) {
|
|
3077
3795
|
return items;
|
|
3078
3796
|
}
|
|
3079
3797
|
const entries = (await readdir(dirPath, { withFileTypes: true })).sort((a, b) => a.name.localeCompare(b.name));
|
|
3080
3798
|
for (const entry of entries) {
|
|
3081
|
-
const entryPath =
|
|
3799
|
+
const entryPath = join8(dirPath, entry.name);
|
|
3082
3800
|
if (entry.isDirectory()) {
|
|
3083
3801
|
for (const pattern of filePatterns) {
|
|
3084
|
-
if (
|
|
3802
|
+
if (existsSync12(join8(entryPath, pattern))) {
|
|
3085
3803
|
items.push({
|
|
3086
3804
|
name: entry.name,
|
|
3087
3805
|
path: entryPath,
|
|
@@ -3102,8 +3820,8 @@ async function findContentItems(dirPath, filePatterns) {
|
|
|
3102
3820
|
return items;
|
|
3103
3821
|
}
|
|
3104
3822
|
async function parsePluginJson(dirPath) {
|
|
3105
|
-
const pluginJsonPath =
|
|
3106
|
-
if (!
|
|
3823
|
+
const pluginJsonPath = join8(dirPath, ".claude-plugin", "plugin.json");
|
|
3824
|
+
if (!existsSync12(pluginJsonPath)) {
|
|
3107
3825
|
return null;
|
|
3108
3826
|
}
|
|
3109
3827
|
try {
|
|
@@ -3127,8 +3845,8 @@ async function parsePluginJson(dirPath) {
|
|
|
3127
3845
|
}
|
|
3128
3846
|
}
|
|
3129
3847
|
async function readReadmeDescription(dirPath) {
|
|
3130
|
-
const readmePath =
|
|
3131
|
-
if (!
|
|
3848
|
+
const readmePath = join8(dirPath, "README.md");
|
|
3849
|
+
if (!existsSync12(readmePath)) {
|
|
3132
3850
|
return null;
|
|
3133
3851
|
}
|
|
3134
3852
|
try {
|
|
@@ -3164,14 +3882,12 @@ async function normalizeFolderNames(repoPath) {
|
|
|
3164
3882
|
const renameMappings = [
|
|
3165
3883
|
{ from: "skill", to: "skills" },
|
|
3166
3884
|
{ from: "command", to: "commands" },
|
|
3167
|
-
{ from: "rule", to: "rules" }
|
|
3168
|
-
{ from: "agent", to: "agents" },
|
|
3169
|
-
{ from: "subagent", to: "subagents" }
|
|
3885
|
+
{ from: "rule", to: "rules" }
|
|
3170
3886
|
];
|
|
3171
3887
|
for (const { from, to } of renameMappings) {
|
|
3172
|
-
const fromPath =
|
|
3173
|
-
const toPath =
|
|
3174
|
-
if (
|
|
3888
|
+
const fromPath = join8(repoPath, from);
|
|
3889
|
+
const toPath = join8(repoPath, to);
|
|
3890
|
+
if (existsSync12(fromPath) && !existsSync12(toPath)) {
|
|
3175
3891
|
try {
|
|
3176
3892
|
const stats = await stat(fromPath);
|
|
3177
3893
|
if (stats.isDirectory()) {
|
|
@@ -3260,7 +3976,7 @@ repository = "${repoUrl}"
|
|
|
3260
3976
|
wrapped = true
|
|
3261
3977
|
commit = "${commit}"
|
|
3262
3978
|
`;
|
|
3263
|
-
await
|
|
3979
|
+
await writeFile3(join8(repoPath, "capability.toml"), tomlContent, "utf-8");
|
|
3264
3980
|
}
|
|
3265
3981
|
async function fetchGitCapabilitySource(id, config, options) {
|
|
3266
3982
|
const gitUrl = sourceToGitUrl(config.source);
|
|
@@ -3270,29 +3986,29 @@ async function fetchGitCapabilitySource(id, config, options) {
|
|
|
3270
3986
|
let repoPath;
|
|
3271
3987
|
const gitRef = config.version && config.version !== "latest" ? config.version : undefined;
|
|
3272
3988
|
if (config.path) {
|
|
3273
|
-
const tempPath =
|
|
3274
|
-
if (
|
|
3989
|
+
const tempPath = join8(OMNI_LOCAL, "_temp", `${id}-repo`);
|
|
3990
|
+
if (existsSync12(join8(tempPath, ".git"))) {
|
|
3275
3991
|
updated = await fetchRepo(tempPath, gitRef);
|
|
3276
3992
|
commit = await getRepoCommit(tempPath);
|
|
3277
3993
|
} else {
|
|
3278
|
-
await
|
|
3994
|
+
await mkdir(join8(tempPath, ".."), { recursive: true });
|
|
3279
3995
|
await cloneRepo(gitUrl, tempPath, gitRef);
|
|
3280
3996
|
commit = await getRepoCommit(tempPath);
|
|
3281
3997
|
updated = true;
|
|
3282
3998
|
}
|
|
3283
|
-
const sourcePath =
|
|
3284
|
-
if (!
|
|
3999
|
+
const sourcePath = join8(tempPath, config.path);
|
|
4000
|
+
if (!existsSync12(sourcePath)) {
|
|
3285
4001
|
throw new Error(`Path not found in repository: ${config.path}`);
|
|
3286
4002
|
}
|
|
3287
|
-
if (
|
|
4003
|
+
if (existsSync12(targetPath)) {
|
|
3288
4004
|
await rm(targetPath, { recursive: true });
|
|
3289
4005
|
}
|
|
3290
|
-
await
|
|
4006
|
+
await mkdir(join8(targetPath, ".."), { recursive: true });
|
|
3291
4007
|
await cp(sourcePath, targetPath, { recursive: true });
|
|
3292
4008
|
await rm(tempPath, { recursive: true });
|
|
3293
4009
|
repoPath = targetPath;
|
|
3294
4010
|
} else {
|
|
3295
|
-
if (
|
|
4011
|
+
if (existsSync12(join8(targetPath, ".git"))) {
|
|
3296
4012
|
if (!options?.silent) {
|
|
3297
4013
|
console.log(` Checking ${id}...`);
|
|
3298
4014
|
}
|
|
@@ -3343,7 +4059,7 @@ async function fetchGitCapabilitySource(id, config, options) {
|
|
|
3343
4059
|
async function fetchFileCapabilitySource(id, config, options) {
|
|
3344
4060
|
const sourcePath = parseFileSourcePath(config.source);
|
|
3345
4061
|
const targetPath = getSourceCapabilityPath(id);
|
|
3346
|
-
if (!
|
|
4062
|
+
if (!existsSync12(sourcePath)) {
|
|
3347
4063
|
throw new Error(`File source not found: ${sourcePath}`);
|
|
3348
4064
|
}
|
|
3349
4065
|
const sourceStats = await stat(sourcePath);
|
|
@@ -3351,7 +4067,7 @@ async function fetchFileCapabilitySource(id, config, options) {
|
|
|
3351
4067
|
throw new Error(`File source must be a directory: ${sourcePath}`);
|
|
3352
4068
|
}
|
|
3353
4069
|
const contentHash = await computeContentHash(sourcePath);
|
|
3354
|
-
const hasCapToml =
|
|
4070
|
+
const hasCapToml = existsSync12(join8(sourcePath, "capability.toml"));
|
|
3355
4071
|
let needsWrap = false;
|
|
3356
4072
|
if (!hasCapToml) {
|
|
3357
4073
|
needsWrap = await shouldWrapDirectory(sourcePath);
|
|
@@ -3362,10 +4078,10 @@ async function fetchFileCapabilitySource(id, config, options) {
|
|
|
3362
4078
|
if (!options?.silent) {
|
|
3363
4079
|
console.log(` Copying ${id} from ${sourcePath}...`);
|
|
3364
4080
|
}
|
|
3365
|
-
if (
|
|
4081
|
+
if (existsSync12(targetPath)) {
|
|
3366
4082
|
await rm(targetPath, { recursive: true });
|
|
3367
4083
|
}
|
|
3368
|
-
await
|
|
4084
|
+
await mkdir(join8(targetPath, ".."), { recursive: true });
|
|
3369
4085
|
await cp(sourcePath, targetPath, { recursive: true });
|
|
3370
4086
|
if (needsWrap) {
|
|
3371
4087
|
await normalizeFolderNames(targetPath);
|
|
@@ -3445,7 +4161,7 @@ description = "${description}"
|
|
|
3445
4161
|
wrapped = true
|
|
3446
4162
|
source = "${source}"
|
|
3447
4163
|
`;
|
|
3448
|
-
await
|
|
4164
|
+
await writeFile3(join8(targetPath, "capability.toml"), tomlContent, "utf-8");
|
|
3449
4165
|
}
|
|
3450
4166
|
async function fetchCapabilitySource(id, sourceConfig, options) {
|
|
3451
4167
|
const config = parseSourceConfig(sourceConfig);
|
|
@@ -3518,11 +4234,11 @@ generated_from_omni_toml = true
|
|
|
3518
4234
|
}
|
|
3519
4235
|
async function generateMcpCapabilityToml(id, mcpConfig, targetPath) {
|
|
3520
4236
|
const tomlContent = generateMcpCapabilityTomlContent(id, mcpConfig);
|
|
3521
|
-
await
|
|
4237
|
+
await writeFile3(join8(targetPath, "capability.toml"), tomlContent, "utf-8");
|
|
3522
4238
|
}
|
|
3523
4239
|
async function isGeneratedMcpCapability(capabilityDir) {
|
|
3524
|
-
const tomlPath =
|
|
3525
|
-
if (!
|
|
4240
|
+
const tomlPath = join8(capabilityDir, "capability.toml");
|
|
4241
|
+
if (!existsSync12(tomlPath)) {
|
|
3526
4242
|
console.warn("no capability.toml found in", capabilityDir);
|
|
3527
4243
|
return false;
|
|
3528
4244
|
}
|
|
@@ -3537,14 +4253,14 @@ async function isGeneratedMcpCapability(capabilityDir) {
|
|
|
3537
4253
|
}
|
|
3538
4254
|
}
|
|
3539
4255
|
async function cleanupStaleMcpCapabilities(currentMcpIds) {
|
|
3540
|
-
const capabilitiesDir =
|
|
3541
|
-
if (!
|
|
4256
|
+
const capabilitiesDir = join8(OMNI_LOCAL, "capabilities");
|
|
4257
|
+
if (!existsSync12(capabilitiesDir)) {
|
|
3542
4258
|
return;
|
|
3543
4259
|
}
|
|
3544
4260
|
const entries = await readdir(capabilitiesDir, { withFileTypes: true });
|
|
3545
4261
|
for (const entry of entries) {
|
|
3546
4262
|
if (entry.isDirectory()) {
|
|
3547
|
-
const capDir =
|
|
4263
|
+
const capDir = join8(capabilitiesDir, entry.name);
|
|
3548
4264
|
const isGenerated = await isGeneratedMcpCapability(capDir);
|
|
3549
4265
|
if (isGenerated && !currentMcpIds.has(entry.name)) {
|
|
3550
4266
|
await rm(capDir, { recursive: true });
|
|
@@ -3557,20 +4273,20 @@ async function generateMcpCapabilities(config) {
|
|
|
3557
4273
|
await cleanupStaleMcpCapabilities(new Set);
|
|
3558
4274
|
return;
|
|
3559
4275
|
}
|
|
3560
|
-
const mcpCapabilitiesDir =
|
|
4276
|
+
const mcpCapabilitiesDir = join8(OMNI_LOCAL, "capabilities");
|
|
3561
4277
|
const currentMcpIds = new Set;
|
|
3562
4278
|
for (const [id, mcpConfig] of Object.entries(config.mcps)) {
|
|
3563
|
-
const targetPath =
|
|
4279
|
+
const targetPath = join8(mcpCapabilitiesDir, id);
|
|
3564
4280
|
currentMcpIds.add(id);
|
|
3565
|
-
await
|
|
4281
|
+
await mkdir(targetPath, { recursive: true });
|
|
3566
4282
|
await generateMcpCapabilityToml(id, mcpConfig, targetPath);
|
|
3567
4283
|
}
|
|
3568
4284
|
await cleanupStaleMcpCapabilities(currentMcpIds);
|
|
3569
4285
|
}
|
|
3570
4286
|
async function fetchAllCapabilitySources(config, options) {
|
|
3571
4287
|
await generateMcpCapabilities(config);
|
|
3572
|
-
const tempDir =
|
|
3573
|
-
if (
|
|
4288
|
+
const tempDir = join8(OMNI_LOCAL, "_temp");
|
|
4289
|
+
if (existsSync12(tempDir)) {
|
|
3574
4290
|
await rm(tempDir, { recursive: true });
|
|
3575
4291
|
}
|
|
3576
4292
|
const sources = config.capabilities?.sources;
|
|
@@ -3656,7 +4372,7 @@ async function checkForUpdates(config) {
|
|
|
3656
4372
|
continue;
|
|
3657
4373
|
}
|
|
3658
4374
|
const gitConfig = sourceConfig;
|
|
3659
|
-
if (!
|
|
4375
|
+
if (!existsSync12(join8(targetPath, ".git"))) {
|
|
3660
4376
|
updates.push({
|
|
3661
4377
|
id,
|
|
3662
4378
|
source: gitConfig.source,
|
|
@@ -3699,12 +4415,12 @@ function checkVersionMismatch(lockEntry, currentCommit, currentVersion) {
|
|
|
3699
4415
|
}
|
|
3700
4416
|
async function verifyIntegrity(id, lockEntry) {
|
|
3701
4417
|
const capabilityPath = getSourceCapabilityPath(id);
|
|
3702
|
-
if (!
|
|
4418
|
+
if (!existsSync12(capabilityPath)) {
|
|
3703
4419
|
return "capability directory missing";
|
|
3704
4420
|
}
|
|
3705
4421
|
if (lockEntry.commit) {
|
|
3706
|
-
const gitDir =
|
|
3707
|
-
if (
|
|
4422
|
+
const gitDir = join8(capabilityPath, ".git");
|
|
4423
|
+
if (existsSync12(gitDir)) {
|
|
3708
4424
|
try {
|
|
3709
4425
|
const currentCommit = await getRepoCommit(capabilityPath);
|
|
3710
4426
|
if (currentCommit !== lockEntry.commit) {
|
|
@@ -3769,13 +4485,14 @@ var init_hooks = __esm(() => {
|
|
|
3769
4485
|
init_variables();
|
|
3770
4486
|
init_loader();
|
|
3771
4487
|
init_merger();
|
|
4488
|
+
init_json_loader();
|
|
3772
4489
|
});
|
|
3773
4490
|
|
|
3774
4491
|
// ../core/src/config/provider.ts
|
|
3775
|
-
import { existsSync as
|
|
3776
|
-
import { readFile as readFile10, writeFile as
|
|
4492
|
+
import { existsSync as existsSync13 } from "node:fs";
|
|
4493
|
+
import { readFile as readFile10, writeFile as writeFile4 } from "node:fs/promises";
|
|
3777
4494
|
async function loadProviderConfig() {
|
|
3778
|
-
if (!
|
|
4495
|
+
if (!existsSync13(PROVIDER_CONFIG_PATH)) {
|
|
3779
4496
|
return { provider: "claude" };
|
|
3780
4497
|
}
|
|
3781
4498
|
const content = await readFile10(PROVIDER_CONFIG_PATH, "utf-8");
|
|
@@ -3805,7 +4522,7 @@ async function writeProviderConfig(config) {
|
|
|
3805
4522
|
lines.push("# Default: Claude");
|
|
3806
4523
|
lines.push('provider = "claude"');
|
|
3807
4524
|
}
|
|
3808
|
-
await
|
|
4525
|
+
await writeFile4(PROVIDER_CONFIG_PATH, `${lines.join(`
|
|
3809
4526
|
`)}
|
|
3810
4527
|
`, "utf-8");
|
|
3811
4528
|
}
|
|
@@ -3825,16 +4542,16 @@ var init_provider = __esm(() => {
|
|
|
3825
4542
|
});
|
|
3826
4543
|
|
|
3827
4544
|
// ../core/src/config/toml-patcher.ts
|
|
3828
|
-
import { existsSync as
|
|
3829
|
-
import { readFile as readFile11, writeFile as
|
|
4545
|
+
import { existsSync as existsSync14 } from "node:fs";
|
|
4546
|
+
import { readFile as readFile11, writeFile as writeFile5 } from "node:fs/promises";
|
|
3830
4547
|
async function readConfigFile() {
|
|
3831
|
-
if (!
|
|
4548
|
+
if (!existsSync14(CONFIG_PATH2)) {
|
|
3832
4549
|
return "";
|
|
3833
4550
|
}
|
|
3834
4551
|
return readFile11(CONFIG_PATH2, "utf-8");
|
|
3835
4552
|
}
|
|
3836
4553
|
async function writeConfigFile(content) {
|
|
3837
|
-
await
|
|
4554
|
+
await writeFile5(CONFIG_PATH2, content, "utf-8");
|
|
3838
4555
|
}
|
|
3839
4556
|
function findSection(lines, sectionPattern) {
|
|
3840
4557
|
return lines.findIndex((line) => sectionPattern.test(line.trim()));
|
|
@@ -4053,10 +4770,10 @@ var init_config2 = __esm(() => {
|
|
|
4053
4770
|
});
|
|
4054
4771
|
|
|
4055
4772
|
// ../core/src/mcp-json/manager.ts
|
|
4056
|
-
import { existsSync as
|
|
4057
|
-
import { readFile as readFile12, writeFile as
|
|
4773
|
+
import { existsSync as existsSync15 } from "node:fs";
|
|
4774
|
+
import { readFile as readFile12, writeFile as writeFile6 } from "node:fs/promises";
|
|
4058
4775
|
async function readMcpJson() {
|
|
4059
|
-
if (!
|
|
4776
|
+
if (!existsSync15(MCP_JSON_PATH)) {
|
|
4060
4777
|
return { mcpServers: {} };
|
|
4061
4778
|
}
|
|
4062
4779
|
try {
|
|
@@ -4070,7 +4787,7 @@ async function readMcpJson() {
|
|
|
4070
4787
|
}
|
|
4071
4788
|
}
|
|
4072
4789
|
async function writeMcpJson(config2) {
|
|
4073
|
-
await
|
|
4790
|
+
await writeFile6(MCP_JSON_PATH, `${JSON.stringify(config2, null, 2)}
|
|
4074
4791
|
`, "utf-8");
|
|
4075
4792
|
}
|
|
4076
4793
|
function buildMcpServerConfig(mcp) {
|
|
@@ -4142,10 +4859,10 @@ var init_mcp_json = __esm(() => {
|
|
|
4142
4859
|
});
|
|
4143
4860
|
|
|
4144
4861
|
// ../core/src/state/manifest.ts
|
|
4145
|
-
import { existsSync as
|
|
4146
|
-
import { readFile as readFile13, writeFile as
|
|
4862
|
+
import { existsSync as existsSync16, mkdirSync as mkdirSync2, rmSync } from "node:fs";
|
|
4863
|
+
import { readFile as readFile13, writeFile as writeFile7 } from "node:fs/promises";
|
|
4147
4864
|
async function loadManifest() {
|
|
4148
|
-
if (!
|
|
4865
|
+
if (!existsSync16(MANIFEST_PATH)) {
|
|
4149
4866
|
return {
|
|
4150
4867
|
version: CURRENT_VERSION,
|
|
4151
4868
|
syncedAt: new Date().toISOString(),
|
|
@@ -4157,7 +4874,7 @@ async function loadManifest() {
|
|
|
4157
4874
|
}
|
|
4158
4875
|
async function saveManifest(manifest) {
|
|
4159
4876
|
mkdirSync2(".omni/state", { recursive: true });
|
|
4160
|
-
await
|
|
4877
|
+
await writeFile7(MANIFEST_PATH, `${JSON.stringify(manifest, null, 2)}
|
|
4161
4878
|
`, "utf-8");
|
|
4162
4879
|
}
|
|
4163
4880
|
function buildManifestFromCapabilities(capabilities2) {
|
|
@@ -4192,14 +4909,14 @@ async function cleanupStaleResources(previousManifest, currentCapabilityIds) {
|
|
|
4192
4909
|
}
|
|
4193
4910
|
for (const skillName of resources.skills) {
|
|
4194
4911
|
const skillDir = `.claude/skills/${skillName}`;
|
|
4195
|
-
if (
|
|
4912
|
+
if (existsSync16(skillDir)) {
|
|
4196
4913
|
rmSync(skillDir, { recursive: true });
|
|
4197
4914
|
result.deletedSkills.push(skillName);
|
|
4198
4915
|
}
|
|
4199
4916
|
}
|
|
4200
4917
|
for (const ruleName of resources.rules) {
|
|
4201
4918
|
const rulePath = `.cursor/rules/omnidev-${ruleName}.mdc`;
|
|
4202
|
-
if (
|
|
4919
|
+
if (existsSync16(rulePath)) {
|
|
4203
4920
|
rmSync(rulePath);
|
|
4204
4921
|
result.deletedRules.push(ruleName);
|
|
4205
4922
|
}
|
|
@@ -4211,10 +4928,10 @@ var MANIFEST_PATH = ".omni/state/manifest.json", CURRENT_VERSION = 1;
|
|
|
4211
4928
|
var init_manifest = () => {};
|
|
4212
4929
|
|
|
4213
4930
|
// ../core/src/state/providers.ts
|
|
4214
|
-
import { existsSync as
|
|
4215
|
-
import { readFile as readFile14, writeFile as
|
|
4931
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync3 } from "node:fs";
|
|
4932
|
+
import { readFile as readFile14, writeFile as writeFile8 } from "node:fs/promises";
|
|
4216
4933
|
async function readEnabledProviders() {
|
|
4217
|
-
if (!
|
|
4934
|
+
if (!existsSync17(PROVIDERS_PATH)) {
|
|
4218
4935
|
return DEFAULT_PROVIDERS;
|
|
4219
4936
|
}
|
|
4220
4937
|
try {
|
|
@@ -4228,7 +4945,7 @@ async function readEnabledProviders() {
|
|
|
4228
4945
|
async function writeEnabledProviders(providers) {
|
|
4229
4946
|
mkdirSync3(STATE_DIR2, { recursive: true });
|
|
4230
4947
|
const state = { enabled: providers };
|
|
4231
|
-
await
|
|
4948
|
+
await writeFile8(PROVIDERS_PATH, `${JSON.stringify(state, null, 2)}
|
|
4232
4949
|
`, "utf-8");
|
|
4233
4950
|
}
|
|
4234
4951
|
async function enableProvider(providerId) {
|
|
@@ -4253,10 +4970,10 @@ var init_providers = __esm(() => {
|
|
|
4253
4970
|
});
|
|
4254
4971
|
|
|
4255
4972
|
// ../core/src/state/security-allows.ts
|
|
4256
|
-
import { existsSync as
|
|
4257
|
-
import { readFile as readFile15, writeFile as
|
|
4973
|
+
import { existsSync as existsSync18, mkdirSync as mkdirSync4 } from "node:fs";
|
|
4974
|
+
import { readFile as readFile15, writeFile as writeFile9 } from "node:fs/promises";
|
|
4258
4975
|
async function readSecurityAllows() {
|
|
4259
|
-
if (!
|
|
4976
|
+
if (!existsSync18(SECURITY_PATH)) {
|
|
4260
4977
|
return { ...DEFAULT_STATE };
|
|
4261
4978
|
}
|
|
4262
4979
|
try {
|
|
@@ -4270,7 +4987,7 @@ async function readSecurityAllows() {
|
|
|
4270
4987
|
async function writeSecurityAllows(state) {
|
|
4271
4988
|
mkdirSync4(OMNI_DIR, { recursive: true });
|
|
4272
4989
|
state.modifiedAt = new Date().toISOString();
|
|
4273
|
-
await
|
|
4990
|
+
await writeFile9(SECURITY_PATH, `${JSON.stringify(state, null, 2)}
|
|
4274
4991
|
`, "utf-8");
|
|
4275
4992
|
}
|
|
4276
4993
|
async function addSecurityAllow(capabilityId, findingType) {
|
|
@@ -4357,10 +5074,10 @@ var init_state = __esm(() => {
|
|
|
4357
5074
|
import { spawn as spawn2 } from "node:child_process";
|
|
4358
5075
|
import { mkdirSync as mkdirSync5 } from "node:fs";
|
|
4359
5076
|
async function installCapabilityDependencies(silent) {
|
|
4360
|
-
const { existsSync:
|
|
4361
|
-
const { join:
|
|
5077
|
+
const { existsSync: existsSync19, readdirSync: readdirSync7, readFileSync: readFileSync3 } = await import("node:fs");
|
|
5078
|
+
const { join: join9 } = await import("node:path");
|
|
4362
5079
|
const capabilitiesDir = ".omni/capabilities";
|
|
4363
|
-
if (!
|
|
5080
|
+
if (!existsSync19(capabilitiesDir)) {
|
|
4364
5081
|
return;
|
|
4365
5082
|
}
|
|
4366
5083
|
const entries = readdirSync7(capabilitiesDir, { withFileTypes: true });
|
|
@@ -4380,13 +5097,13 @@ async function installCapabilityDependencies(silent) {
|
|
|
4380
5097
|
if (!entry.isDirectory()) {
|
|
4381
5098
|
continue;
|
|
4382
5099
|
}
|
|
4383
|
-
const capabilityPath =
|
|
4384
|
-
const packageJsonPath =
|
|
4385
|
-
if (!
|
|
5100
|
+
const capabilityPath = join9(capabilitiesDir, entry.name);
|
|
5101
|
+
const packageJsonPath = join9(capabilityPath, "package.json");
|
|
5102
|
+
if (!existsSync19(packageJsonPath)) {
|
|
4386
5103
|
continue;
|
|
4387
5104
|
}
|
|
4388
5105
|
await new Promise((resolve2, reject) => {
|
|
4389
|
-
const useNpmCi = hasNpm &&
|
|
5106
|
+
const useNpmCi = hasNpm && existsSync19(join9(capabilityPath, "package-lock.json"));
|
|
4390
5107
|
const cmd = hasBun ? "bun" : "npm";
|
|
4391
5108
|
const args = hasBun ? ["install"] : useNpmCi ? ["ci"] : ["install"];
|
|
4392
5109
|
const proc = spawn2(cmd, args, {
|
|
@@ -4409,39 +5126,39 @@ ${stderr}`));
|
|
|
4409
5126
|
reject(error);
|
|
4410
5127
|
});
|
|
4411
5128
|
});
|
|
4412
|
-
const hasIndexTs =
|
|
4413
|
-
|
|
4414
|
-
|
|
4415
|
-
|
|
4416
|
-
|
|
4417
|
-
|
|
4418
|
-
|
|
4419
|
-
|
|
4420
|
-
|
|
4421
|
-
|
|
4422
|
-
|
|
4423
|
-
|
|
4424
|
-
|
|
4425
|
-
|
|
4426
|
-
|
|
4427
|
-
|
|
4428
|
-
|
|
4429
|
-
|
|
4430
|
-
|
|
4431
|
-
|
|
4432
|
-
|
|
4433
|
-
|
|
4434
|
-
|
|
4435
|
-
} else {
|
|
4436
|
-
reject(new Error(`Failed to build capability ${capabilityPath}:
|
|
5129
|
+
const hasIndexTs = existsSync19(join9(capabilityPath, "index.ts"));
|
|
5130
|
+
let hasBuildScript = false;
|
|
5131
|
+
try {
|
|
5132
|
+
const pkgJson = JSON.parse(readFileSync3(packageJsonPath, "utf-8"));
|
|
5133
|
+
hasBuildScript = Boolean(pkgJson.scripts?.build);
|
|
5134
|
+
} catch {}
|
|
5135
|
+
if (hasBuildScript) {
|
|
5136
|
+
await new Promise((resolve2, reject) => {
|
|
5137
|
+
const cmd = hasBun ? "bun" : "npm";
|
|
5138
|
+
const args = ["run", "build"];
|
|
5139
|
+
const proc = spawn2(cmd, args, {
|
|
5140
|
+
cwd: capabilityPath,
|
|
5141
|
+
stdio: "pipe"
|
|
5142
|
+
});
|
|
5143
|
+
let stderr = "";
|
|
5144
|
+
proc.stderr?.on("data", (data) => {
|
|
5145
|
+
stderr += data.toString();
|
|
5146
|
+
});
|
|
5147
|
+
proc.on("close", (code) => {
|
|
5148
|
+
if (code === 0) {
|
|
5149
|
+
resolve2();
|
|
5150
|
+
} else {
|
|
5151
|
+
reject(new Error(`Failed to build capability ${capabilityPath}:
|
|
4437
5152
|
${stderr}`));
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
});
|
|
5153
|
+
}
|
|
5154
|
+
});
|
|
5155
|
+
proc.on("error", (error) => {
|
|
5156
|
+
reject(error);
|
|
4443
5157
|
});
|
|
4444
|
-
}
|
|
5158
|
+
});
|
|
5159
|
+
} else if (hasIndexTs && !silent) {
|
|
5160
|
+
const hasBuiltIndex = existsSync19(join9(capabilityPath, "dist", "index.js"));
|
|
5161
|
+
if (!hasBuiltIndex) {
|
|
4445
5162
|
console.warn(`Warning: Capability at ${capabilityPath} has index.ts but no build script.
|
|
4446
5163
|
Add a "build" script to package.json (e.g., "build": "tsc") to compile TypeScript.`);
|
|
4447
5164
|
}
|
|
@@ -4579,9 +5296,9 @@ var init_types3 = __esm(() => {
|
|
|
4579
5296
|
});
|
|
4580
5297
|
|
|
4581
5298
|
// ../core/src/security/scanner.ts
|
|
4582
|
-
import { existsSync as
|
|
5299
|
+
import { existsSync as existsSync19 } from "node:fs";
|
|
4583
5300
|
import { lstat, readdir as readdir2, readFile as readFile16, readlink, realpath } from "node:fs/promises";
|
|
4584
|
-
import { join as
|
|
5301
|
+
import { join as join9, relative, resolve as resolve2 } from "node:path";
|
|
4585
5302
|
async function scanFileForUnicode(filePath, relativePath) {
|
|
4586
5303
|
const findings = [];
|
|
4587
5304
|
try {
|
|
@@ -4665,7 +5382,7 @@ async function scanFileForScripts(filePath, relativePath) {
|
|
|
4665
5382
|
async function checkSymlink(symlinkPath, relativePath, capabilityRoot) {
|
|
4666
5383
|
try {
|
|
4667
5384
|
const linkTarget = await readlink(symlinkPath);
|
|
4668
|
-
const resolvedTarget = resolve2(
|
|
5385
|
+
const resolvedTarget = resolve2(join9(symlinkPath, "..", linkTarget));
|
|
4669
5386
|
const normalizedRoot = await realpath(capabilityRoot);
|
|
4670
5387
|
if (linkTarget.startsWith("/")) {
|
|
4671
5388
|
return {
|
|
@@ -4700,7 +5417,7 @@ function isTextFile(filePath) {
|
|
|
4700
5417
|
async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_SCAN_SETTINGS) {
|
|
4701
5418
|
const startTime = Date.now();
|
|
4702
5419
|
const findings = [];
|
|
4703
|
-
if (!
|
|
5420
|
+
if (!existsSync19(capabilityPath)) {
|
|
4704
5421
|
return {
|
|
4705
5422
|
capabilityId,
|
|
4706
5423
|
path: capabilityPath,
|
|
@@ -4712,7 +5429,7 @@ async function scanCapability(capabilityId, capabilityPath, settings = DEFAULT_S
|
|
|
4712
5429
|
async function scanDirectory(dirPath) {
|
|
4713
5430
|
const entries = await readdir2(dirPath, { withFileTypes: true });
|
|
4714
5431
|
for (const entry of entries) {
|
|
4715
|
-
const fullPath =
|
|
5432
|
+
const fullPath = join9(dirPath, entry.name);
|
|
4716
5433
|
const relativePath = relative(capabilityPath, fullPath);
|
|
4717
5434
|
if (entry.name.startsWith(".") || entry.name === "node_modules" || entry.name === "__pycache__") {
|
|
4718
5435
|
continue;
|
|
@@ -5172,6 +5889,7 @@ __export(exports_src, {
|
|
|
5172
5889
|
verifyIntegrity: () => verifyIntegrity,
|
|
5173
5890
|
validateHooksConfig: () => validateHooksConfig,
|
|
5174
5891
|
validateHook: () => validateHook,
|
|
5892
|
+
validateGitCapability: () => validateGitCapability,
|
|
5175
5893
|
transformToOmnidev: () => transformToOmnidev,
|
|
5176
5894
|
transformToClaude: () => transformToClaude,
|
|
5177
5895
|
transformHooksConfig: () => transformHooksConfig,
|
|
@@ -5185,6 +5903,8 @@ __export(exports_src, {
|
|
|
5185
5903
|
saveManifest: () => saveManifest,
|
|
5186
5904
|
saveLockFile: () => saveLockFile,
|
|
5187
5905
|
resolveEnabledCapabilities: () => resolveEnabledCapabilities,
|
|
5906
|
+
resolveCapabilityRootInConfig: () => resolveCapabilityRootInConfig,
|
|
5907
|
+
resolveCapabilityRoot: () => resolveCapabilityRoot,
|
|
5188
5908
|
removeSecurityAllow: () => removeSecurityAllow,
|
|
5189
5909
|
readSecurityAllows: () => readSecurityAllows,
|
|
5190
5910
|
readMcpJson: () => readMcpJson,
|
|
@@ -5208,6 +5928,7 @@ __export(exports_src, {
|
|
|
5208
5928
|
loadProfileConfig: () => loadProfileConfig,
|
|
5209
5929
|
loadManifest: () => loadManifest,
|
|
5210
5930
|
loadLockFile: () => loadLockFile,
|
|
5931
|
+
loadHooksJson: () => loadHooksJson,
|
|
5211
5932
|
loadHooksFromCapability: () => loadHooksFromCapability,
|
|
5212
5933
|
loadDocs: () => loadDocs,
|
|
5213
5934
|
loadConfig: () => loadConfig,
|
|
@@ -5290,7 +6011,8 @@ __export(exports_src, {
|
|
|
5290
6011
|
DEFAULT_SCAN_SETTINGS: () => DEFAULT_SCAN_SETTINGS,
|
|
5291
6012
|
DEFAULT_PROMPT_TIMEOUT: () => DEFAULT_PROMPT_TIMEOUT,
|
|
5292
6013
|
DEFAULT_COMMAND_TIMEOUT: () => DEFAULT_COMMAND_TIMEOUT,
|
|
5293
|
-
COMMON_TOOL_MATCHERS: () => COMMON_TOOL_MATCHERS
|
|
6014
|
+
COMMON_TOOL_MATCHERS: () => COMMON_TOOL_MATCHERS,
|
|
6015
|
+
CLAUDE_HOOKS_CONFIG_FILENAME: () => CLAUDE_HOOKS_CONFIG_FILENAME
|
|
5294
6016
|
});
|
|
5295
6017
|
function getVersion() {
|
|
5296
6018
|
return version;
|
|
@@ -5311,51 +6033,59 @@ var init_src = __esm(() => {
|
|
|
5311
6033
|
import { run } from "@stricli/core";
|
|
5312
6034
|
|
|
5313
6035
|
// src/lib/dynamic-app.ts
|
|
5314
|
-
import { existsSync as
|
|
6036
|
+
import { existsSync as existsSync29 } from "node:fs";
|
|
5315
6037
|
import { createRequire as createRequire2 } from "node:module";
|
|
5316
|
-
import { join as
|
|
6038
|
+
import { join as join26 } from "node:path";
|
|
5317
6039
|
import { buildApplication, buildRouteMap as buildRouteMap7 } from "@stricli/core";
|
|
5318
6040
|
|
|
5319
6041
|
// src/commands/add.ts
|
|
5320
|
-
import { existsSync as
|
|
5321
|
-
import { basename as
|
|
6042
|
+
import { existsSync as existsSync22 } from "node:fs";
|
|
6043
|
+
import { basename as basename5, resolve as resolve3 } from "node:path";
|
|
5322
6044
|
|
|
5323
|
-
// ../adapters/src/writers/
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
|
|
5327
|
-
|
|
5328
|
-
|
|
5329
|
-
const
|
|
5330
|
-
|
|
5331
|
-
|
|
5332
|
-
|
|
5333
|
-
const rulePath = join(rulesDir, `omnidev-${rule.name}.mdc`);
|
|
5334
|
-
await writeFile(rulePath, rule.content, "utf-8");
|
|
5335
|
-
filesWritten.push(join(ctx.outputPath, `omnidev-${rule.name}.mdc`));
|
|
6045
|
+
// ../adapters/src/writers/generic/executor.ts
|
|
6046
|
+
async function executeWriters(writerConfigs, bundle, projectRoot) {
|
|
6047
|
+
const seen = new Set;
|
|
6048
|
+
const uniqueConfigs = [];
|
|
6049
|
+
let deduplicatedCount = 0;
|
|
6050
|
+
for (const config of writerConfigs) {
|
|
6051
|
+
const key = `${config.writer.id}:${config.outputPath}`;
|
|
6052
|
+
if (seen.has(key)) {
|
|
6053
|
+
deduplicatedCount++;
|
|
6054
|
+
continue;
|
|
5336
6055
|
}
|
|
5337
|
-
|
|
5338
|
-
|
|
5339
|
-
};
|
|
6056
|
+
seen.add(key);
|
|
6057
|
+
uniqueConfigs.push(config);
|
|
5340
6058
|
}
|
|
5341
|
-
|
|
5342
|
-
|
|
6059
|
+
const allFilesWritten = [];
|
|
6060
|
+
for (const config of uniqueConfigs) {
|
|
6061
|
+
const result = await config.writer.write(bundle, {
|
|
6062
|
+
outputPath: config.outputPath,
|
|
6063
|
+
projectRoot
|
|
6064
|
+
});
|
|
6065
|
+
allFilesWritten.push(...result.filesWritten);
|
|
6066
|
+
}
|
|
6067
|
+
return {
|
|
6068
|
+
filesWritten: allFilesWritten,
|
|
6069
|
+
deduplicatedCount
|
|
6070
|
+
};
|
|
6071
|
+
}
|
|
6072
|
+
// ../adapters/src/writers/generic/hooks.ts
|
|
5343
6073
|
init_src();
|
|
5344
|
-
import { existsSync as
|
|
5345
|
-
import { mkdir as
|
|
5346
|
-
import { dirname, join as
|
|
6074
|
+
import { existsSync as existsSync20 } from "node:fs";
|
|
6075
|
+
import { mkdir as mkdir2, readFile as readFile17, writeFile as writeFile10 } from "node:fs/promises";
|
|
6076
|
+
import { dirname, join as join10 } from "node:path";
|
|
5347
6077
|
var HooksWriter = {
|
|
5348
6078
|
id: "hooks",
|
|
5349
6079
|
async write(bundle, ctx) {
|
|
5350
6080
|
if (!bundle.hooks) {
|
|
5351
6081
|
return { filesWritten: [] };
|
|
5352
6082
|
}
|
|
5353
|
-
const settingsPath =
|
|
6083
|
+
const settingsPath = join10(ctx.projectRoot, ctx.outputPath);
|
|
5354
6084
|
const parentDir = dirname(settingsPath);
|
|
5355
|
-
await
|
|
6085
|
+
await mkdir2(parentDir, { recursive: true });
|
|
5356
6086
|
const claudeHooks = transformHooksConfig(bundle.hooks, "toClaude");
|
|
5357
6087
|
let existingSettings = {};
|
|
5358
|
-
if (
|
|
6088
|
+
if (existsSync20(settingsPath)) {
|
|
5359
6089
|
try {
|
|
5360
6090
|
const content = await readFile17(settingsPath, "utf-8");
|
|
5361
6091
|
existingSettings = JSON.parse(content);
|
|
@@ -5367,28 +6097,28 @@ var HooksWriter = {
|
|
|
5367
6097
|
...existingSettings,
|
|
5368
6098
|
hooks: claudeHooks
|
|
5369
6099
|
};
|
|
5370
|
-
await
|
|
6100
|
+
await writeFile10(settingsPath, `${JSON.stringify(newSettings, null, 2)}
|
|
5371
6101
|
`, "utf-8");
|
|
5372
6102
|
return {
|
|
5373
6103
|
filesWritten: [ctx.outputPath]
|
|
5374
6104
|
};
|
|
5375
6105
|
}
|
|
5376
6106
|
};
|
|
5377
|
-
// ../adapters/src/writers/instructions-md.ts
|
|
5378
|
-
import { existsSync as
|
|
5379
|
-
import { mkdir as
|
|
5380
|
-
import { dirname as dirname2, join as
|
|
6107
|
+
// ../adapters/src/writers/generic/instructions-md.ts
|
|
6108
|
+
import { existsSync as existsSync21 } from "node:fs";
|
|
6109
|
+
import { mkdir as mkdir3, readFile as readFile18, writeFile as writeFile11 } from "node:fs/promises";
|
|
6110
|
+
import { dirname as dirname2, join as join11 } from "node:path";
|
|
5381
6111
|
var InstructionsMdWriter = {
|
|
5382
6112
|
id: "instructions-md",
|
|
5383
6113
|
async write(bundle, ctx) {
|
|
5384
|
-
const outputFullPath =
|
|
6114
|
+
const outputFullPath = join11(ctx.projectRoot, ctx.outputPath);
|
|
5385
6115
|
const parentDir = dirname2(outputFullPath);
|
|
5386
6116
|
if (parentDir !== ctx.projectRoot) {
|
|
5387
|
-
await
|
|
6117
|
+
await mkdir3(parentDir, { recursive: true });
|
|
5388
6118
|
}
|
|
5389
|
-
const omniMdPath =
|
|
6119
|
+
const omniMdPath = join11(ctx.projectRoot, "OMNI.md");
|
|
5390
6120
|
let omniMdContent = "";
|
|
5391
|
-
if (
|
|
6121
|
+
if (existsSync21(omniMdPath)) {
|
|
5392
6122
|
omniMdContent = await readFile18(omniMdPath, "utf-8");
|
|
5393
6123
|
}
|
|
5394
6124
|
let content = omniMdContent;
|
|
@@ -5398,66 +6128,121 @@ var InstructionsMdWriter = {
|
|
|
5398
6128
|
${bundle.instructionsContent}
|
|
5399
6129
|
`;
|
|
5400
6130
|
}
|
|
5401
|
-
await
|
|
6131
|
+
await writeFile11(outputFullPath, content, "utf-8");
|
|
5402
6132
|
return {
|
|
5403
6133
|
filesWritten: [ctx.outputPath]
|
|
5404
6134
|
};
|
|
5405
6135
|
}
|
|
5406
6136
|
};
|
|
5407
|
-
// ../adapters/src/writers/skills.ts
|
|
5408
|
-
import { mkdir as
|
|
5409
|
-
import { join as
|
|
6137
|
+
// ../adapters/src/writers/generic/skills.ts
|
|
6138
|
+
import { mkdir as mkdir4, writeFile as writeFile12 } from "node:fs/promises";
|
|
6139
|
+
import { join as join12 } from "node:path";
|
|
5410
6140
|
var SkillsWriter = {
|
|
5411
6141
|
id: "skills",
|
|
5412
6142
|
async write(bundle, ctx) {
|
|
5413
|
-
const skillsDir =
|
|
5414
|
-
await
|
|
6143
|
+
const skillsDir = join12(ctx.projectRoot, ctx.outputPath);
|
|
6144
|
+
await mkdir4(skillsDir, { recursive: true });
|
|
5415
6145
|
const filesWritten = [];
|
|
5416
6146
|
for (const skill of bundle.skills) {
|
|
5417
|
-
const skillDir =
|
|
5418
|
-
await
|
|
5419
|
-
const skillPath =
|
|
6147
|
+
const skillDir = join12(skillsDir, skill.name);
|
|
6148
|
+
await mkdir4(skillDir, { recursive: true });
|
|
6149
|
+
const skillPath = join12(skillDir, "SKILL.md");
|
|
5420
6150
|
const content = `---
|
|
5421
6151
|
name: ${skill.name}
|
|
5422
6152
|
description: "${skill.description}"
|
|
5423
6153
|
---
|
|
5424
6154
|
|
|
5425
6155
|
${skill.instructions}`;
|
|
5426
|
-
await
|
|
5427
|
-
filesWritten.push(
|
|
6156
|
+
await writeFile12(skillPath, content, "utf-8");
|
|
6157
|
+
filesWritten.push(join12(ctx.outputPath, skill.name, "SKILL.md"));
|
|
5428
6158
|
}
|
|
5429
6159
|
return {
|
|
5430
6160
|
filesWritten
|
|
5431
6161
|
};
|
|
5432
6162
|
}
|
|
5433
6163
|
};
|
|
5434
|
-
// ../adapters/src/writers/
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
6164
|
+
// ../adapters/src/writers/generic/commands-as-skills.ts
|
|
6165
|
+
import { mkdir as mkdir5, writeFile as writeFile13 } from "node:fs/promises";
|
|
6166
|
+
import { join as join13 } from "node:path";
|
|
6167
|
+
function generateSkillFrontmatter(command) {
|
|
6168
|
+
const lines = ["---"];
|
|
6169
|
+
lines.push(`name: ${command.name}`);
|
|
6170
|
+
lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
|
|
6171
|
+
if (command.allowedTools) {
|
|
6172
|
+
lines.push(`allowed_tools: "${command.allowedTools}"`);
|
|
6173
|
+
}
|
|
6174
|
+
lines.push("---");
|
|
6175
|
+
return lines.join(`
|
|
6176
|
+
`);
|
|
6177
|
+
}
|
|
6178
|
+
var CommandsAsSkillsWriter = {
|
|
6179
|
+
id: "commands-as-skills",
|
|
6180
|
+
async write(bundle, ctx) {
|
|
6181
|
+
const skillsDir = join13(ctx.projectRoot, ctx.outputPath);
|
|
6182
|
+
await mkdir5(skillsDir, { recursive: true });
|
|
6183
|
+
const filesWritten = [];
|
|
6184
|
+
for (const command of bundle.commands) {
|
|
6185
|
+
const commandSkillDir = join13(skillsDir, command.name);
|
|
6186
|
+
await mkdir5(commandSkillDir, { recursive: true });
|
|
6187
|
+
const frontmatter = generateSkillFrontmatter(command);
|
|
6188
|
+
const content = `${frontmatter}
|
|
6189
|
+
|
|
6190
|
+
${command.prompt}`;
|
|
6191
|
+
const skillPath = join13(commandSkillDir, "SKILL.md");
|
|
6192
|
+
await writeFile13(skillPath, content, "utf-8");
|
|
6193
|
+
filesWritten.push(join13(ctx.outputPath, command.name, "SKILL.md"));
|
|
5444
6194
|
}
|
|
5445
|
-
|
|
5446
|
-
|
|
6195
|
+
return {
|
|
6196
|
+
filesWritten
|
|
6197
|
+
};
|
|
5447
6198
|
}
|
|
5448
|
-
|
|
5449
|
-
|
|
5450
|
-
|
|
5451
|
-
|
|
5452
|
-
|
|
5453
|
-
|
|
5454
|
-
|
|
6199
|
+
};
|
|
6200
|
+
// ../adapters/src/writers/claude/agents.ts
|
|
6201
|
+
import { mkdir as mkdir6, writeFile as writeFile14 } from "node:fs/promises";
|
|
6202
|
+
import { join as join14 } from "node:path";
|
|
6203
|
+
function generateFrontmatter(agent) {
|
|
6204
|
+
const lines = ["---"];
|
|
6205
|
+
lines.push(`name: ${agent.name}`);
|
|
6206
|
+
lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
|
|
6207
|
+
if (agent.tools && agent.tools.length > 0) {
|
|
6208
|
+
lines.push(`tools: ${agent.tools.join(", ")}`);
|
|
5455
6209
|
}
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
6210
|
+
if (agent.disallowedTools && agent.disallowedTools.length > 0) {
|
|
6211
|
+
lines.push(`disallowedTools: ${agent.disallowedTools.join(", ")}`);
|
|
6212
|
+
}
|
|
6213
|
+
if (agent.model && agent.model !== "inherit") {
|
|
6214
|
+
lines.push(`model: ${agent.model}`);
|
|
6215
|
+
}
|
|
6216
|
+
if (agent.permissionMode && agent.permissionMode !== "default") {
|
|
6217
|
+
lines.push(`permissionMode: ${agent.permissionMode}`);
|
|
6218
|
+
}
|
|
6219
|
+
if (agent.skills && agent.skills.length > 0) {
|
|
6220
|
+
lines.push(`skills: ${agent.skills.join(", ")}`);
|
|
6221
|
+
}
|
|
6222
|
+
lines.push("---");
|
|
6223
|
+
return lines.join(`
|
|
6224
|
+
`);
|
|
5460
6225
|
}
|
|
6226
|
+
var ClaudeAgentsWriter = {
|
|
6227
|
+
id: "claude-agents",
|
|
6228
|
+
async write(bundle, ctx) {
|
|
6229
|
+
const agentsDir = join14(ctx.projectRoot, ctx.outputPath);
|
|
6230
|
+
await mkdir6(agentsDir, { recursive: true });
|
|
6231
|
+
const filesWritten = [];
|
|
6232
|
+
for (const agent of bundle.subagents) {
|
|
6233
|
+
const frontmatter = generateFrontmatter(agent);
|
|
6234
|
+
const content = `${frontmatter}
|
|
6235
|
+
|
|
6236
|
+
${agent.systemPrompt}`;
|
|
6237
|
+
const agentPath = join14(agentsDir, `${agent.name}.md`);
|
|
6238
|
+
await writeFile14(agentPath, content, "utf-8");
|
|
6239
|
+
filesWritten.push(join14(ctx.outputPath, `${agent.name}.md`));
|
|
6240
|
+
}
|
|
6241
|
+
return {
|
|
6242
|
+
filesWritten
|
|
6243
|
+
};
|
|
6244
|
+
}
|
|
6245
|
+
};
|
|
5461
6246
|
// ../adapters/src/claude-code/index.ts
|
|
5462
6247
|
var claudeCodeAdapter = {
|
|
5463
6248
|
id: "claude-code",
|
|
@@ -5465,6 +6250,8 @@ var claudeCodeAdapter = {
|
|
|
5465
6250
|
writers: [
|
|
5466
6251
|
{ writer: InstructionsMdWriter, outputPath: "CLAUDE.md" },
|
|
5467
6252
|
{ writer: SkillsWriter, outputPath: ".claude/skills/" },
|
|
6253
|
+
{ writer: ClaudeAgentsWriter, outputPath: ".claude/agents/" },
|
|
6254
|
+
{ writer: CommandsAsSkillsWriter, outputPath: ".claude/skills/" },
|
|
5468
6255
|
{ writer: HooksWriter, outputPath: ".claude/settings.json" }
|
|
5469
6256
|
],
|
|
5470
6257
|
async init(_ctx) {
|
|
@@ -5483,16 +6270,97 @@ var claudeCodeAdapter = {
|
|
|
5483
6270
|
};
|
|
5484
6271
|
// ../adapters/src/codex/index.ts
|
|
5485
6272
|
import { mkdirSync as mkdirSync6 } from "node:fs";
|
|
5486
|
-
import { join as
|
|
6273
|
+
import { join as join16 } from "node:path";
|
|
6274
|
+
|
|
6275
|
+
// ../adapters/src/writers/codex/toml.ts
|
|
6276
|
+
init_dist();
|
|
6277
|
+
import { mkdir as mkdir7, writeFile as writeFile15 } from "node:fs/promises";
|
|
6278
|
+
import { dirname as dirname3, join as join15 } from "node:path";
|
|
6279
|
+
var FILE_HEADER = `# Generated by OmniDev - DO NOT EDIT
|
|
6280
|
+
# Run \`omnidev sync\` to regenerate
|
|
6281
|
+
|
|
6282
|
+
`;
|
|
6283
|
+
function buildCodexMcpConfig(id, mcp) {
|
|
6284
|
+
const transport = mcp.transport ?? "stdio";
|
|
6285
|
+
if (transport === "sse") {
|
|
6286
|
+
console.warn(` Warning: Skipping MCP "${id}" - SSE transport is not supported by Codex`);
|
|
6287
|
+
return null;
|
|
6288
|
+
}
|
|
6289
|
+
const config3 = {};
|
|
6290
|
+
if (transport === "http") {
|
|
6291
|
+
if (mcp.url) {
|
|
6292
|
+
config3.url = mcp.url;
|
|
6293
|
+
}
|
|
6294
|
+
if (mcp.headers && Object.keys(mcp.headers).length > 0) {
|
|
6295
|
+
config3.http_headers = mcp.headers;
|
|
6296
|
+
}
|
|
6297
|
+
} else {
|
|
6298
|
+
if (mcp.command) {
|
|
6299
|
+
config3.command = mcp.command;
|
|
6300
|
+
}
|
|
6301
|
+
if (mcp.args && mcp.args.length > 0) {
|
|
6302
|
+
config3.args = mcp.args;
|
|
6303
|
+
}
|
|
6304
|
+
if (mcp.env && Object.keys(mcp.env).length > 0) {
|
|
6305
|
+
config3.env = mcp.env;
|
|
6306
|
+
}
|
|
6307
|
+
if (mcp.cwd) {
|
|
6308
|
+
config3.cwd = mcp.cwd;
|
|
6309
|
+
}
|
|
6310
|
+
}
|
|
6311
|
+
return config3;
|
|
6312
|
+
}
|
|
6313
|
+
function collectMcps(bundle) {
|
|
6314
|
+
const mcps = new Map;
|
|
6315
|
+
for (const capability3 of bundle.capabilities) {
|
|
6316
|
+
if (capability3.config.mcp) {
|
|
6317
|
+
mcps.set(capability3.id, capability3.config.mcp);
|
|
6318
|
+
}
|
|
6319
|
+
}
|
|
6320
|
+
return mcps;
|
|
6321
|
+
}
|
|
6322
|
+
var CodexTomlWriter = {
|
|
6323
|
+
id: "codex-toml",
|
|
6324
|
+
async write(bundle, ctx) {
|
|
6325
|
+
const mcps = collectMcps(bundle);
|
|
6326
|
+
if (mcps.size === 0) {
|
|
6327
|
+
return { filesWritten: [] };
|
|
6328
|
+
}
|
|
6329
|
+
const configPath = join15(ctx.projectRoot, ctx.outputPath);
|
|
6330
|
+
const parentDir = dirname3(configPath);
|
|
6331
|
+
await mkdir7(parentDir, { recursive: true });
|
|
6332
|
+
const mcpServers = {};
|
|
6333
|
+
for (const [id, mcp] of mcps) {
|
|
6334
|
+
const converted = buildCodexMcpConfig(id, mcp);
|
|
6335
|
+
if (converted) {
|
|
6336
|
+
mcpServers[id] = converted;
|
|
6337
|
+
}
|
|
6338
|
+
}
|
|
6339
|
+
if (Object.keys(mcpServers).length === 0) {
|
|
6340
|
+
return { filesWritten: [] };
|
|
6341
|
+
}
|
|
6342
|
+
const codexConfig = {
|
|
6343
|
+
mcp_servers: mcpServers
|
|
6344
|
+
};
|
|
6345
|
+
const tomlContent = FILE_HEADER + stringify(codexConfig);
|
|
6346
|
+
await writeFile15(configPath, tomlContent, "utf-8");
|
|
6347
|
+
return {
|
|
6348
|
+
filesWritten: [ctx.outputPath]
|
|
6349
|
+
};
|
|
6350
|
+
}
|
|
6351
|
+
};
|
|
6352
|
+
// ../adapters/src/codex/index.ts
|
|
5487
6353
|
var codexAdapter = {
|
|
5488
6354
|
id: "codex",
|
|
5489
6355
|
displayName: "Codex",
|
|
5490
6356
|
writers: [
|
|
5491
6357
|
{ writer: InstructionsMdWriter, outputPath: "AGENTS.md" },
|
|
5492
|
-
{ writer: SkillsWriter, outputPath: ".codex/skills/" }
|
|
6358
|
+
{ writer: SkillsWriter, outputPath: ".codex/skills/" },
|
|
6359
|
+
{ writer: CommandsAsSkillsWriter, outputPath: ".codex/skills/" },
|
|
6360
|
+
{ writer: CodexTomlWriter, outputPath: ".codex/config.toml" }
|
|
5493
6361
|
],
|
|
5494
6362
|
async init(ctx) {
|
|
5495
|
-
const codexDir =
|
|
6363
|
+
const codexDir = join16(ctx.projectRoot, ".codex");
|
|
5496
6364
|
mkdirSync6(codexDir, { recursive: true });
|
|
5497
6365
|
return {
|
|
5498
6366
|
filesCreated: [".codex/"],
|
|
@@ -5509,17 +6377,186 @@ var codexAdapter = {
|
|
|
5509
6377
|
};
|
|
5510
6378
|
// ../adapters/src/cursor/index.ts
|
|
5511
6379
|
import { mkdirSync as mkdirSync7 } from "node:fs";
|
|
5512
|
-
import { join as
|
|
6380
|
+
import { join as join21 } from "node:path";
|
|
6381
|
+
|
|
6382
|
+
// ../adapters/src/writers/cursor/agents.ts
|
|
6383
|
+
import { mkdir as mkdir8, writeFile as writeFile16 } from "node:fs/promises";
|
|
6384
|
+
import { join as join17 } from "node:path";
|
|
6385
|
+
function mapModelToCursor(model) {
|
|
6386
|
+
if (!model || model === "inherit")
|
|
6387
|
+
return "inherit";
|
|
6388
|
+
const modelMap = {
|
|
6389
|
+
haiku: "fast",
|
|
6390
|
+
sonnet: "inherit",
|
|
6391
|
+
opus: "inherit"
|
|
6392
|
+
};
|
|
6393
|
+
return modelMap[model] ?? "inherit";
|
|
6394
|
+
}
|
|
6395
|
+
function generateFrontmatter2(agent) {
|
|
6396
|
+
const lines = ["---"];
|
|
6397
|
+
lines.push(`name: ${agent.name}`);
|
|
6398
|
+
lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
|
|
6399
|
+
const model = mapModelToCursor(agent.model);
|
|
6400
|
+
if (model) {
|
|
6401
|
+
lines.push(`model: ${model}`);
|
|
6402
|
+
}
|
|
6403
|
+
if (agent.permissionMode === "plan") {
|
|
6404
|
+
lines.push("readonly: true");
|
|
6405
|
+
}
|
|
6406
|
+
if (agent.isBackground) {
|
|
6407
|
+
lines.push("is_background: true");
|
|
6408
|
+
}
|
|
6409
|
+
lines.push("---");
|
|
6410
|
+
return lines.join(`
|
|
6411
|
+
`);
|
|
6412
|
+
}
|
|
6413
|
+
var CursorAgentsWriter = {
|
|
6414
|
+
id: "cursor-agents",
|
|
6415
|
+
async write(bundle, ctx) {
|
|
6416
|
+
const agentsDir = join17(ctx.projectRoot, ctx.outputPath);
|
|
6417
|
+
await mkdir8(agentsDir, { recursive: true });
|
|
6418
|
+
const filesWritten = [];
|
|
6419
|
+
for (const agent of bundle.subagents) {
|
|
6420
|
+
const frontmatter = generateFrontmatter2(agent);
|
|
6421
|
+
const content = `${frontmatter}
|
|
6422
|
+
|
|
6423
|
+
${agent.systemPrompt}`;
|
|
6424
|
+
const agentPath = join17(agentsDir, `${agent.name}.md`);
|
|
6425
|
+
await writeFile16(agentPath, content, "utf-8");
|
|
6426
|
+
filesWritten.push(join17(ctx.outputPath, `${agent.name}.md`));
|
|
6427
|
+
}
|
|
6428
|
+
return {
|
|
6429
|
+
filesWritten
|
|
6430
|
+
};
|
|
6431
|
+
}
|
|
6432
|
+
};
|
|
6433
|
+
// ../adapters/src/writers/cursor/commands.ts
|
|
6434
|
+
import { mkdir as mkdir9, writeFile as writeFile17 } from "node:fs/promises";
|
|
6435
|
+
import { join as join18 } from "node:path";
|
|
6436
|
+
var CursorCommandsWriter = {
|
|
6437
|
+
id: "cursor-commands",
|
|
6438
|
+
async write(bundle, ctx) {
|
|
6439
|
+
const commandsDir = join18(ctx.projectRoot, ctx.outputPath);
|
|
6440
|
+
await mkdir9(commandsDir, { recursive: true });
|
|
6441
|
+
const filesWritten = [];
|
|
6442
|
+
for (const command of bundle.commands) {
|
|
6443
|
+
const content = `# ${command.name}
|
|
6444
|
+
|
|
6445
|
+
${command.description}
|
|
6446
|
+
|
|
6447
|
+
${command.prompt}`;
|
|
6448
|
+
const commandPath = join18(commandsDir, `${command.name}.md`);
|
|
6449
|
+
await writeFile17(commandPath, content, "utf-8");
|
|
6450
|
+
filesWritten.push(join18(ctx.outputPath, `${command.name}.md`));
|
|
6451
|
+
}
|
|
6452
|
+
return {
|
|
6453
|
+
filesWritten
|
|
6454
|
+
};
|
|
6455
|
+
}
|
|
6456
|
+
};
|
|
6457
|
+
// ../adapters/src/writers/cursor/mcp-json.ts
|
|
6458
|
+
import { mkdir as mkdir10, writeFile as writeFile18 } from "node:fs/promises";
|
|
6459
|
+
import { dirname as dirname4, join as join19 } from "node:path";
|
|
6460
|
+
function buildCursorMcpConfig(mcp) {
|
|
6461
|
+
const transport = mcp.transport ?? "stdio";
|
|
6462
|
+
if (transport === "http" || transport === "sse") {
|
|
6463
|
+
if (!mcp.url) {
|
|
6464
|
+
return null;
|
|
6465
|
+
}
|
|
6466
|
+
const config4 = {
|
|
6467
|
+
url: mcp.url
|
|
6468
|
+
};
|
|
6469
|
+
if (mcp.headers && Object.keys(mcp.headers).length > 0) {
|
|
6470
|
+
config4.headers = mcp.headers;
|
|
6471
|
+
}
|
|
6472
|
+
return config4;
|
|
6473
|
+
}
|
|
6474
|
+
if (!mcp.command) {
|
|
6475
|
+
return null;
|
|
6476
|
+
}
|
|
6477
|
+
const config3 = {
|
|
6478
|
+
command: mcp.command
|
|
6479
|
+
};
|
|
6480
|
+
if (mcp.args && mcp.args.length > 0) {
|
|
6481
|
+
config3.args = mcp.args;
|
|
6482
|
+
}
|
|
6483
|
+
if (mcp.env && Object.keys(mcp.env).length > 0) {
|
|
6484
|
+
config3.env = mcp.env;
|
|
6485
|
+
}
|
|
6486
|
+
return config3;
|
|
6487
|
+
}
|
|
6488
|
+
function collectMcps2(bundle) {
|
|
6489
|
+
const mcps = new Map;
|
|
6490
|
+
for (const capability3 of bundle.capabilities) {
|
|
6491
|
+
if (capability3.config.mcp) {
|
|
6492
|
+
mcps.set(capability3.id, capability3.config.mcp);
|
|
6493
|
+
}
|
|
6494
|
+
}
|
|
6495
|
+
return mcps;
|
|
6496
|
+
}
|
|
6497
|
+
var CursorMcpJsonWriter = {
|
|
6498
|
+
id: "cursor-mcp-json",
|
|
6499
|
+
async write(bundle, ctx) {
|
|
6500
|
+
const mcps = collectMcps2(bundle);
|
|
6501
|
+
if (mcps.size === 0) {
|
|
6502
|
+
return { filesWritten: [] };
|
|
6503
|
+
}
|
|
6504
|
+
const configPath = join19(ctx.projectRoot, ctx.outputPath);
|
|
6505
|
+
const parentDir = dirname4(configPath);
|
|
6506
|
+
await mkdir10(parentDir, { recursive: true });
|
|
6507
|
+
const mcpServers = {};
|
|
6508
|
+
for (const [id, mcp] of mcps) {
|
|
6509
|
+
const converted = buildCursorMcpConfig(mcp);
|
|
6510
|
+
if (converted) {
|
|
6511
|
+
mcpServers[id] = converted;
|
|
6512
|
+
}
|
|
6513
|
+
}
|
|
6514
|
+
if (Object.keys(mcpServers).length === 0) {
|
|
6515
|
+
return { filesWritten: [] };
|
|
6516
|
+
}
|
|
6517
|
+
const cursorMcpJson = {
|
|
6518
|
+
mcpServers
|
|
6519
|
+
};
|
|
6520
|
+
await writeFile18(configPath, `${JSON.stringify(cursorMcpJson, null, 2)}
|
|
6521
|
+
`, "utf-8");
|
|
6522
|
+
return {
|
|
6523
|
+
filesWritten: [ctx.outputPath]
|
|
6524
|
+
};
|
|
6525
|
+
}
|
|
6526
|
+
};
|
|
6527
|
+
// ../adapters/src/writers/cursor/rules.ts
|
|
6528
|
+
import { mkdir as mkdir11, writeFile as writeFile19 } from "node:fs/promises";
|
|
6529
|
+
import { join as join20 } from "node:path";
|
|
6530
|
+
var CursorRulesWriter = {
|
|
6531
|
+
id: "cursor-rules",
|
|
6532
|
+
async write(bundle, ctx) {
|
|
6533
|
+
const rulesDir = join20(ctx.projectRoot, ctx.outputPath);
|
|
6534
|
+
await mkdir11(rulesDir, { recursive: true });
|
|
6535
|
+
const filesWritten = [];
|
|
6536
|
+
for (const rule of bundle.rules) {
|
|
6537
|
+
const rulePath = join20(rulesDir, `omnidev-${rule.name}.mdc`);
|
|
6538
|
+
await writeFile19(rulePath, rule.content, "utf-8");
|
|
6539
|
+
filesWritten.push(join20(ctx.outputPath, `omnidev-${rule.name}.mdc`));
|
|
6540
|
+
}
|
|
6541
|
+
return {
|
|
6542
|
+
filesWritten
|
|
6543
|
+
};
|
|
6544
|
+
}
|
|
6545
|
+
};
|
|
6546
|
+
// ../adapters/src/cursor/index.ts
|
|
5513
6547
|
var cursorAdapter = {
|
|
5514
6548
|
id: "cursor",
|
|
5515
6549
|
displayName: "Cursor",
|
|
5516
6550
|
writers: [
|
|
5517
6551
|
{ writer: InstructionsMdWriter, outputPath: "CLAUDE.md" },
|
|
5518
|
-
{ writer: SkillsWriter, outputPath: ".
|
|
5519
|
-
{ writer: CursorRulesWriter, outputPath: ".cursor/rules/" }
|
|
6552
|
+
{ writer: SkillsWriter, outputPath: ".cursor/skills/" },
|
|
6553
|
+
{ writer: CursorRulesWriter, outputPath: ".cursor/rules/" },
|
|
6554
|
+
{ writer: CursorAgentsWriter, outputPath: ".cursor/agents/" },
|
|
6555
|
+
{ writer: CursorCommandsWriter, outputPath: ".cursor/commands/" },
|
|
6556
|
+
{ writer: CursorMcpJsonWriter, outputPath: ".cursor/mcp.json" }
|
|
5520
6557
|
],
|
|
5521
6558
|
async init(ctx) {
|
|
5522
|
-
const rulesDir =
|
|
6559
|
+
const rulesDir = join21(ctx.projectRoot, ".cursor", "rules");
|
|
5523
6560
|
mkdirSync7(rulesDir, { recursive: true });
|
|
5524
6561
|
return {
|
|
5525
6562
|
filesCreated: [".cursor/rules/"],
|
|
@@ -5536,16 +6573,153 @@ var cursorAdapter = {
|
|
|
5536
6573
|
};
|
|
5537
6574
|
// ../adapters/src/opencode/index.ts
|
|
5538
6575
|
import { mkdirSync as mkdirSync8 } from "node:fs";
|
|
5539
|
-
import { join as
|
|
6576
|
+
import { join as join24 } from "node:path";
|
|
6577
|
+
|
|
6578
|
+
// ../adapters/src/writers/opencode/agents.ts
|
|
6579
|
+
import { mkdir as mkdir12, writeFile as writeFile20 } from "node:fs/promises";
|
|
6580
|
+
import { join as join22 } from "node:path";
|
|
6581
|
+
function mapModelToOpenCode(model) {
|
|
6582
|
+
if (!model || model === "inherit")
|
|
6583
|
+
return;
|
|
6584
|
+
const modelMap = {
|
|
6585
|
+
sonnet: "anthropic/claude-sonnet-4",
|
|
6586
|
+
opus: "anthropic/claude-opus-4",
|
|
6587
|
+
haiku: "anthropic/claude-haiku-3-5"
|
|
6588
|
+
};
|
|
6589
|
+
return modelMap[model];
|
|
6590
|
+
}
|
|
6591
|
+
function mapPermissionsToOpenCode(permissionMode) {
|
|
6592
|
+
if (!permissionMode || permissionMode === "default")
|
|
6593
|
+
return;
|
|
6594
|
+
const permissionMap = {
|
|
6595
|
+
acceptEdits: { edit: "allow", bash: { "*": "ask" } },
|
|
6596
|
+
dontAsk: { edit: "allow", bash: { "*": "allow" } },
|
|
6597
|
+
bypassPermissions: { edit: "allow", bash: { "*": "allow" }, webfetch: "allow" },
|
|
6598
|
+
plan: { edit: "deny", bash: { "*": "deny" } }
|
|
6599
|
+
};
|
|
6600
|
+
return permissionMap[permissionMode];
|
|
6601
|
+
}
|
|
6602
|
+
function mapToolsToOpenCode(tools) {
|
|
6603
|
+
if (!tools || tools.length === 0)
|
|
6604
|
+
return;
|
|
6605
|
+
const toolsObject = {};
|
|
6606
|
+
for (const tool of tools) {
|
|
6607
|
+
toolsObject[tool.toLowerCase()] = true;
|
|
6608
|
+
}
|
|
6609
|
+
return toolsObject;
|
|
6610
|
+
}
|
|
6611
|
+
function generateFrontmatter3(agent) {
|
|
6612
|
+
const lines = ["---"];
|
|
6613
|
+
lines.push(`description: "${agent.description.replace(/"/g, "\\\"")}"`);
|
|
6614
|
+
const modelId = agent.modelId ?? mapModelToOpenCode(agent.model);
|
|
6615
|
+
if (modelId) {
|
|
6616
|
+
lines.push(`model: ${modelId}`);
|
|
6617
|
+
}
|
|
6618
|
+
if (agent.mode) {
|
|
6619
|
+
lines.push(`mode: ${agent.mode}`);
|
|
6620
|
+
}
|
|
6621
|
+
if (agent.temperature !== undefined) {
|
|
6622
|
+
lines.push(`temperature: ${agent.temperature}`);
|
|
6623
|
+
}
|
|
6624
|
+
if (agent.maxSteps !== undefined) {
|
|
6625
|
+
lines.push(`maxSteps: ${agent.maxSteps}`);
|
|
6626
|
+
}
|
|
6627
|
+
if (agent.hidden !== undefined) {
|
|
6628
|
+
lines.push(`hidden: ${agent.hidden}`);
|
|
6629
|
+
}
|
|
6630
|
+
const toolsObj = agent.toolPermissions ?? mapToolsToOpenCode(agent.tools);
|
|
6631
|
+
if (toolsObj) {
|
|
6632
|
+
lines.push("tools:");
|
|
6633
|
+
for (const [tool, enabled] of Object.entries(toolsObj)) {
|
|
6634
|
+
lines.push(` ${tool}: ${enabled}`);
|
|
6635
|
+
}
|
|
6636
|
+
}
|
|
6637
|
+
const permissions = agent.permissions ?? mapPermissionsToOpenCode(agent.permissionMode);
|
|
6638
|
+
if (permissions) {
|
|
6639
|
+
lines.push("permissions:");
|
|
6640
|
+
for (const [key, value] of Object.entries(permissions)) {
|
|
6641
|
+
if (typeof value === "object") {
|
|
6642
|
+
lines.push(` ${key}:`);
|
|
6643
|
+
for (const [subKey, subValue] of Object.entries(value)) {
|
|
6644
|
+
lines.push(` ${subKey}: ${subValue}`);
|
|
6645
|
+
}
|
|
6646
|
+
} else {
|
|
6647
|
+
lines.push(` ${key}: ${value}`);
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
}
|
|
6651
|
+
lines.push("---");
|
|
6652
|
+
return lines.join(`
|
|
6653
|
+
`);
|
|
6654
|
+
}
|
|
6655
|
+
var OpenCodeAgentsWriter = {
|
|
6656
|
+
id: "opencode-agents",
|
|
6657
|
+
async write(bundle, ctx) {
|
|
6658
|
+
const agentsDir = join22(ctx.projectRoot, ctx.outputPath);
|
|
6659
|
+
await mkdir12(agentsDir, { recursive: true });
|
|
6660
|
+
const filesWritten = [];
|
|
6661
|
+
for (const agent of bundle.subagents) {
|
|
6662
|
+
const frontmatter = generateFrontmatter3(agent);
|
|
6663
|
+
const content = `${frontmatter}
|
|
6664
|
+
|
|
6665
|
+
${agent.systemPrompt}`;
|
|
6666
|
+
const agentPath = join22(agentsDir, `${agent.name}.md`);
|
|
6667
|
+
await writeFile20(agentPath, content, "utf-8");
|
|
6668
|
+
filesWritten.push(join22(ctx.outputPath, `${agent.name}.md`));
|
|
6669
|
+
}
|
|
6670
|
+
return {
|
|
6671
|
+
filesWritten
|
|
6672
|
+
};
|
|
6673
|
+
}
|
|
6674
|
+
};
|
|
6675
|
+
// ../adapters/src/writers/opencode/commands.ts
|
|
6676
|
+
import { mkdir as mkdir13, writeFile as writeFile21 } from "node:fs/promises";
|
|
6677
|
+
import { join as join23 } from "node:path";
|
|
6678
|
+
function generateFrontmatter4(command) {
|
|
6679
|
+
const lines = ["---"];
|
|
6680
|
+
lines.push(`description: "${command.description.replace(/"/g, "\\\"")}"`);
|
|
6681
|
+
if (command.modelId) {
|
|
6682
|
+
lines.push(`model: ${command.modelId}`);
|
|
6683
|
+
}
|
|
6684
|
+
if (command.agent) {
|
|
6685
|
+
lines.push(`agent: ${command.agent}`);
|
|
6686
|
+
}
|
|
6687
|
+
lines.push("---");
|
|
6688
|
+
return lines.join(`
|
|
6689
|
+
`);
|
|
6690
|
+
}
|
|
6691
|
+
var OpenCodeCommandsWriter = {
|
|
6692
|
+
id: "opencode-commands",
|
|
6693
|
+
async write(bundle, ctx) {
|
|
6694
|
+
const commandsDir = join23(ctx.projectRoot, ctx.outputPath);
|
|
6695
|
+
await mkdir13(commandsDir, { recursive: true });
|
|
6696
|
+
const filesWritten = [];
|
|
6697
|
+
for (const command of bundle.commands) {
|
|
6698
|
+
const frontmatter = generateFrontmatter4(command);
|
|
6699
|
+
const content = `${frontmatter}
|
|
6700
|
+
|
|
6701
|
+
${command.prompt}`;
|
|
6702
|
+
const commandPath = join23(commandsDir, `${command.name}.md`);
|
|
6703
|
+
await writeFile21(commandPath, content, "utf-8");
|
|
6704
|
+
filesWritten.push(join23(ctx.outputPath, `${command.name}.md`));
|
|
6705
|
+
}
|
|
6706
|
+
return {
|
|
6707
|
+
filesWritten
|
|
6708
|
+
};
|
|
6709
|
+
}
|
|
6710
|
+
};
|
|
6711
|
+
// ../adapters/src/opencode/index.ts
|
|
5540
6712
|
var opencodeAdapter = {
|
|
5541
6713
|
id: "opencode",
|
|
5542
6714
|
displayName: "OpenCode",
|
|
5543
6715
|
writers: [
|
|
5544
6716
|
{ writer: InstructionsMdWriter, outputPath: "AGENTS.md" },
|
|
5545
|
-
{ writer: SkillsWriter, outputPath: ".opencode/skills/" }
|
|
6717
|
+
{ writer: SkillsWriter, outputPath: ".opencode/skills/" },
|
|
6718
|
+
{ writer: OpenCodeAgentsWriter, outputPath: ".opencode/agents/" },
|
|
6719
|
+
{ writer: OpenCodeCommandsWriter, outputPath: ".opencode/commands/" }
|
|
5546
6720
|
],
|
|
5547
6721
|
async init(ctx) {
|
|
5548
|
-
const opencodeDir =
|
|
6722
|
+
const opencodeDir = join24(ctx.projectRoot, ".opencode");
|
|
5549
6723
|
mkdirSync8(opencodeDir, { recursive: true });
|
|
5550
6724
|
return {
|
|
5551
6725
|
filesCreated: [".opencode/"],
|
|
@@ -5587,7 +6761,7 @@ async function inferCapabilityId(source, sourceType) {
|
|
|
5587
6761
|
if (id) {
|
|
5588
6762
|
return id;
|
|
5589
6763
|
}
|
|
5590
|
-
return
|
|
6764
|
+
return basename5(resolvedPath);
|
|
5591
6765
|
}
|
|
5592
6766
|
const parts = source.replace("github:", "").split("/");
|
|
5593
6767
|
if (parts.length >= 2) {
|
|
@@ -5597,7 +6771,7 @@ async function inferCapabilityId(source, sourceType) {
|
|
|
5597
6771
|
}
|
|
5598
6772
|
async function runAddCap(flags, name) {
|
|
5599
6773
|
try {
|
|
5600
|
-
if (!
|
|
6774
|
+
if (!existsSync22("omni.toml")) {
|
|
5601
6775
|
console.log("✗ No config file found");
|
|
5602
6776
|
console.log(" Run: omnidev init");
|
|
5603
6777
|
process.exit(1);
|
|
@@ -5620,7 +6794,7 @@ async function runAddCap(flags, name) {
|
|
|
5620
6794
|
sourceType = "local";
|
|
5621
6795
|
const localPath = flags.local.startsWith("file://") ? flags.local.slice(7) : flags.local;
|
|
5622
6796
|
source = `file://${localPath}`;
|
|
5623
|
-
if (!
|
|
6797
|
+
if (!existsSync22(localPath)) {
|
|
5624
6798
|
console.error(`✗ Local path not found: ${localPath}`);
|
|
5625
6799
|
process.exit(1);
|
|
5626
6800
|
}
|
|
@@ -5633,6 +6807,17 @@ async function runAddCap(flags, name) {
|
|
|
5633
6807
|
process.exit(1);
|
|
5634
6808
|
}
|
|
5635
6809
|
source = `github:${flags.github}`;
|
|
6810
|
+
console.log(` Validating repository ${flags.github}...`);
|
|
6811
|
+
const validation = await validateGitCapability(source, flags.path);
|
|
6812
|
+
if (!validation.valid) {
|
|
6813
|
+
console.error(`✗ ${validation.error}`);
|
|
6814
|
+
process.exit(1);
|
|
6815
|
+
}
|
|
6816
|
+
if (validation.hasCapabilityToml) {
|
|
6817
|
+
console.log(` Found capability.toml`);
|
|
6818
|
+
} else {
|
|
6819
|
+
console.log(` Repository can be auto-wrapped as capability`);
|
|
6820
|
+
}
|
|
5636
6821
|
} else {
|
|
5637
6822
|
throw new Error("Unreachable: no source specified");
|
|
5638
6823
|
}
|
|
@@ -5701,7 +6886,7 @@ async function runAddCap(flags, name) {
|
|
|
5701
6886
|
}
|
|
5702
6887
|
async function runAddMcp(flags, name) {
|
|
5703
6888
|
try {
|
|
5704
|
-
if (!
|
|
6889
|
+
if (!existsSync22("omni.toml")) {
|
|
5705
6890
|
console.log("✗ No config file found");
|
|
5706
6891
|
console.log(" Run: omnidev init");
|
|
5707
6892
|
process.exit(1);
|
|
@@ -5832,12 +7017,16 @@ If the capability name is omitted, it will be inferred from:
|
|
|
5832
7017
|
- For local sources: the ID in capability.toml or directory name
|
|
5833
7018
|
- For GitHub sources: the repository name or last path segment
|
|
5834
7019
|
|
|
7020
|
+
Claude plugins (.claude-plugin/plugin.json) are automatically wrapped as OmniDev capabilities.
|
|
7021
|
+
Hooks defined in hooks.json are also supported and will be synced to .claude/settings.json.
|
|
7022
|
+
|
|
5835
7023
|
Examples:
|
|
5836
7024
|
omnidev add cap my-cap --github expo/skills # Uses version = "latest"
|
|
5837
7025
|
omnidev add cap --github expo/skills # Infers name as "skills"
|
|
5838
7026
|
omnidev add cap --github expo/skills --pin # Pins to detected version
|
|
5839
7027
|
omnidev add cap --local ./capabilities/my-cap # Infers name from capability.toml
|
|
5840
|
-
omnidev add cap custom-name --local ./capabilities/my-cap
|
|
7028
|
+
omnidev add cap custom-name --local ./capabilities/my-cap
|
|
7029
|
+
omnidev add cap --github user/claude-plugin # Auto-wraps Claude plugins`
|
|
5841
7030
|
},
|
|
5842
7031
|
parameters: {
|
|
5843
7032
|
flags: {
|
|
@@ -5984,9 +7173,9 @@ var addRoutes = buildRouteMap({
|
|
|
5984
7173
|
});
|
|
5985
7174
|
|
|
5986
7175
|
// src/commands/capability.ts
|
|
5987
|
-
import { existsSync as
|
|
5988
|
-
import { writeFile as
|
|
5989
|
-
import { join as
|
|
7176
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync9 } from "node:fs";
|
|
7177
|
+
import { writeFile as writeFile22 } from "node:fs/promises";
|
|
7178
|
+
import { join as join25 } from "node:path";
|
|
5990
7179
|
import { input } from "@inquirer/prompts";
|
|
5991
7180
|
init_src();
|
|
5992
7181
|
import { buildCommand as buildCommand2, buildRouteMap as buildRouteMap2 } from "@stricli/core";
|
|
@@ -6171,7 +7360,7 @@ node_modules/
|
|
|
6171
7360
|
}
|
|
6172
7361
|
async function runCapabilityNew(flags, capabilityId) {
|
|
6173
7362
|
try {
|
|
6174
|
-
if (!
|
|
7363
|
+
if (!existsSync23(".omni")) {
|
|
6175
7364
|
console.error("✗ OmniDev is not initialized in this directory.");
|
|
6176
7365
|
console.log("");
|
|
6177
7366
|
console.log(" Run: omnidev init");
|
|
@@ -6195,28 +7384,28 @@ async function runCapabilityNew(flags, capabilityId) {
|
|
|
6195
7384
|
default: defaultPath
|
|
6196
7385
|
});
|
|
6197
7386
|
}
|
|
6198
|
-
if (
|
|
7387
|
+
if (existsSync23(capabilityDir)) {
|
|
6199
7388
|
console.error(`✗ Directory already exists at ${capabilityDir}`);
|
|
6200
7389
|
process.exit(1);
|
|
6201
7390
|
}
|
|
6202
7391
|
const name = toTitleCase(id);
|
|
6203
7392
|
mkdirSync9(capabilityDir, { recursive: true });
|
|
6204
7393
|
const capabilityToml = generateCapabilityToml2({ id, name });
|
|
6205
|
-
await
|
|
6206
|
-
const skillDir =
|
|
7394
|
+
await writeFile22(join25(capabilityDir, "capability.toml"), capabilityToml, "utf-8");
|
|
7395
|
+
const skillDir = join25(capabilityDir, "skills", "getting-started");
|
|
6207
7396
|
mkdirSync9(skillDir, { recursive: true });
|
|
6208
|
-
await
|
|
6209
|
-
const rulesDir =
|
|
7397
|
+
await writeFile22(join25(skillDir, "SKILL.md"), generateSkillTemplate("getting-started"), "utf-8");
|
|
7398
|
+
const rulesDir = join25(capabilityDir, "rules");
|
|
6210
7399
|
mkdirSync9(rulesDir, { recursive: true });
|
|
6211
|
-
await
|
|
6212
|
-
const hooksDir =
|
|
7400
|
+
await writeFile22(join25(rulesDir, "coding-standards.md"), generateRuleTemplate("coding-standards"), "utf-8");
|
|
7401
|
+
const hooksDir = join25(capabilityDir, "hooks");
|
|
6213
7402
|
mkdirSync9(hooksDir, { recursive: true });
|
|
6214
|
-
await
|
|
6215
|
-
await
|
|
7403
|
+
await writeFile22(join25(hooksDir, "hooks.toml"), generateHooksTemplate(), "utf-8");
|
|
7404
|
+
await writeFile22(join25(hooksDir, "example-hook.sh"), generateHookScript(), "utf-8");
|
|
6216
7405
|
if (flags.programmatic) {
|
|
6217
|
-
await
|
|
6218
|
-
await
|
|
6219
|
-
await
|
|
7406
|
+
await writeFile22(join25(capabilityDir, "package.json"), generatePackageJson(id), "utf-8");
|
|
7407
|
+
await writeFile22(join25(capabilityDir, "index.ts"), generateIndexTs(id, name), "utf-8");
|
|
7408
|
+
await writeFile22(join25(capabilityDir, ".gitignore"), generateGitignore(), "utf-8");
|
|
6220
7409
|
}
|
|
6221
7410
|
console.log(`✓ Created capability: ${name}`);
|
|
6222
7411
|
console.log(` Location: ${capabilityDir}`);
|
|
@@ -6372,7 +7561,7 @@ var capabilityRoutes = buildRouteMap2({
|
|
|
6372
7561
|
});
|
|
6373
7562
|
|
|
6374
7563
|
// src/commands/doctor.ts
|
|
6375
|
-
import { existsSync as
|
|
7564
|
+
import { existsSync as existsSync24 } from "node:fs";
|
|
6376
7565
|
import { execFile } from "node:child_process";
|
|
6377
7566
|
import { readFile as readFile19 } from "node:fs/promises";
|
|
6378
7567
|
import { promisify } from "node:util";
|
|
@@ -6462,7 +7651,7 @@ async function checkPackageManager() {
|
|
|
6462
7651
|
}
|
|
6463
7652
|
}
|
|
6464
7653
|
async function checkOmniLocalDir() {
|
|
6465
|
-
const exists =
|
|
7654
|
+
const exists = existsSync24(".omni");
|
|
6466
7655
|
if (!exists) {
|
|
6467
7656
|
return {
|
|
6468
7657
|
name: ".omni/ directory",
|
|
@@ -6479,7 +7668,7 @@ async function checkOmniLocalDir() {
|
|
|
6479
7668
|
}
|
|
6480
7669
|
async function checkConfig() {
|
|
6481
7670
|
const configPath = "omni.toml";
|
|
6482
|
-
if (!
|
|
7671
|
+
if (!existsSync24(configPath)) {
|
|
6483
7672
|
return {
|
|
6484
7673
|
name: "Configuration",
|
|
6485
7674
|
passed: false,
|
|
@@ -6506,7 +7695,7 @@ async function checkConfig() {
|
|
|
6506
7695
|
}
|
|
6507
7696
|
async function checkRootGitignore() {
|
|
6508
7697
|
const gitignorePath = ".gitignore";
|
|
6509
|
-
if (!
|
|
7698
|
+
if (!existsSync24(gitignorePath)) {
|
|
6510
7699
|
return {
|
|
6511
7700
|
name: "Root .gitignore",
|
|
6512
7701
|
passed: false,
|
|
@@ -6540,7 +7729,7 @@ async function checkRootGitignore() {
|
|
|
6540
7729
|
}
|
|
6541
7730
|
async function checkCapabilitiesDir() {
|
|
6542
7731
|
const capabilitiesDirPath = ".omni/capabilities";
|
|
6543
|
-
if (!
|
|
7732
|
+
if (!existsSync24(capabilitiesDirPath)) {
|
|
6544
7733
|
return {
|
|
6545
7734
|
name: "Capabilities Directory",
|
|
6546
7735
|
passed: true,
|
|
@@ -6556,8 +7745,8 @@ async function checkCapabilitiesDir() {
|
|
|
6556
7745
|
|
|
6557
7746
|
// src/commands/init.ts
|
|
6558
7747
|
import { exec } from "node:child_process";
|
|
6559
|
-
import { existsSync as
|
|
6560
|
-
import { readFile as readFile20, writeFile as
|
|
7748
|
+
import { existsSync as existsSync25, mkdirSync as mkdirSync10 } from "node:fs";
|
|
7749
|
+
import { readFile as readFile20, writeFile as writeFile23 } from "node:fs/promises";
|
|
6561
7750
|
import { promisify as promisify2 } from "node:util";
|
|
6562
7751
|
init_src();
|
|
6563
7752
|
import { buildCommand as buildCommand4 } from "@stricli/core";
|
|
@@ -6626,7 +7815,7 @@ async function runInit(_flags, providerArg) {
|
|
|
6626
7815
|
}
|
|
6627
7816
|
}
|
|
6628
7817
|
await writeEnabledProviders(providerIds);
|
|
6629
|
-
if (!
|
|
7818
|
+
if (!existsSync25("omni.toml")) {
|
|
6630
7819
|
await writeConfig({
|
|
6631
7820
|
profiles: {
|
|
6632
7821
|
default: {
|
|
@@ -6642,8 +7831,8 @@ async function runInit(_flags, providerArg) {
|
|
|
6642
7831
|
});
|
|
6643
7832
|
await setActiveProfile("default");
|
|
6644
7833
|
}
|
|
6645
|
-
if (!
|
|
6646
|
-
await
|
|
7834
|
+
if (!existsSync25("OMNI.md")) {
|
|
7835
|
+
await writeFile23("OMNI.md", generateOmniMdTemplate(), "utf-8");
|
|
6647
7836
|
}
|
|
6648
7837
|
const config3 = await loadConfig();
|
|
6649
7838
|
const ctx = {
|
|
@@ -6720,7 +7909,7 @@ async function addProviderFilesToGitignore(entries) {
|
|
|
6720
7909
|
async function addToGitignore(entriesToAdd, sectionHeader) {
|
|
6721
7910
|
const gitignorePath = ".gitignore";
|
|
6722
7911
|
let content = "";
|
|
6723
|
-
if (
|
|
7912
|
+
if (existsSync25(gitignorePath)) {
|
|
6724
7913
|
content = await readFile20(gitignorePath, "utf-8");
|
|
6725
7914
|
}
|
|
6726
7915
|
const lines = content.split(`
|
|
@@ -6736,7 +7925,7 @@ async function addToGitignore(entriesToAdd, sectionHeader) {
|
|
|
6736
7925
|
${missingEntries.join(`
|
|
6737
7926
|
`)}
|
|
6738
7927
|
`;
|
|
6739
|
-
await
|
|
7928
|
+
await writeFile23(gitignorePath, content + section, "utf-8");
|
|
6740
7929
|
}
|
|
6741
7930
|
async function getTrackedProviderFiles(files) {
|
|
6742
7931
|
const tracked = [];
|
|
@@ -6752,7 +7941,7 @@ async function getTrackedProviderFiles(files) {
|
|
|
6752
7941
|
}
|
|
6753
7942
|
|
|
6754
7943
|
// src/commands/profile.ts
|
|
6755
|
-
import { existsSync as
|
|
7944
|
+
import { existsSync as existsSync26 } from "node:fs";
|
|
6756
7945
|
init_src();
|
|
6757
7946
|
import { buildCommand as buildCommand5, buildRouteMap as buildRouteMap3 } from "@stricli/core";
|
|
6758
7947
|
var listCommand2 = buildCommand5({
|
|
@@ -6796,7 +7985,7 @@ var profileRoutes = buildRouteMap3({
|
|
|
6796
7985
|
});
|
|
6797
7986
|
async function runProfileList() {
|
|
6798
7987
|
try {
|
|
6799
|
-
if (!
|
|
7988
|
+
if (!existsSync26("omni.toml")) {
|
|
6800
7989
|
console.log("✗ No config file found");
|
|
6801
7990
|
console.log(" Run: omnidev init");
|
|
6802
7991
|
process.exit(1);
|
|
@@ -6836,7 +8025,7 @@ async function runProfileList() {
|
|
|
6836
8025
|
}
|
|
6837
8026
|
async function runProfileSet(profileName) {
|
|
6838
8027
|
try {
|
|
6839
|
-
if (!
|
|
8028
|
+
if (!existsSync26("omni.toml")) {
|
|
6840
8029
|
console.log("✗ No config file found");
|
|
6841
8030
|
console.log(" Run: omnidev init");
|
|
6842
8031
|
process.exit(1);
|
|
@@ -6985,7 +8174,7 @@ var providerRoutes = buildRouteMap4({
|
|
|
6985
8174
|
|
|
6986
8175
|
// src/commands/security.ts
|
|
6987
8176
|
init_src();
|
|
6988
|
-
import { existsSync as
|
|
8177
|
+
import { existsSync as existsSync27 } from "node:fs";
|
|
6989
8178
|
import { buildCommand as buildCommand7, buildRouteMap as buildRouteMap5 } from "@stricli/core";
|
|
6990
8179
|
var VALID_FINDING_TYPES = [
|
|
6991
8180
|
"unicode_bidi",
|
|
@@ -7102,7 +8291,7 @@ function formatFindingsWithHints(summary) {
|
|
|
7102
8291
|
}
|
|
7103
8292
|
async function runSecurityIssues(flags = {}) {
|
|
7104
8293
|
try {
|
|
7105
|
-
if (!
|
|
8294
|
+
if (!existsSync27("omni.toml")) {
|
|
7106
8295
|
console.log("No config file found");
|
|
7107
8296
|
console.log(" Run: omnidev init");
|
|
7108
8297
|
process.exit(1);
|
|
@@ -7357,7 +8546,7 @@ var securityRoutes = buildRouteMap5({
|
|
|
7357
8546
|
});
|
|
7358
8547
|
|
|
7359
8548
|
// src/commands/sync.ts
|
|
7360
|
-
import { existsSync as
|
|
8549
|
+
import { existsSync as existsSync28 } from "node:fs";
|
|
7361
8550
|
init_src();
|
|
7362
8551
|
import { buildCommand as buildCommand8 } from "@stricli/core";
|
|
7363
8552
|
var PROVIDERS_STATE_PATH = ".omni/state/providers.json";
|
|
@@ -7375,7 +8564,7 @@ async function runSync() {
|
|
|
7375
8564
|
const config3 = await loadConfig();
|
|
7376
8565
|
const activeProfile = await getActiveProfile() ?? "default";
|
|
7377
8566
|
let adapters = await getEnabledAdapters();
|
|
7378
|
-
if (!
|
|
8567
|
+
if (!existsSync28(PROVIDERS_STATE_PATH) || adapters.length === 0) {
|
|
7379
8568
|
console.log("No providers configured yet. Select your provider(s):");
|
|
7380
8569
|
const providerIds = await promptForProviders();
|
|
7381
8570
|
await writeEnabledProviders(providerIds);
|
|
@@ -7585,9 +8774,9 @@ async function buildDynamicApp() {
|
|
|
7585
8774
|
security: securityRoutes
|
|
7586
8775
|
};
|
|
7587
8776
|
debug("Core routes registered", Object.keys(routes));
|
|
7588
|
-
const configPath =
|
|
7589
|
-
debug("Checking for config", { configPath, exists:
|
|
7590
|
-
if (
|
|
8777
|
+
const configPath = join26(process.cwd(), "omni.toml");
|
|
8778
|
+
debug("Checking for config", { configPath, exists: existsSync29(configPath), cwd: process.cwd() });
|
|
8779
|
+
if (existsSync29(configPath)) {
|
|
7591
8780
|
try {
|
|
7592
8781
|
debug("Loading capability commands...");
|
|
7593
8782
|
const capabilityCommands = await loadCapabilityCommands();
|
|
@@ -7662,25 +8851,25 @@ async function loadCapabilityCommands() {
|
|
|
7662
8851
|
return commands;
|
|
7663
8852
|
}
|
|
7664
8853
|
async function loadCapabilityExport(capability3) {
|
|
7665
|
-
const capabilityPath =
|
|
7666
|
-
const builtIndexPath =
|
|
7667
|
-
const jsIndexPath =
|
|
7668
|
-
const tsIndexPath =
|
|
8854
|
+
const capabilityPath = join26(process.cwd(), capability3.path);
|
|
8855
|
+
const builtIndexPath = join26(capabilityPath, "dist", "index.js");
|
|
8856
|
+
const jsIndexPath = join26(capabilityPath, "index.js");
|
|
8857
|
+
const tsIndexPath = join26(capabilityPath, "index.ts");
|
|
7669
8858
|
debug(`Checking entry points for '${capability3.id}'`, {
|
|
7670
8859
|
capabilityPath,
|
|
7671
8860
|
builtIndexPath,
|
|
7672
|
-
builtExists:
|
|
8861
|
+
builtExists: existsSync29(builtIndexPath),
|
|
7673
8862
|
jsIndexPath,
|
|
7674
|
-
jsExists:
|
|
8863
|
+
jsExists: existsSync29(jsIndexPath),
|
|
7675
8864
|
tsIndexPath,
|
|
7676
|
-
tsExists:
|
|
8865
|
+
tsExists: existsSync29(tsIndexPath)
|
|
7677
8866
|
});
|
|
7678
8867
|
let indexPath = null;
|
|
7679
|
-
if (
|
|
8868
|
+
if (existsSync29(builtIndexPath)) {
|
|
7680
8869
|
indexPath = builtIndexPath;
|
|
7681
|
-
} else if (
|
|
8870
|
+
} else if (existsSync29(jsIndexPath)) {
|
|
7682
8871
|
indexPath = jsIndexPath;
|
|
7683
|
-
} else if (
|
|
8872
|
+
} else if (existsSync29(tsIndexPath)) {
|
|
7684
8873
|
indexPath = tsIndexPath;
|
|
7685
8874
|
}
|
|
7686
8875
|
if (!indexPath) {
|