@omnidev-ai/cli 0.4.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +1017 -695
- package/package.json +35 -36
package/dist/index.js
CHANGED
|
@@ -1,772 +1,1094 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
|
+
var __defProp = Object.defineProperty;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __toESM = (mod, isNodeMode, target) => {
|
|
9
|
+
target = mod != null ? __create(__getProtoOf(mod)) : {};
|
|
10
|
+
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
|
|
11
|
+
for (let key of __getOwnPropNames(mod))
|
|
12
|
+
if (!__hasOwnProp.call(to, key))
|
|
13
|
+
__defProp(to, key, {
|
|
14
|
+
get: () => mod[key],
|
|
15
|
+
enumerable: true
|
|
16
|
+
});
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
20
|
+
|
|
21
|
+
// src/index.ts
|
|
22
|
+
import { run } from "@stricli/core";
|
|
23
|
+
|
|
24
|
+
// src/lib/dynamic-app.ts
|
|
25
|
+
import { existsSync as existsSync7 } from "node:fs";
|
|
26
|
+
import { join as join5 } from "node:path";
|
|
27
|
+
import { buildApplication, buildRouteMap as buildRouteMap4 } from "@stricli/core";
|
|
28
|
+
|
|
29
|
+
// ../adapters/src/claude-code/index.ts
|
|
3
30
|
import { existsSync, mkdirSync } from "node:fs";
|
|
4
31
|
import { join } from "node:path";
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
32
|
+
var claudeCodeAdapter = {
|
|
33
|
+
id: "claude-code",
|
|
34
|
+
displayName: "Claude Code",
|
|
35
|
+
async init(ctx) {
|
|
36
|
+
const claudeMdPath = join(ctx.projectRoot, "CLAUDE.md");
|
|
37
|
+
const filesCreated = [];
|
|
38
|
+
if (!existsSync(claudeMdPath)) {
|
|
39
|
+
await Bun.write(claudeMdPath, generateClaudeTemplate());
|
|
40
|
+
filesCreated.push("CLAUDE.md");
|
|
41
|
+
}
|
|
42
|
+
return {
|
|
43
|
+
filesCreated,
|
|
44
|
+
message: filesCreated.length > 0 ? `Created ${filesCreated.join(", ")}` : "CLAUDE.md already exists"
|
|
45
|
+
};
|
|
46
|
+
},
|
|
47
|
+
async sync(bundle, ctx) {
|
|
48
|
+
const filesWritten = [];
|
|
49
|
+
const filesDeleted = [];
|
|
50
|
+
const skillsDir = join(ctx.projectRoot, ".claude", "skills");
|
|
51
|
+
mkdirSync(skillsDir, { recursive: true });
|
|
52
|
+
for (const skill of bundle.skills) {
|
|
53
|
+
const skillDir = join(skillsDir, skill.name);
|
|
54
|
+
mkdirSync(skillDir, { recursive: true });
|
|
55
|
+
const skillPath = join(skillDir, "SKILL.md");
|
|
56
|
+
const content = `---
|
|
57
|
+
name: ${skill.name}
|
|
58
|
+
description: "${skill.description}"
|
|
59
|
+
---
|
|
60
|
+
|
|
61
|
+
${skill.instructions}`;
|
|
62
|
+
await Bun.write(skillPath, content);
|
|
63
|
+
filesWritten.push(`.claude/skills/${skill.name}/SKILL.md`);
|
|
64
|
+
}
|
|
65
|
+
return {
|
|
66
|
+
filesWritten,
|
|
67
|
+
filesDeleted
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
function generateClaudeTemplate() {
|
|
72
|
+
return `# Project Instructions
|
|
73
|
+
|
|
74
|
+
<!-- Add your project-specific instructions here -->
|
|
75
|
+
|
|
76
|
+
## OmniDev
|
|
77
|
+
|
|
78
|
+
@import .omni/instructions.md
|
|
79
|
+
`;
|
|
80
|
+
}
|
|
81
|
+
// ../adapters/src/codex/index.ts
|
|
82
|
+
import { existsSync as existsSync2 } from "node:fs";
|
|
83
|
+
import { join as join2 } from "node:path";
|
|
84
|
+
var codexAdapter = {
|
|
85
|
+
id: "codex",
|
|
86
|
+
displayName: "Codex",
|
|
87
|
+
async init(ctx) {
|
|
88
|
+
const agentsMdPath = join2(ctx.projectRoot, "AGENTS.md");
|
|
89
|
+
const filesCreated = [];
|
|
90
|
+
if (!existsSync2(agentsMdPath)) {
|
|
91
|
+
await Bun.write(agentsMdPath, generateAgentsTemplate());
|
|
92
|
+
filesCreated.push("AGENTS.md");
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
filesCreated,
|
|
96
|
+
message: filesCreated.length > 0 ? `Created ${filesCreated.join(", ")}` : "AGENTS.md already exists"
|
|
97
|
+
};
|
|
98
|
+
},
|
|
99
|
+
async sync(_bundle, _ctx) {
|
|
100
|
+
return {
|
|
101
|
+
filesWritten: [],
|
|
102
|
+
filesDeleted: []
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
function generateAgentsTemplate() {
|
|
107
|
+
return `# Project Instructions
|
|
108
|
+
|
|
109
|
+
<!-- Add your project-specific instructions here -->
|
|
110
|
+
|
|
111
|
+
## OmniDev
|
|
8
112
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
113
|
+
@import .omni/instructions.md
|
|
114
|
+
`;
|
|
115
|
+
}
|
|
116
|
+
// ../adapters/src/cursor/index.ts
|
|
117
|
+
import { mkdirSync as mkdirSync2 } from "node:fs";
|
|
118
|
+
import { join as join3 } from "node:path";
|
|
119
|
+
var cursorAdapter = {
|
|
120
|
+
id: "cursor",
|
|
121
|
+
displayName: "Cursor",
|
|
122
|
+
async init(ctx) {
|
|
123
|
+
const rulesDir = join3(ctx.projectRoot, ".cursor", "rules");
|
|
124
|
+
mkdirSync2(rulesDir, { recursive: true });
|
|
125
|
+
return {
|
|
126
|
+
filesCreated: [".cursor/rules/"],
|
|
127
|
+
message: "Created .cursor/rules/ directory"
|
|
128
|
+
};
|
|
129
|
+
},
|
|
130
|
+
async sync(bundle, ctx) {
|
|
131
|
+
const filesWritten = [];
|
|
132
|
+
const filesDeleted = [];
|
|
133
|
+
const rulesDir = join3(ctx.projectRoot, ".cursor", "rules");
|
|
134
|
+
mkdirSync2(rulesDir, { recursive: true });
|
|
135
|
+
for (const rule of bundle.rules) {
|
|
136
|
+
const rulePath = join3(rulesDir, `omnidev-${rule.name}.mdc`);
|
|
137
|
+
await Bun.write(rulePath, rule.content);
|
|
138
|
+
filesWritten.push(`.cursor/rules/omnidev-${rule.name}.mdc`);
|
|
139
|
+
}
|
|
140
|
+
return {
|
|
141
|
+
filesWritten,
|
|
142
|
+
filesDeleted
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
// ../adapters/src/opencode/index.ts
|
|
147
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync3 } from "node:fs";
|
|
148
|
+
import { join as join4 } from "node:path";
|
|
149
|
+
var opencodeAdapter = {
|
|
150
|
+
id: "opencode",
|
|
151
|
+
displayName: "OpenCode",
|
|
152
|
+
async init(ctx) {
|
|
153
|
+
const opencodeDir = join4(ctx.projectRoot, ".opencode");
|
|
154
|
+
mkdirSync3(opencodeDir, { recursive: true });
|
|
155
|
+
const instructionsPath = join4(opencodeDir, "instructions.md");
|
|
156
|
+
const filesCreated = [];
|
|
157
|
+
if (!existsSync3(instructionsPath)) {
|
|
158
|
+
await Bun.write(instructionsPath, generateOpencodeTemplate());
|
|
159
|
+
filesCreated.push(".opencode/instructions.md");
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
filesCreated,
|
|
163
|
+
message: filesCreated.length > 0 ? `Created ${filesCreated.join(", ")}` : ".opencode/instructions.md already exists"
|
|
164
|
+
};
|
|
165
|
+
},
|
|
166
|
+
async sync(_bundle, _ctx) {
|
|
167
|
+
return {
|
|
168
|
+
filesWritten: [],
|
|
169
|
+
filesDeleted: []
|
|
170
|
+
};
|
|
171
|
+
}
|
|
172
|
+
};
|
|
173
|
+
function generateOpencodeTemplate() {
|
|
174
|
+
return `# OpenCode Instructions
|
|
175
|
+
|
|
176
|
+
<!-- Add your project-specific instructions here -->
|
|
177
|
+
|
|
178
|
+
## OmniDev
|
|
179
|
+
|
|
180
|
+
@import ../.omni/instructions.md
|
|
181
|
+
`;
|
|
182
|
+
}
|
|
183
|
+
// ../adapters/src/registry.ts
|
|
184
|
+
import { readEnabledProviders } from "@omnidev-ai/core";
|
|
185
|
+
var builtInAdapters = [
|
|
186
|
+
claudeCodeAdapter,
|
|
187
|
+
codexAdapter,
|
|
188
|
+
cursorAdapter,
|
|
189
|
+
opencodeAdapter
|
|
190
|
+
];
|
|
191
|
+
var adapterMap = new Map(builtInAdapters.map((adapter) => [adapter.id, adapter]));
|
|
192
|
+
function getAllAdapters() {
|
|
193
|
+
return builtInAdapters;
|
|
194
|
+
}
|
|
195
|
+
async function getEnabledAdapters() {
|
|
196
|
+
const enabledIds = await readEnabledProviders();
|
|
197
|
+
return enabledIds.map((id) => adapterMap.get(id)).filter((a) => a != null);
|
|
198
|
+
}
|
|
199
|
+
// src/commands/capability.ts
|
|
200
|
+
import {
|
|
201
|
+
disableCapability,
|
|
202
|
+
discoverCapabilities,
|
|
203
|
+
enableCapability,
|
|
204
|
+
getEnabledCapabilities,
|
|
205
|
+
loadCapabilityConfig,
|
|
206
|
+
syncAgentConfiguration
|
|
207
|
+
} from "@omnidev-ai/core";
|
|
208
|
+
import { buildCommand, buildRouteMap } from "@stricli/core";
|
|
13
209
|
async function runCapabilityList() {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
210
|
+
try {
|
|
211
|
+
const enabledIds = await getEnabledCapabilities();
|
|
212
|
+
const capabilityPaths = await discoverCapabilities();
|
|
213
|
+
if (capabilityPaths.length === 0) {
|
|
214
|
+
console.log("No capabilities found.");
|
|
215
|
+
console.log("");
|
|
216
|
+
console.log("To add capabilities, create directories in omni/capabilities/");
|
|
217
|
+
console.log("Each capability must have a capability.toml file.");
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
console.log("Capabilities:");
|
|
221
|
+
console.log("");
|
|
222
|
+
for (const path of capabilityPaths) {
|
|
223
|
+
try {
|
|
224
|
+
const capConfig = await loadCapabilityConfig(path);
|
|
225
|
+
const isEnabled = enabledIds.includes(capConfig.capability.id);
|
|
226
|
+
const status = isEnabled ? "✓ enabled" : "✗ disabled";
|
|
227
|
+
const { id, name, version } = capConfig.capability;
|
|
228
|
+
console.log(` ${status} ${name}`);
|
|
229
|
+
console.log(` ID: ${id}`);
|
|
230
|
+
console.log(` Version: ${version}`);
|
|
231
|
+
console.log("");
|
|
232
|
+
} catch (error) {
|
|
233
|
+
console.error(` ✗ Failed to load capability at ${path}:`, error);
|
|
234
|
+
console.log("");
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch (error) {
|
|
238
|
+
console.error("Error listing capabilities:", error);
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
43
241
|
}
|
|
44
|
-
/**
|
|
45
|
-
* Run the capability enable command.
|
|
46
|
-
*/
|
|
47
242
|
async function runCapabilityEnable(_flags, name) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
243
|
+
try {
|
|
244
|
+
const capabilityPaths = await discoverCapabilities();
|
|
245
|
+
const capabilityExists = capabilityPaths.some(async (path) => {
|
|
246
|
+
const config = await loadCapabilityConfig(path);
|
|
247
|
+
return config.capability.id === name;
|
|
248
|
+
});
|
|
249
|
+
if (!capabilityExists) {
|
|
250
|
+
console.error(`Error: Capability '${name}' not found`);
|
|
251
|
+
console.log("");
|
|
252
|
+
console.log("Run 'dev capability list' to see available capabilities");
|
|
253
|
+
process.exit(1);
|
|
254
|
+
}
|
|
255
|
+
await enableCapability(name);
|
|
256
|
+
console.log(`✓ Enabled capability: ${name}`);
|
|
257
|
+
console.log("");
|
|
258
|
+
const adapters = await getEnabledAdapters();
|
|
259
|
+
await syncAgentConfiguration({ adapters });
|
|
260
|
+
} catch (error) {
|
|
261
|
+
console.error("Error enabling capability:", error);
|
|
262
|
+
process.exit(1);
|
|
263
|
+
}
|
|
69
264
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Run the capability disable command.
|
|
72
|
-
*/
|
|
73
265
|
async function runCapabilityDisable(_flags, name) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
266
|
+
try {
|
|
267
|
+
await disableCapability(name);
|
|
268
|
+
console.log(`✓ Disabled capability: ${name}`);
|
|
269
|
+
console.log("");
|
|
270
|
+
const adapters = await getEnabledAdapters();
|
|
271
|
+
await syncAgentConfiguration({ adapters });
|
|
272
|
+
} catch (error) {
|
|
273
|
+
console.error("Error disabling capability:", error);
|
|
274
|
+
process.exit(1);
|
|
275
|
+
}
|
|
84
276
|
}
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
277
|
+
var listCommand = buildCommand({
|
|
278
|
+
docs: {
|
|
279
|
+
brief: "List all discovered capabilities"
|
|
280
|
+
},
|
|
281
|
+
parameters: {},
|
|
282
|
+
async func() {
|
|
283
|
+
await runCapabilityList();
|
|
284
|
+
}
|
|
91
285
|
});
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
286
|
+
var enableCommand = buildCommand({
|
|
287
|
+
docs: {
|
|
288
|
+
brief: "Enable a capability"
|
|
289
|
+
},
|
|
290
|
+
parameters: {
|
|
291
|
+
flags: {},
|
|
292
|
+
positional: {
|
|
293
|
+
kind: "tuple",
|
|
294
|
+
parameters: [
|
|
295
|
+
{
|
|
296
|
+
brief: "Capability name to enable",
|
|
297
|
+
parse: String
|
|
298
|
+
}
|
|
299
|
+
]
|
|
300
|
+
}
|
|
301
|
+
},
|
|
302
|
+
func: runCapabilityEnable
|
|
105
303
|
});
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
304
|
+
var disableCommand = buildCommand({
|
|
305
|
+
docs: {
|
|
306
|
+
brief: "Disable a capability"
|
|
307
|
+
},
|
|
308
|
+
parameters: {
|
|
309
|
+
flags: {},
|
|
310
|
+
positional: {
|
|
311
|
+
kind: "tuple",
|
|
312
|
+
parameters: [
|
|
313
|
+
{
|
|
314
|
+
brief: "Capability name to disable",
|
|
315
|
+
parse: String
|
|
316
|
+
}
|
|
317
|
+
]
|
|
318
|
+
}
|
|
319
|
+
},
|
|
320
|
+
func: runCapabilityDisable
|
|
119
321
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
322
|
+
var capabilityRoutes = buildRouteMap({
|
|
323
|
+
routes: {
|
|
324
|
+
list: listCommand,
|
|
325
|
+
enable: enableCommand,
|
|
326
|
+
disable: disableCommand
|
|
327
|
+
},
|
|
328
|
+
docs: {
|
|
329
|
+
brief: "Manage capabilities"
|
|
330
|
+
}
|
|
127
331
|
});
|
|
128
332
|
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
333
|
+
// src/commands/doctor.ts
|
|
334
|
+
import { existsSync as existsSync4 } from "node:fs";
|
|
335
|
+
import { buildCommand as buildCommand2 } from "@stricli/core";
|
|
336
|
+
var doctorCommand = buildCommand2({
|
|
337
|
+
docs: {
|
|
338
|
+
brief: "Check OmniDev setup and dependencies"
|
|
339
|
+
},
|
|
340
|
+
parameters: {},
|
|
341
|
+
async func() {
|
|
342
|
+
return await runDoctor();
|
|
343
|
+
}
|
|
137
344
|
});
|
|
138
345
|
async function runDoctor() {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
346
|
+
console.log("OmniDev Doctor");
|
|
347
|
+
console.log("==============");
|
|
348
|
+
console.log("");
|
|
349
|
+
const checks = [
|
|
350
|
+
checkBunVersion(),
|
|
351
|
+
checkOmniLocalDir(),
|
|
352
|
+
checkConfig(),
|
|
353
|
+
checkRootGitignore(),
|
|
354
|
+
checkCapabilitiesDir()
|
|
355
|
+
];
|
|
356
|
+
let allPassed = true;
|
|
357
|
+
for (const check of checks) {
|
|
358
|
+
const { name, passed, message, fix } = await check;
|
|
359
|
+
const icon = passed ? "✓" : "✗";
|
|
360
|
+
console.log(`${icon} ${name}: ${message}`);
|
|
361
|
+
if (!passed && fix) {
|
|
362
|
+
console.log(` Fix: ${fix}`);
|
|
363
|
+
}
|
|
364
|
+
if (!passed)
|
|
365
|
+
allPassed = false;
|
|
366
|
+
}
|
|
367
|
+
console.log("");
|
|
368
|
+
if (allPassed) {
|
|
369
|
+
console.log("All checks passed!");
|
|
370
|
+
} else {
|
|
371
|
+
console.log("Some checks failed. Please fix the issues above.");
|
|
372
|
+
process.exit(1);
|
|
373
|
+
}
|
|
163
374
|
}
|
|
164
375
|
async function checkBunVersion() {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
376
|
+
const version = Bun.version;
|
|
377
|
+
const parts = version.split(".");
|
|
378
|
+
const firstPart = parts[0];
|
|
379
|
+
if (!firstPart) {
|
|
380
|
+
return {
|
|
381
|
+
name: "Bun Version",
|
|
382
|
+
passed: false,
|
|
383
|
+
message: `Invalid version format: ${version}`,
|
|
384
|
+
fix: "Reinstall Bun: curl -fsSL https://bun.sh/install | bash"
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
const major = Number.parseInt(firstPart, 10);
|
|
388
|
+
if (major < 1) {
|
|
389
|
+
return {
|
|
390
|
+
name: "Bun Version",
|
|
391
|
+
passed: false,
|
|
392
|
+
message: `v${version}`,
|
|
393
|
+
fix: "Upgrade Bun: curl -fsSL https://bun.sh/install | bash"
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
return {
|
|
397
|
+
name: "Bun Version",
|
|
398
|
+
passed: true,
|
|
399
|
+
message: `v${version}`
|
|
400
|
+
};
|
|
186
401
|
}
|
|
187
402
|
async function checkOmniLocalDir() {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
403
|
+
const exists = existsSync4(".omni");
|
|
404
|
+
if (!exists) {
|
|
405
|
+
return {
|
|
406
|
+
name: ".omni/ directory",
|
|
407
|
+
passed: false,
|
|
408
|
+
message: "Not found",
|
|
409
|
+
fix: "Run: omnidev init"
|
|
410
|
+
};
|
|
411
|
+
}
|
|
412
|
+
return {
|
|
413
|
+
name: ".omni/ directory",
|
|
414
|
+
passed: true,
|
|
415
|
+
message: "Found"
|
|
416
|
+
};
|
|
200
417
|
}
|
|
201
418
|
async function checkConfig() {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
419
|
+
const configPath = "omni.toml";
|
|
420
|
+
if (!existsSync4(configPath)) {
|
|
421
|
+
return {
|
|
422
|
+
name: "Configuration",
|
|
423
|
+
passed: false,
|
|
424
|
+
message: "omni.toml not found",
|
|
425
|
+
fix: "Run: omnidev init"
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
try {
|
|
429
|
+
const { loadConfig } = await import("@omnidev-ai/core");
|
|
430
|
+
await loadConfig();
|
|
431
|
+
return {
|
|
432
|
+
name: "Configuration",
|
|
433
|
+
passed: true,
|
|
434
|
+
message: "Valid"
|
|
435
|
+
};
|
|
436
|
+
} catch (error) {
|
|
437
|
+
return {
|
|
438
|
+
name: "Configuration",
|
|
439
|
+
passed: false,
|
|
440
|
+
message: `Invalid: ${error instanceof Error ? error.message : String(error)}`,
|
|
441
|
+
fix: "Check omni.toml syntax"
|
|
442
|
+
};
|
|
443
|
+
}
|
|
225
444
|
}
|
|
226
445
|
async function checkRootGitignore() {
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
446
|
+
const gitignorePath = ".gitignore";
|
|
447
|
+
if (!existsSync4(gitignorePath)) {
|
|
448
|
+
return {
|
|
449
|
+
name: "Root .gitignore",
|
|
450
|
+
passed: false,
|
|
451
|
+
message: ".gitignore not found",
|
|
452
|
+
fix: "Run: omnidev init"
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
const content = await Bun.file(gitignorePath).text();
|
|
456
|
+
const lines = content.split(`
|
|
457
|
+
`).map((line) => line.trim());
|
|
458
|
+
const hasOmniDir = lines.includes(".omni/");
|
|
459
|
+
const hasLocalToml = lines.includes("omni.local.toml");
|
|
460
|
+
if (!hasOmniDir || !hasLocalToml) {
|
|
461
|
+
const missing = [];
|
|
462
|
+
if (!hasOmniDir)
|
|
463
|
+
missing.push(".omni/");
|
|
464
|
+
if (!hasLocalToml)
|
|
465
|
+
missing.push("omni.local.toml");
|
|
466
|
+
return {
|
|
467
|
+
name: "Root .gitignore",
|
|
468
|
+
passed: false,
|
|
469
|
+
message: `Missing entries: ${missing.join(", ")}`,
|
|
470
|
+
fix: "Run: omnidev init"
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
return {
|
|
474
|
+
name: "Root .gitignore",
|
|
475
|
+
passed: true,
|
|
476
|
+
message: "Found with OmniDev entries"
|
|
477
|
+
};
|
|
254
478
|
}
|
|
255
479
|
async function checkCapabilitiesDir() {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
480
|
+
const capabilitiesDirPath = ".omni/capabilities";
|
|
481
|
+
if (!existsSync4(capabilitiesDirPath)) {
|
|
482
|
+
return {
|
|
483
|
+
name: "Capabilities Directory",
|
|
484
|
+
passed: true,
|
|
485
|
+
message: "Not found (no custom capabilities)"
|
|
486
|
+
};
|
|
487
|
+
}
|
|
488
|
+
return {
|
|
489
|
+
name: "Capabilities Directory",
|
|
490
|
+
passed: true,
|
|
491
|
+
message: "Found"
|
|
492
|
+
};
|
|
267
493
|
}
|
|
268
494
|
|
|
269
|
-
|
|
270
|
-
|
|
495
|
+
// src/commands/init.ts
|
|
496
|
+
import { existsSync as existsSync5, mkdirSync as mkdirSync4 } from "node:fs";
|
|
497
|
+
import {
|
|
498
|
+
generateInstructionsTemplate,
|
|
499
|
+
loadConfig,
|
|
500
|
+
setActiveProfile,
|
|
501
|
+
syncAgentConfiguration as syncAgentConfiguration2,
|
|
502
|
+
writeConfig,
|
|
503
|
+
writeEnabledProviders
|
|
504
|
+
} from "@omnidev-ai/core";
|
|
505
|
+
import { buildCommand as buildCommand3 } from "@stricli/core";
|
|
506
|
+
|
|
507
|
+
// src/prompts/provider.ts
|
|
508
|
+
import { checkbox } from "@inquirer/prompts";
|
|
271
509
|
async function promptForProviders() {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
checked: false
|
|
284
|
-
},
|
|
285
|
-
{
|
|
286
|
-
name: "Codex",
|
|
287
|
-
value: "codex",
|
|
288
|
-
checked: false
|
|
289
|
-
},
|
|
290
|
-
{
|
|
291
|
-
name: "OpenCode",
|
|
292
|
-
value: "opencode",
|
|
293
|
-
checked: false
|
|
294
|
-
}
|
|
295
|
-
],
|
|
296
|
-
required: true
|
|
297
|
-
});
|
|
298
|
-
return answers;
|
|
510
|
+
const answers = await checkbox({
|
|
511
|
+
message: "Select your AI provider(s):",
|
|
512
|
+
choices: [
|
|
513
|
+
{ name: "Claude Code (Claude CLI)", value: "claude-code", checked: true },
|
|
514
|
+
{ name: "Cursor", value: "cursor", checked: false },
|
|
515
|
+
{ name: "Codex", value: "codex", checked: false },
|
|
516
|
+
{ name: "OpenCode", value: "opencode", checked: false }
|
|
517
|
+
],
|
|
518
|
+
required: true
|
|
519
|
+
});
|
|
520
|
+
return answers;
|
|
299
521
|
}
|
|
300
522
|
|
|
301
|
-
|
|
302
|
-
//#region src/commands/init.ts
|
|
523
|
+
// src/commands/init.ts
|
|
303
524
|
async function runInit(_flags, providerArg) {
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
525
|
+
console.log("Initializing OmniDev...");
|
|
526
|
+
mkdirSync4(".omni", { recursive: true });
|
|
527
|
+
mkdirSync4(".omni/capabilities", { recursive: true });
|
|
528
|
+
mkdirSync4(".omni/state", { recursive: true });
|
|
529
|
+
await updateRootGitignore();
|
|
530
|
+
let providerIds;
|
|
531
|
+
if (providerArg) {
|
|
532
|
+
providerIds = parseProviderArg(providerArg);
|
|
533
|
+
} else {
|
|
534
|
+
providerIds = await promptForProviders();
|
|
535
|
+
}
|
|
536
|
+
await writeEnabledProviders(providerIds);
|
|
537
|
+
if (!existsSync5("omni.toml")) {
|
|
538
|
+
await writeConfig({
|
|
539
|
+
project: "my-project",
|
|
540
|
+
profiles: {
|
|
541
|
+
default: {
|
|
542
|
+
capabilities: []
|
|
543
|
+
},
|
|
544
|
+
planning: {
|
|
545
|
+
capabilities: []
|
|
546
|
+
},
|
|
547
|
+
coding: {
|
|
548
|
+
capabilities: []
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
});
|
|
552
|
+
await setActiveProfile("default");
|
|
553
|
+
}
|
|
554
|
+
if (!existsSync5(".omni/instructions.md")) {
|
|
555
|
+
await Bun.write(".omni/instructions.md", generateInstructionsTemplate());
|
|
556
|
+
}
|
|
557
|
+
const config = await loadConfig();
|
|
558
|
+
const ctx = {
|
|
559
|
+
projectRoot: process.cwd(),
|
|
560
|
+
config
|
|
561
|
+
};
|
|
562
|
+
const allAdapters = getAllAdapters();
|
|
563
|
+
const selectedAdapters = allAdapters.filter((a) => providerIds.includes(a.id));
|
|
564
|
+
const filesCreated = [];
|
|
565
|
+
const filesExisting = [];
|
|
566
|
+
for (const adapter of selectedAdapters) {
|
|
567
|
+
if (adapter.init) {
|
|
568
|
+
const result = await adapter.init(ctx);
|
|
569
|
+
if (result.filesCreated) {
|
|
570
|
+
filesCreated.push(...result.filesCreated);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
574
|
+
const enabledAdapters = await getEnabledAdapters();
|
|
575
|
+
await syncAgentConfiguration2({ silent: true, adapters: enabledAdapters });
|
|
576
|
+
console.log("");
|
|
577
|
+
console.log(`✓ OmniDev initialized for ${selectedAdapters.map((a) => a.displayName).join(" and ")}!`);
|
|
578
|
+
console.log("");
|
|
579
|
+
if (filesCreated.length > 0) {
|
|
580
|
+
console.log("\uD83D\uDCDD Don't forget to add your project description to:");
|
|
581
|
+
console.log(" • .omni/instructions.md");
|
|
582
|
+
}
|
|
583
|
+
if (filesExisting.length > 0) {
|
|
584
|
+
console.log("\uD83D\uDCDD Add this line to your existing file(s):");
|
|
585
|
+
for (const file of filesExisting) {
|
|
586
|
+
console.log(` • ${file}: @import .omni/instructions.md`);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
console.log("");
|
|
590
|
+
console.log("\uD83D\uDCA1 Recommendation:");
|
|
591
|
+
console.log(" Add provider-specific files to .gitignore:");
|
|
592
|
+
console.log(" CLAUDE.md, .claude/, AGENTS.md, .cursor/, .mcp.json");
|
|
593
|
+
console.log("");
|
|
594
|
+
console.log(" Run 'omnidev capability list' to see available capabilities.");
|
|
360
595
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
596
|
+
var initCommand = buildCommand3({
|
|
597
|
+
parameters: {
|
|
598
|
+
flags: {},
|
|
599
|
+
positional: {
|
|
600
|
+
kind: "tuple",
|
|
601
|
+
parameters: [
|
|
602
|
+
{
|
|
603
|
+
brief: "AI provider(s): claude-code, cursor, codex, opencode, or comma-separated",
|
|
604
|
+
parse: String,
|
|
605
|
+
optional: true
|
|
606
|
+
}
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
},
|
|
610
|
+
docs: {
|
|
611
|
+
brief: "Initialize OmniDev in the current project"
|
|
612
|
+
},
|
|
613
|
+
func: runInit
|
|
375
614
|
});
|
|
376
615
|
function parseProviderArg(arg) {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
616
|
+
const allAdapters = getAllAdapters();
|
|
617
|
+
const validIds = new Set(allAdapters.map((a) => a.id));
|
|
618
|
+
if (arg.toLowerCase() === "both") {
|
|
619
|
+
return ["claude-code", "cursor"];
|
|
620
|
+
}
|
|
621
|
+
const parts = arg.split(",").map((p) => p.trim().toLowerCase());
|
|
622
|
+
const result = [];
|
|
623
|
+
for (const part of parts) {
|
|
624
|
+
let id = part;
|
|
625
|
+
if (id === "claude") {
|
|
626
|
+
id = "claude-code";
|
|
627
|
+
}
|
|
628
|
+
if (!validIds.has(id)) {
|
|
629
|
+
throw new Error(`Invalid provider: ${part}. Valid providers: ${[...validIds].join(", ")}`);
|
|
630
|
+
}
|
|
631
|
+
result.push(id);
|
|
632
|
+
}
|
|
633
|
+
return result;
|
|
389
634
|
}
|
|
390
635
|
async function updateRootGitignore() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
636
|
+
const gitignorePath = ".gitignore";
|
|
637
|
+
const entriesToAdd = [".omni/", "omni.local.toml"];
|
|
638
|
+
let content = "";
|
|
639
|
+
if (existsSync5(gitignorePath)) {
|
|
640
|
+
content = await Bun.file(gitignorePath).text();
|
|
641
|
+
}
|
|
642
|
+
const lines = content.split(`
|
|
643
|
+
`);
|
|
644
|
+
const missingEntries = entriesToAdd.filter((entry) => !lines.some((line) => line.trim() === entry));
|
|
645
|
+
if (missingEntries.length === 0) {
|
|
646
|
+
return;
|
|
647
|
+
}
|
|
648
|
+
const needsNewline = content.length > 0 && !content.endsWith(`
|
|
649
|
+
`);
|
|
650
|
+
const section = `${needsNewline ? `
|
|
651
|
+
` : ""}# OmniDev
|
|
652
|
+
${missingEntries.join(`
|
|
653
|
+
`)}
|
|
654
|
+
`;
|
|
655
|
+
await Bun.write(gitignorePath, content + section);
|
|
401
656
|
}
|
|
402
657
|
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
658
|
+
// src/commands/profile.ts
|
|
659
|
+
import { existsSync as existsSync6 } from "node:fs";
|
|
660
|
+
import {
|
|
661
|
+
getActiveProfile,
|
|
662
|
+
loadConfig as loadConfig2,
|
|
663
|
+
resolveEnabledCapabilities,
|
|
664
|
+
setActiveProfile as setActiveProfile2,
|
|
665
|
+
syncAgentConfiguration as syncAgentConfiguration3
|
|
666
|
+
} from "@omnidev-ai/core";
|
|
667
|
+
import { buildCommand as buildCommand4, buildRouteMap as buildRouteMap2 } from "@stricli/core";
|
|
668
|
+
var listCommand2 = buildCommand4({
|
|
669
|
+
docs: {
|
|
670
|
+
brief: "List available profiles"
|
|
671
|
+
},
|
|
672
|
+
parameters: {},
|
|
673
|
+
async func() {
|
|
674
|
+
await runProfileList();
|
|
675
|
+
}
|
|
411
676
|
});
|
|
412
677
|
async function runSetCommand(_flags, profileName) {
|
|
413
|
-
|
|
678
|
+
await runProfileSet(profileName);
|
|
414
679
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
680
|
+
var setCommand = buildCommand4({
|
|
681
|
+
docs: {
|
|
682
|
+
brief: "Set the active profile"
|
|
683
|
+
},
|
|
684
|
+
parameters: {
|
|
685
|
+
flags: {},
|
|
686
|
+
positional: {
|
|
687
|
+
kind: "tuple",
|
|
688
|
+
parameters: [
|
|
689
|
+
{
|
|
690
|
+
brief: "Profile name",
|
|
691
|
+
parse: String
|
|
692
|
+
}
|
|
693
|
+
]
|
|
694
|
+
}
|
|
695
|
+
},
|
|
696
|
+
func: runSetCommand
|
|
428
697
|
});
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
698
|
+
var profileRoutes = buildRouteMap2({
|
|
699
|
+
routes: {
|
|
700
|
+
list: listCommand2,
|
|
701
|
+
set: setCommand
|
|
702
|
+
},
|
|
703
|
+
docs: {
|
|
704
|
+
brief: "Manage capability profiles"
|
|
705
|
+
}
|
|
435
706
|
});
|
|
436
707
|
async function runProfileList() {
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
708
|
+
try {
|
|
709
|
+
if (!existsSync6("omni.toml")) {
|
|
710
|
+
console.log("✗ No config file found");
|
|
711
|
+
console.log(" Run: omnidev init");
|
|
712
|
+
process.exit(1);
|
|
713
|
+
}
|
|
714
|
+
const config = await loadConfig2();
|
|
715
|
+
const activeProfile = await getActiveProfile() ?? config.active_profile ?? "default";
|
|
716
|
+
const profiles = config.profiles ?? {};
|
|
717
|
+
const profileNames = Object.keys(profiles);
|
|
718
|
+
if (profileNames.length === 0) {
|
|
719
|
+
console.log("No profiles defined in omni.toml");
|
|
720
|
+
console.log("");
|
|
721
|
+
console.log("Using default capabilities from omni.toml");
|
|
722
|
+
return;
|
|
723
|
+
}
|
|
724
|
+
console.log("Available Profiles:");
|
|
725
|
+
console.log("");
|
|
726
|
+
for (const name of profileNames) {
|
|
727
|
+
const isActive = name === activeProfile;
|
|
728
|
+
const icon = isActive ? "●" : "○";
|
|
729
|
+
const profile = profiles[name];
|
|
730
|
+
if (profile === undefined) {
|
|
731
|
+
continue;
|
|
732
|
+
}
|
|
733
|
+
console.log(`${icon} ${name}${isActive ? " (active)" : ""}`);
|
|
734
|
+
const capabilities = resolveEnabledCapabilities(config, name);
|
|
735
|
+
if (capabilities.length > 0) {
|
|
736
|
+
console.log(` Capabilities: ${capabilities.join(", ")}`);
|
|
737
|
+
} else {
|
|
738
|
+
console.log(" Capabilities: none");
|
|
739
|
+
}
|
|
740
|
+
console.log("");
|
|
741
|
+
}
|
|
742
|
+
} catch (error) {
|
|
743
|
+
console.error("✗ Error loading profiles:", error);
|
|
744
|
+
process.exit(1);
|
|
745
|
+
}
|
|
470
746
|
}
|
|
471
747
|
async function runProfileSet(profileName) {
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
748
|
+
try {
|
|
749
|
+
if (!existsSync6("omni.toml")) {
|
|
750
|
+
console.log("✗ No config file found");
|
|
751
|
+
console.log(" Run: omnidev init");
|
|
752
|
+
process.exit(1);
|
|
753
|
+
}
|
|
754
|
+
const config = await loadConfig2();
|
|
755
|
+
const profiles = config.profiles ?? {};
|
|
756
|
+
if (!(profileName in profiles)) {
|
|
757
|
+
console.log(`✗ Profile "${profileName}" not found in omni.toml`);
|
|
758
|
+
console.log("");
|
|
759
|
+
console.log("Available profiles:");
|
|
760
|
+
const profileNames = Object.keys(profiles);
|
|
761
|
+
if (profileNames.length === 0) {
|
|
762
|
+
console.log(" (none defined)");
|
|
763
|
+
} else {
|
|
764
|
+
for (const name of profileNames) {
|
|
765
|
+
console.log(` - ${name}`);
|
|
766
|
+
}
|
|
767
|
+
}
|
|
768
|
+
process.exit(1);
|
|
769
|
+
}
|
|
770
|
+
await setActiveProfile2(profileName);
|
|
771
|
+
console.log(`✓ Active profile set to: ${profileName}`);
|
|
772
|
+
console.log("");
|
|
773
|
+
const adapters = await getEnabledAdapters();
|
|
774
|
+
await syncAgentConfiguration3({ adapters });
|
|
775
|
+
} catch (error) {
|
|
776
|
+
console.error("✗ Error setting profile:", error);
|
|
777
|
+
process.exit(1);
|
|
778
|
+
}
|
|
498
779
|
}
|
|
499
780
|
|
|
500
|
-
|
|
501
|
-
|
|
781
|
+
// src/commands/provider.ts
|
|
782
|
+
import {
|
|
783
|
+
disableProvider,
|
|
784
|
+
enableProvider,
|
|
785
|
+
readEnabledProviders as readEnabledProviders2,
|
|
786
|
+
syncAgentConfiguration as syncAgentConfiguration4
|
|
787
|
+
} from "@omnidev-ai/core";
|
|
788
|
+
import { buildCommand as buildCommand5, buildRouteMap as buildRouteMap3 } from "@stricli/core";
|
|
502
789
|
async function runProviderList() {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
790
|
+
const enabled = await readEnabledProviders2();
|
|
791
|
+
const allAdapters = getAllAdapters();
|
|
792
|
+
console.log("Available providers:");
|
|
793
|
+
console.log("");
|
|
794
|
+
for (const adapter of allAdapters) {
|
|
795
|
+
const isEnabled = enabled.includes(adapter.id);
|
|
796
|
+
const marker = isEnabled ? "●" : "○";
|
|
797
|
+
console.log(` ${marker} ${adapter.displayName} (${adapter.id})`);
|
|
798
|
+
}
|
|
799
|
+
console.log("");
|
|
800
|
+
console.log("Legend: ● enabled, ○ disabled");
|
|
514
801
|
}
|
|
515
802
|
async function runProviderEnable(_flags, providerId) {
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
});
|
|
803
|
+
if (!providerId) {
|
|
804
|
+
console.error("Error: Provider ID is required");
|
|
805
|
+
console.error("Usage: omnidev provider enable <provider-id>");
|
|
806
|
+
process.exit(1);
|
|
807
|
+
}
|
|
808
|
+
const allAdapters = getAllAdapters();
|
|
809
|
+
const adapter = allAdapters.find((a) => a.id === providerId);
|
|
810
|
+
if (!adapter) {
|
|
811
|
+
console.error(`Error: Unknown provider "${providerId}"`);
|
|
812
|
+
console.error("Available providers:");
|
|
813
|
+
for (const a of allAdapters) {
|
|
814
|
+
console.error(` - ${a.id}`);
|
|
815
|
+
}
|
|
816
|
+
process.exit(1);
|
|
817
|
+
}
|
|
818
|
+
await enableProvider(providerId);
|
|
819
|
+
console.log(`✓ Enabled provider: ${adapter.displayName}`);
|
|
820
|
+
const enabledAdapters = await getEnabledAdapters();
|
|
821
|
+
await syncAgentConfiguration4({ silent: false, adapters: enabledAdapters });
|
|
536
822
|
}
|
|
537
823
|
async function runProviderDisable(_flags, providerId) {
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
824
|
+
if (!providerId) {
|
|
825
|
+
console.error("Error: Provider ID is required");
|
|
826
|
+
console.error("Usage: omnidev provider disable <provider-id>");
|
|
827
|
+
process.exit(1);
|
|
828
|
+
}
|
|
829
|
+
const allAdapters = getAllAdapters();
|
|
830
|
+
const adapter = allAdapters.find((a) => a.id === providerId);
|
|
831
|
+
if (!adapter) {
|
|
832
|
+
console.error(`Error: Unknown provider "${providerId}"`);
|
|
833
|
+
console.error("Available providers:");
|
|
834
|
+
for (const a of allAdapters) {
|
|
835
|
+
console.error(` - ${a.id}`);
|
|
836
|
+
}
|
|
837
|
+
process.exit(1);
|
|
838
|
+
}
|
|
839
|
+
await disableProvider(providerId);
|
|
840
|
+
console.log(`✓ Disabled provider: ${adapter.displayName}`);
|
|
553
841
|
}
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
func: runProviderList
|
|
842
|
+
var listCommand3 = buildCommand5({
|
|
843
|
+
parameters: {
|
|
844
|
+
flags: {},
|
|
845
|
+
positional: { kind: "tuple", parameters: [] }
|
|
846
|
+
},
|
|
847
|
+
docs: {
|
|
848
|
+
brief: "List all providers and their status"
|
|
849
|
+
},
|
|
850
|
+
func: runProviderList
|
|
564
851
|
});
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
852
|
+
var enableCommand2 = buildCommand5({
|
|
853
|
+
parameters: {
|
|
854
|
+
flags: {},
|
|
855
|
+
positional: {
|
|
856
|
+
kind: "tuple",
|
|
857
|
+
parameters: [
|
|
858
|
+
{
|
|
859
|
+
brief: "Provider ID to enable",
|
|
860
|
+
parse: String,
|
|
861
|
+
optional: true
|
|
862
|
+
}
|
|
863
|
+
]
|
|
864
|
+
}
|
|
865
|
+
},
|
|
866
|
+
docs: {
|
|
867
|
+
brief: "Enable a provider"
|
|
868
|
+
},
|
|
869
|
+
func: runProviderEnable
|
|
579
870
|
});
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
871
|
+
var disableCommand2 = buildCommand5({
|
|
872
|
+
parameters: {
|
|
873
|
+
flags: {},
|
|
874
|
+
positional: {
|
|
875
|
+
kind: "tuple",
|
|
876
|
+
parameters: [
|
|
877
|
+
{
|
|
878
|
+
brief: "Provider ID to disable",
|
|
879
|
+
parse: String,
|
|
880
|
+
optional: true
|
|
881
|
+
}
|
|
882
|
+
]
|
|
883
|
+
}
|
|
884
|
+
},
|
|
885
|
+
docs: {
|
|
886
|
+
brief: "Disable a provider"
|
|
887
|
+
},
|
|
888
|
+
func: runProviderDisable
|
|
594
889
|
});
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
890
|
+
var providerRoutes = buildRouteMap3({
|
|
891
|
+
routes: {
|
|
892
|
+
list: listCommand3,
|
|
893
|
+
enable: enableCommand2,
|
|
894
|
+
disable: disableCommand2
|
|
895
|
+
},
|
|
896
|
+
docs: {
|
|
897
|
+
brief: "Manage AI provider adapters"
|
|
898
|
+
}
|
|
602
899
|
});
|
|
603
900
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
901
|
+
// src/commands/sync.ts
|
|
902
|
+
import { getActiveProfile as getActiveProfile2, loadConfig as loadConfig3, syncAgentConfiguration as syncAgentConfiguration5 } from "@omnidev-ai/core";
|
|
903
|
+
import { buildCommand as buildCommand6 } from "@stricli/core";
|
|
904
|
+
var syncCommand = buildCommand6({
|
|
905
|
+
docs: {
|
|
906
|
+
brief: "Manually sync all capabilities, roles, and instructions"
|
|
907
|
+
},
|
|
908
|
+
parameters: {},
|
|
909
|
+
async func() {
|
|
910
|
+
return await runSync();
|
|
911
|
+
}
|
|
612
912
|
});
|
|
613
913
|
async function runSync() {
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
}
|
|
914
|
+
console.log("Syncing OmniDev configuration...");
|
|
915
|
+
console.log("");
|
|
916
|
+
try {
|
|
917
|
+
const config = await loadConfig3();
|
|
918
|
+
const activeProfile = await getActiveProfile2() ?? config.active_profile ?? "default";
|
|
919
|
+
const adapters = await getEnabledAdapters();
|
|
920
|
+
const result = await syncAgentConfiguration5({ silent: false, adapters });
|
|
921
|
+
console.log("");
|
|
922
|
+
console.log("✓ Sync completed successfully!");
|
|
923
|
+
console.log("");
|
|
924
|
+
console.log(`Profile: ${activeProfile}`);
|
|
925
|
+
console.log(`Capabilities: ${result.capabilities.join(", ") || "none"}`);
|
|
926
|
+
console.log(`Providers: ${adapters.map((a) => a.displayName).join(", ") || "none"}`);
|
|
927
|
+
console.log("");
|
|
928
|
+
console.log("Synced components:");
|
|
929
|
+
console.log(" • Capability registry");
|
|
930
|
+
console.log(" • Capability sync hooks");
|
|
931
|
+
console.log(" • .omni/.gitignore");
|
|
932
|
+
console.log(" • .omni/instructions.md");
|
|
933
|
+
if (adapters.length > 0) {
|
|
934
|
+
console.log(" • Provider-specific files");
|
|
935
|
+
}
|
|
936
|
+
} catch (error) {
|
|
937
|
+
console.error("");
|
|
938
|
+
console.error("✗ Sync failed:");
|
|
939
|
+
console.error(` ${error instanceof Error ? error.message : String(error)}`);
|
|
940
|
+
process.exit(1);
|
|
941
|
+
}
|
|
643
942
|
}
|
|
644
943
|
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
*/
|
|
944
|
+
// src/lib/debug.ts
|
|
945
|
+
import { debug } from "@omnidev-ai/core";
|
|
946
|
+
|
|
947
|
+
// src/lib/dynamic-app.ts
|
|
650
948
|
async function buildDynamicApp() {
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
949
|
+
const routes = {
|
|
950
|
+
init: initCommand,
|
|
951
|
+
doctor: doctorCommand,
|
|
952
|
+
sync: syncCommand,
|
|
953
|
+
capability: capabilityRoutes,
|
|
954
|
+
profile: profileRoutes,
|
|
955
|
+
provider: providerRoutes
|
|
956
|
+
};
|
|
957
|
+
debug("Core routes registered", Object.keys(routes));
|
|
958
|
+
if (existsSync7(".omni/config.toml")) {
|
|
959
|
+
try {
|
|
960
|
+
const capabilityCommands = await loadCapabilityCommands();
|
|
961
|
+
debug("Capability commands loaded", {
|
|
962
|
+
commands: Object.keys(capabilityCommands),
|
|
963
|
+
details: Object.entries(capabilityCommands).map(([name, cmd]) => ({
|
|
964
|
+
name,
|
|
965
|
+
type: typeof cmd,
|
|
966
|
+
constructor: cmd?.constructor?.name,
|
|
967
|
+
keys: Object.keys(cmd),
|
|
968
|
+
hasGetRoutingTargetForInput: typeof cmd?.getRoutingTargetForInput
|
|
969
|
+
}))
|
|
970
|
+
});
|
|
971
|
+
Object.assign(routes, capabilityCommands);
|
|
972
|
+
} catch (error) {
|
|
973
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
974
|
+
console.warn(`Warning: Failed to load capability commands: ${errorMessage}`);
|
|
975
|
+
debug("Full error loading capabilities", error);
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
debug("Final routes", Object.keys(routes));
|
|
979
|
+
const app = buildApplication(buildRouteMap4({
|
|
980
|
+
routes,
|
|
981
|
+
docs: {
|
|
982
|
+
brief: "OmniDev commands"
|
|
983
|
+
}
|
|
984
|
+
}), {
|
|
985
|
+
name: "omnidev",
|
|
986
|
+
versionInfo: {
|
|
987
|
+
currentVersion: "0.1.0"
|
|
988
|
+
}
|
|
989
|
+
});
|
|
990
|
+
debug("App built successfully");
|
|
991
|
+
return app;
|
|
688
992
|
}
|
|
689
|
-
/**
|
|
690
|
-
* Load CLI commands from enabled capabilities
|
|
691
|
-
*/
|
|
692
993
|
async function loadCapabilityCommands() {
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
994
|
+
const { buildCapabilityRegistry, installCapabilityDependencies } = await import("@omnidev-ai/core");
|
|
995
|
+
await installCapabilityDependencies(true);
|
|
996
|
+
const registry = await buildCapabilityRegistry();
|
|
997
|
+
const capabilities = registry.getAllCapabilities();
|
|
998
|
+
const commands = {};
|
|
999
|
+
for (const capability of capabilities) {
|
|
1000
|
+
try {
|
|
1001
|
+
debug(`Loading capability '${capability.id}'`, { path: capability.path });
|
|
1002
|
+
const capabilityExport = await loadCapabilityExport(capability);
|
|
1003
|
+
debug(`Capability '${capability.id}' export`, {
|
|
1004
|
+
found: !!capabilityExport,
|
|
1005
|
+
hasCLICommands: !!capabilityExport?.cliCommands,
|
|
1006
|
+
cliCommands: capabilityExport?.cliCommands ? Object.keys(capabilityExport.cliCommands) : []
|
|
1007
|
+
});
|
|
1008
|
+
if (capabilityExport?.cliCommands) {
|
|
1009
|
+
for (const [commandName, command] of Object.entries(capabilityExport.cliCommands)) {
|
|
1010
|
+
if (commands[commandName]) {
|
|
1011
|
+
console.warn(`Command '${commandName}' from capability '${capability.id}' conflicts with existing command. Using '${capability.id}' version.`);
|
|
1012
|
+
}
|
|
1013
|
+
commands[commandName] = command;
|
|
1014
|
+
debug(`Registered command '${commandName}' from '${capability.id}'`, {
|
|
1015
|
+
type: typeof command,
|
|
1016
|
+
constructor: command?.constructor?.name
|
|
1017
|
+
});
|
|
1018
|
+
}
|
|
1019
|
+
}
|
|
1020
|
+
} catch (error) {
|
|
1021
|
+
console.error(`Failed to load capability '${capability.id}':`, error);
|
|
1022
|
+
}
|
|
1023
|
+
}
|
|
1024
|
+
return commands;
|
|
718
1025
|
}
|
|
719
|
-
/**
|
|
720
|
-
* Load the default export from a capability
|
|
721
|
-
*/
|
|
722
1026
|
async function loadCapabilityExport(capability) {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
1027
|
+
const capabilityPath = join5(process.cwd(), capability.path);
|
|
1028
|
+
const indexPath = join5(capabilityPath, "index.ts");
|
|
1029
|
+
if (!existsSync7(indexPath)) {
|
|
1030
|
+
const jsIndexPath = join5(capabilityPath, "index.js");
|
|
1031
|
+
if (!existsSync7(jsIndexPath)) {
|
|
1032
|
+
return null;
|
|
1033
|
+
}
|
|
1034
|
+
const module2 = await import(jsIndexPath);
|
|
1035
|
+
if (!module2.default) {
|
|
1036
|
+
return null;
|
|
1037
|
+
}
|
|
1038
|
+
return module2.default;
|
|
1039
|
+
}
|
|
1040
|
+
const module = await import(indexPath);
|
|
1041
|
+
if (!module.default) {
|
|
1042
|
+
return null;
|
|
1043
|
+
}
|
|
1044
|
+
const capExport = module.default;
|
|
1045
|
+
if (capExport.cliCommands) {
|
|
1046
|
+
for (const [name, cmd] of Object.entries(capExport.cliCommands)) {
|
|
1047
|
+
debug(`CLI command '${name}' structure`, {
|
|
1048
|
+
type: typeof cmd,
|
|
1049
|
+
constructor: cmd?.constructor?.name,
|
|
1050
|
+
keys: Object.keys(cmd),
|
|
1051
|
+
hasGetRoutingTargetForInput: typeof cmd?.getRoutingTargetForInput,
|
|
1052
|
+
routesKeys: cmd.routes ? Object.keys(cmd.routes) : undefined
|
|
1053
|
+
});
|
|
1054
|
+
}
|
|
1055
|
+
}
|
|
1056
|
+
return capExport;
|
|
743
1057
|
}
|
|
744
1058
|
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
const app = await buildDynamicApp();
|
|
1059
|
+
// src/index.ts
|
|
1060
|
+
var app = await buildDynamicApp();
|
|
748
1061
|
debug("CLI startup", {
|
|
749
|
-
|
|
750
|
-
|
|
1062
|
+
arguments: process.argv.slice(2),
|
|
1063
|
+
cwd: process.cwd()
|
|
751
1064
|
});
|
|
752
1065
|
try {
|
|
753
|
-
|
|
1066
|
+
run(app, process.argv.slice(2), {
|
|
1067
|
+
process
|
|
1068
|
+
});
|
|
754
1069
|
} catch (error) {
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
1070
|
+
if (error instanceof Error) {
|
|
1071
|
+
if (error.message.includes("getRoutingTargetForInput") || error.stack?.includes("@stricli/core")) {
|
|
1072
|
+
const args = process.argv.slice(2);
|
|
1073
|
+
console.error(`
|
|
1074
|
+
Error: Command not found or invalid usage.`);
|
|
1075
|
+
if (args.length > 0) {
|
|
1076
|
+
console.error(`
|
|
1077
|
+
You tried to run: omnidev ${args.join(" ")}`);
|
|
1078
|
+
console.error(`
|
|
1079
|
+
This could mean:`);
|
|
1080
|
+
console.error(" 1. The command doesn't exist");
|
|
1081
|
+
console.error(" 2. A required capability is not enabled");
|
|
1082
|
+
console.error(` 3. Invalid command syntax
|
|
1083
|
+
`);
|
|
1084
|
+
}
|
|
1085
|
+
console.error("Run 'omnidev --help' to see available commands");
|
|
1086
|
+
console.error(`
|
|
1087
|
+
To enable capabilities, run: omnidev capability enable <name>`);
|
|
1088
|
+
console.error("To see enabled capabilities: omnidev capability list");
|
|
1089
|
+
process.exit(1);
|
|
1090
|
+
} else {
|
|
1091
|
+
throw error;
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
770
1094
|
}
|
|
771
|
-
|
|
772
|
-
//#endregion
|