@omnidev-ai/cli 0.1.0 → 0.3.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/package.json +6 -3
- package/src/commands/AGENTS.md +0 -2
- package/src/commands/capability.test.ts +5 -35
- package/src/commands/capability.ts +7 -4
- package/src/commands/doctor.test.ts +32 -33
- package/src/commands/doctor.ts +24 -7
- package/src/commands/init.test.ts +97 -73
- package/src/commands/init.ts +93 -97
- package/src/commands/profile.test.ts +9 -22
- package/src/commands/profile.ts +4 -2
- package/src/commands/provider.test.ts +128 -0
- package/src/commands/provider.ts +139 -0
- package/src/commands/sync.ts +10 -4
- package/src/index.ts +2 -2
- package/src/lib/dynamic-app.ts +2 -4
- package/src/prompts/provider.ts +6 -4
- package/src/commands/mcp.ts +0 -113
- package/src/commands/serve.test.ts +0 -184
- package/src/commands/serve.ts +0 -63
package/src/commands/init.ts
CHANGED
|
@@ -1,46 +1,43 @@
|
|
|
1
1
|
import { existsSync, mkdirSync } from "node:fs";
|
|
2
|
-
import
|
|
2
|
+
import { getAllAdapters, getEnabledAdapters } from "@omnidev-ai/adapters";
|
|
3
|
+
import type { ProviderId, ProviderContext } from "@omnidev-ai/core";
|
|
3
4
|
import {
|
|
4
|
-
generateAgentsTemplate,
|
|
5
|
-
generateClaudeTemplate,
|
|
6
5
|
generateInstructionsTemplate,
|
|
7
|
-
|
|
6
|
+
loadConfig,
|
|
8
7
|
setActiveProfile,
|
|
9
8
|
syncAgentConfiguration,
|
|
10
9
|
writeConfig,
|
|
10
|
+
writeEnabledProviders,
|
|
11
11
|
} from "@omnidev-ai/core";
|
|
12
12
|
import { buildCommand } from "@stricli/core";
|
|
13
|
-
import {
|
|
13
|
+
import { promptForProviders } from "../prompts/provider.js";
|
|
14
14
|
|
|
15
|
-
export async function runInit(_flags: Record<string, never>,
|
|
15
|
+
export async function runInit(_flags: Record<string, never>, providerArg?: string) {
|
|
16
16
|
console.log("Initializing OmniDev...");
|
|
17
17
|
|
|
18
18
|
// Create .omni/ directory structure
|
|
19
19
|
mkdirSync(".omni", { recursive: true });
|
|
20
20
|
mkdirSync(".omni/capabilities", { recursive: true });
|
|
21
21
|
mkdirSync(".omni/state", { recursive: true });
|
|
22
|
-
mkdirSync(".omni/sandbox", { recursive: true });
|
|
23
22
|
|
|
24
|
-
//
|
|
25
|
-
|
|
26
|
-
await Bun.write(".omni/.gitignore", internalGitignore());
|
|
27
|
-
}
|
|
23
|
+
// Update root .gitignore to ignore .omni/ and omni.local.toml
|
|
24
|
+
await updateRootGitignore();
|
|
28
25
|
|
|
29
26
|
// Get provider selection
|
|
30
|
-
let
|
|
31
|
-
if (
|
|
32
|
-
|
|
27
|
+
let providerIds: ProviderId[];
|
|
28
|
+
if (providerArg) {
|
|
29
|
+
providerIds = parseProviderArg(providerArg);
|
|
33
30
|
} else {
|
|
34
|
-
|
|
31
|
+
providerIds = await promptForProviders();
|
|
35
32
|
}
|
|
36
33
|
|
|
37
|
-
//
|
|
34
|
+
// Save enabled providers to local state (not omni.toml)
|
|
35
|
+
await writeEnabledProviders(providerIds);
|
|
36
|
+
|
|
37
|
+
// Create omni.toml at project root (without provider config - that's in state)
|
|
38
38
|
if (!existsSync("omni.toml")) {
|
|
39
39
|
await writeConfig({
|
|
40
40
|
project: "my-project",
|
|
41
|
-
providers: {
|
|
42
|
-
enabled: providers,
|
|
43
|
-
},
|
|
44
41
|
profiles: {
|
|
45
42
|
default: {
|
|
46
43
|
capabilities: [],
|
|
@@ -53,7 +50,7 @@ export async function runInit(_flags: Record<string, never>, provider?: string)
|
|
|
53
50
|
},
|
|
54
51
|
},
|
|
55
52
|
});
|
|
56
|
-
// Set active profile in state file
|
|
53
|
+
// Set active profile in state file
|
|
57
54
|
await setActiveProfile("default");
|
|
58
55
|
}
|
|
59
56
|
|
|
@@ -62,61 +59,58 @@ export async function runInit(_flags: Record<string, never>, provider?: string)
|
|
|
62
59
|
await Bun.write(".omni/instructions.md", generateInstructionsTemplate());
|
|
63
60
|
}
|
|
64
61
|
|
|
65
|
-
//
|
|
66
|
-
const
|
|
62
|
+
// Load config and create provider context
|
|
63
|
+
const config = await loadConfig();
|
|
64
|
+
const ctx: ProviderContext = {
|
|
65
|
+
projectRoot: process.cwd(),
|
|
66
|
+
config,
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// Initialize enabled adapters (create their root files)
|
|
70
|
+
const allAdapters = getAllAdapters();
|
|
71
|
+
const selectedAdapters = allAdapters.filter((a) => providerIds.includes(a.id));
|
|
72
|
+
const filesCreated: string[] = [];
|
|
73
|
+
const filesExisting: string[] = [];
|
|
74
|
+
|
|
75
|
+
for (const adapter of selectedAdapters) {
|
|
76
|
+
if (adapter.init) {
|
|
77
|
+
const result = await adapter.init(ctx);
|
|
78
|
+
if (result.filesCreated) {
|
|
79
|
+
filesCreated.push(...result.filesCreated);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
67
83
|
|
|
68
|
-
// Run initial sync
|
|
69
|
-
|
|
84
|
+
// Run initial sync with enabled adapters (silent - no need to show details)
|
|
85
|
+
const enabledAdapters = await getEnabledAdapters();
|
|
86
|
+
await syncAgentConfiguration({ silent: true, adapters: enabledAdapters });
|
|
70
87
|
|
|
88
|
+
// Output success message
|
|
71
89
|
console.log("");
|
|
72
|
-
console.log(
|
|
90
|
+
console.log(
|
|
91
|
+
`✓ OmniDev initialized for ${selectedAdapters.map((a) => a.displayName).join(" and ")}!`,
|
|
92
|
+
);
|
|
73
93
|
console.log("");
|
|
74
94
|
|
|
75
95
|
// Show appropriate message based on file status
|
|
76
|
-
|
|
77
|
-
const hasExistingFiles = fileStatus.existing.length > 0;
|
|
78
|
-
|
|
79
|
-
if (hasNewFiles) {
|
|
96
|
+
if (filesCreated.length > 0) {
|
|
80
97
|
console.log("📝 Don't forget to add your project description to:");
|
|
81
98
|
console.log(" • .omni/instructions.md");
|
|
82
99
|
}
|
|
83
100
|
|
|
84
|
-
if (
|
|
101
|
+
if (filesExisting.length > 0) {
|
|
85
102
|
console.log("📝 Add this line to your existing file(s):");
|
|
86
|
-
for (const file of
|
|
103
|
+
for (const file of filesExisting) {
|
|
87
104
|
console.log(` • ${file}: @import .omni/instructions.md`);
|
|
88
105
|
}
|
|
89
106
|
}
|
|
90
107
|
|
|
91
108
|
console.log("");
|
|
92
|
-
console.log("
|
|
93
|
-
console.log("");
|
|
94
|
-
console.log("
|
|
95
|
-
console.log(" {");
|
|
96
|
-
console.log(' "mcpServers": {');
|
|
97
|
-
console.log(' "omnidev": {');
|
|
98
|
-
console.log(' "command": "npx",');
|
|
99
|
-
console.log(' "args": ["-y", "@omnidev-ai/cli", "serve"]');
|
|
100
|
-
console.log(" }");
|
|
101
|
-
console.log(" }");
|
|
102
|
-
console.log(" }");
|
|
103
|
-
console.log("");
|
|
104
|
-
console.log(" Or for local development:");
|
|
105
|
-
console.log(" {");
|
|
106
|
-
console.log(' "mcpServers": {');
|
|
107
|
-
console.log(' "omnidev": {');
|
|
108
|
-
console.log(' "command": "bun",');
|
|
109
|
-
console.log(' "args": ["run", "omnidev", "serve"],');
|
|
110
|
-
console.log(' "cwd": "/path/to/your/project"');
|
|
111
|
-
console.log(" }");
|
|
112
|
-
console.log(" }");
|
|
113
|
-
console.log(" }");
|
|
109
|
+
console.log("💡 Recommendation:");
|
|
110
|
+
console.log(" Add provider-specific files to .gitignore:");
|
|
111
|
+
console.log(" CLAUDE.md, .claude/, AGENTS.md, .cursor/, .mcp.json");
|
|
114
112
|
console.log("");
|
|
115
|
-
console.log("
|
|
116
|
-
console.log(" • omni.toml - Main config (commit to share with team)");
|
|
117
|
-
console.log(" • omni.lock.toml - Lock file (commit for reproducibility)");
|
|
118
|
-
console.log(" • omni.local.toml - Local overrides (add to .gitignore)");
|
|
119
|
-
console.log(" • .omni/ - Runtime directory (add to .gitignore)");
|
|
113
|
+
console.log(" Run 'omnidev capability list' to see available capabilities.");
|
|
120
114
|
}
|
|
121
115
|
|
|
122
116
|
export const initCommand = buildCommand({
|
|
@@ -126,7 +120,7 @@ export const initCommand = buildCommand({
|
|
|
126
120
|
kind: "tuple" as const,
|
|
127
121
|
parameters: [
|
|
128
122
|
{
|
|
129
|
-
brief: "AI provider: claude, codex, or
|
|
123
|
+
brief: "AI provider(s): claude-code, cursor, codex, opencode, or comma-separated",
|
|
130
124
|
parse: String,
|
|
131
125
|
optional: true,
|
|
132
126
|
},
|
|
@@ -139,54 +133,56 @@ export const initCommand = buildCommand({
|
|
|
139
133
|
func: runInit,
|
|
140
134
|
});
|
|
141
135
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (providers.includes("codex")) {
|
|
150
|
-
if (!existsSync("AGENTS.md")) {
|
|
151
|
-
await Bun.write("AGENTS.md", generateAgentsTemplate());
|
|
152
|
-
created.push("AGENTS.md");
|
|
153
|
-
} else {
|
|
154
|
-
existing.push("AGENTS.md");
|
|
155
|
-
}
|
|
136
|
+
function parseProviderArg(arg: string): ProviderId[] {
|
|
137
|
+
const allAdapters = getAllAdapters();
|
|
138
|
+
const validIds = new Set(allAdapters.map((a) => a.id));
|
|
139
|
+
|
|
140
|
+
// Handle legacy "both" argument
|
|
141
|
+
if (arg.toLowerCase() === "both") {
|
|
142
|
+
return ["claude-code", "cursor"];
|
|
156
143
|
}
|
|
157
144
|
|
|
158
|
-
//
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
145
|
+
// Handle comma-separated list
|
|
146
|
+
const parts = arg.split(",").map((p) => p.trim().toLowerCase());
|
|
147
|
+
const result: ProviderId[] = [];
|
|
148
|
+
|
|
149
|
+
for (const part of parts) {
|
|
150
|
+
// Map legacy names
|
|
151
|
+
let id = part;
|
|
152
|
+
if (id === "claude") {
|
|
153
|
+
id = "claude-code";
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
if (!validIds.has(id)) {
|
|
157
|
+
throw new Error(`Invalid provider: ${part}. Valid providers: ${[...validIds].join(", ")}`);
|
|
165
158
|
}
|
|
159
|
+
result.push(id as ProviderId);
|
|
166
160
|
}
|
|
167
161
|
|
|
168
|
-
return
|
|
162
|
+
return result;
|
|
169
163
|
}
|
|
170
164
|
|
|
171
|
-
function
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# Secrets
|
|
176
|
-
.env
|
|
165
|
+
async function updateRootGitignore(): Promise<void> {
|
|
166
|
+
const gitignorePath = ".gitignore";
|
|
167
|
+
const entriesToAdd = [".omni/", "omni.local.toml"];
|
|
177
168
|
|
|
178
|
-
|
|
179
|
-
|
|
169
|
+
let content = "";
|
|
170
|
+
if (existsSync(gitignorePath)) {
|
|
171
|
+
content = await Bun.file(gitignorePath).text();
|
|
172
|
+
}
|
|
180
173
|
|
|
181
|
-
|
|
182
|
-
|
|
174
|
+
const lines = content.split("\n");
|
|
175
|
+
const missingEntries = entriesToAdd.filter(
|
|
176
|
+
(entry) => !lines.some((line) => line.trim() === entry),
|
|
177
|
+
);
|
|
183
178
|
|
|
184
|
-
|
|
185
|
-
|
|
179
|
+
if (missingEntries.length === 0) {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
186
182
|
|
|
187
|
-
|
|
188
|
-
|
|
183
|
+
// Add a newline before our section if the file doesn't end with one
|
|
184
|
+
const needsNewline = content.length > 0 && !content.endsWith("\n");
|
|
185
|
+
const section = `${needsNewline ? "\n" : ""}# OmniDev\n${missingEntries.join("\n")}\n`;
|
|
189
186
|
|
|
190
|
-
|
|
191
|
-
`;
|
|
187
|
+
await Bun.write(gitignorePath, content + section);
|
|
192
188
|
}
|
|
@@ -1,23 +1,18 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { mkdirSync } from "node:fs";
|
|
3
|
+
import { setupTestDir } from "@omnidev-ai/core/test-utils";
|
|
4
4
|
import { runProfileList, runProfileSet } from "./profile";
|
|
5
5
|
|
|
6
6
|
describe("profile commands", () => {
|
|
7
|
-
|
|
8
|
-
let originalCwd: string;
|
|
7
|
+
setupTestDir("profile-test-", { chdir: true });
|
|
9
8
|
let originalExit: typeof process.exit;
|
|
10
9
|
let exitCode: number | undefined;
|
|
11
10
|
let consoleOutput: string[];
|
|
12
11
|
let consoleErrors: string[];
|
|
12
|
+
let originalLog: typeof console.log;
|
|
13
|
+
let originalError: typeof console.error;
|
|
13
14
|
|
|
14
15
|
beforeEach(() => {
|
|
15
|
-
// Create a unique test directory
|
|
16
|
-
testDir = join(import.meta.dir, "..", "..", "..", "test-temp", `profile-test-${Date.now()}`);
|
|
17
|
-
mkdirSync(testDir, { recursive: true });
|
|
18
|
-
originalCwd = process.cwd();
|
|
19
|
-
process.chdir(testDir);
|
|
20
|
-
|
|
21
16
|
// Mock process.exit
|
|
22
17
|
exitCode = undefined;
|
|
23
18
|
originalExit = process.exit;
|
|
@@ -29,28 +24,20 @@ describe("profile commands", () => {
|
|
|
29
24
|
// Mock console
|
|
30
25
|
consoleOutput = [];
|
|
31
26
|
consoleErrors = [];
|
|
32
|
-
|
|
33
|
-
|
|
27
|
+
originalLog = console.log;
|
|
28
|
+
originalError = console.error;
|
|
34
29
|
console.log = (...args: unknown[]) => {
|
|
35
30
|
consoleOutput.push(args.join(" "));
|
|
36
31
|
};
|
|
37
32
|
console.error = (...args: unknown[]) => {
|
|
38
33
|
consoleErrors.push(args.join(" "));
|
|
39
34
|
};
|
|
40
|
-
|
|
41
|
-
// Restore after test (in afterEach)
|
|
42
|
-
return () => {
|
|
43
|
-
console.log = originalLog;
|
|
44
|
-
console.error = originalError;
|
|
45
|
-
};
|
|
46
35
|
});
|
|
47
36
|
|
|
48
37
|
afterEach(() => {
|
|
49
38
|
process.exit = originalExit;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
rmSync(testDir, { recursive: true, force: true });
|
|
53
|
-
}
|
|
39
|
+
console.log = originalLog;
|
|
40
|
+
console.error = originalError;
|
|
54
41
|
});
|
|
55
42
|
|
|
56
43
|
describe("runProfileList", () => {
|
package/src/commands/profile.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
|
+
import { getEnabledAdapters } from "@omnidev-ai/adapters";
|
|
2
3
|
import {
|
|
3
4
|
getActiveProfile,
|
|
4
5
|
loadConfig,
|
|
@@ -142,8 +143,9 @@ export async function runProfileSet(profileName: string): Promise<void> {
|
|
|
142
143
|
console.log(`✓ Active profile set to: ${profileName}`);
|
|
143
144
|
console.log("");
|
|
144
145
|
|
|
145
|
-
// Auto-sync agent configuration
|
|
146
|
-
await
|
|
146
|
+
// Auto-sync agent configuration with enabled adapters
|
|
147
|
+
const adapters = await getEnabledAdapters();
|
|
148
|
+
await syncAgentConfiguration({ adapters });
|
|
147
149
|
} catch (error) {
|
|
148
150
|
console.error("✗ Error setting profile:", error);
|
|
149
151
|
process.exit(1);
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, test } from "bun:test";
|
|
2
|
+
import { existsSync, mkdirSync, rmSync } from "node:fs";
|
|
3
|
+
import { captureConsole, tmpdir } from "@omnidev-ai/core/test-utils";
|
|
4
|
+
import { runProviderList, runProviderEnable, runProviderDisable } from "./provider";
|
|
5
|
+
|
|
6
|
+
// Import the functions we need to test
|
|
7
|
+
async function getProviderFunctions() {
|
|
8
|
+
const { readEnabledProviders, writeEnabledProviders } = await import("@omnidev-ai/core");
|
|
9
|
+
return { readEnabledProviders, writeEnabledProviders };
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
describe("provider commands", () => {
|
|
13
|
+
let testDir: string;
|
|
14
|
+
let originalCwd: string;
|
|
15
|
+
|
|
16
|
+
beforeEach(async () => {
|
|
17
|
+
originalCwd = process.cwd();
|
|
18
|
+
testDir = tmpdir("provider-test-");
|
|
19
|
+
process.chdir(testDir);
|
|
20
|
+
|
|
21
|
+
// Create basic OmniDev structure
|
|
22
|
+
mkdirSync(".omni/state", { recursive: true });
|
|
23
|
+
await Bun.write("omni.toml", 'project = "test"\n');
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
afterEach(() => {
|
|
27
|
+
process.chdir(originalCwd);
|
|
28
|
+
if (existsSync(testDir)) {
|
|
29
|
+
rmSync(testDir, { recursive: true, force: true });
|
|
30
|
+
}
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
describe("runProviderList", () => {
|
|
34
|
+
test("lists all providers with status", async () => {
|
|
35
|
+
const { writeEnabledProviders } = await getProviderFunctions();
|
|
36
|
+
await writeEnabledProviders(["claude-code", "cursor"]);
|
|
37
|
+
|
|
38
|
+
const { stdout } = await captureConsole(async () => {
|
|
39
|
+
await runProviderList();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const output = stdout.join("\n");
|
|
43
|
+
expect(output).toContain("Available providers:");
|
|
44
|
+
expect(output).toContain("Claude Code");
|
|
45
|
+
expect(output).toContain("Cursor");
|
|
46
|
+
expect(output).toContain("Codex");
|
|
47
|
+
expect(output).toContain("OpenCode");
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test("shows enabled providers with marker", async () => {
|
|
51
|
+
const { writeEnabledProviders } = await getProviderFunctions();
|
|
52
|
+
await writeEnabledProviders(["claude-code"]);
|
|
53
|
+
|
|
54
|
+
const { stdout } = await captureConsole(async () => {
|
|
55
|
+
await runProviderList();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
const output = stdout.join("\n");
|
|
59
|
+
// Should have at least one enabled marker
|
|
60
|
+
expect(output).toContain("●");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("shows disabled providers with different marker", async () => {
|
|
64
|
+
const { writeEnabledProviders } = await getProviderFunctions();
|
|
65
|
+
await writeEnabledProviders(["claude-code"]);
|
|
66
|
+
|
|
67
|
+
const { stdout } = await captureConsole(async () => {
|
|
68
|
+
await runProviderList();
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
const output = stdout.join("\n");
|
|
72
|
+
// Should have disabled markers for other providers
|
|
73
|
+
expect(output).toContain("○");
|
|
74
|
+
});
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
describe("runProviderEnable", () => {
|
|
78
|
+
test("enables a provider", async () => {
|
|
79
|
+
const { writeEnabledProviders, readEnabledProviders } = await getProviderFunctions();
|
|
80
|
+
await writeEnabledProviders(["claude-code"]);
|
|
81
|
+
|
|
82
|
+
await captureConsole(async () => {
|
|
83
|
+
await runProviderEnable({}, "cursor");
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const providers = await readEnabledProviders();
|
|
87
|
+
expect(providers).toContain("cursor");
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
test("shows success message", async () => {
|
|
91
|
+
const { writeEnabledProviders } = await getProviderFunctions();
|
|
92
|
+
await writeEnabledProviders(["claude-code"]);
|
|
93
|
+
|
|
94
|
+
const { stdout } = await captureConsole(async () => {
|
|
95
|
+
await runProviderEnable({}, "cursor");
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const output = stdout.join("\n");
|
|
99
|
+
expect(output).toContain("✓ Enabled provider: Cursor");
|
|
100
|
+
});
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
describe("runProviderDisable", () => {
|
|
104
|
+
test("disables a provider", async () => {
|
|
105
|
+
const { writeEnabledProviders, readEnabledProviders } = await getProviderFunctions();
|
|
106
|
+
await writeEnabledProviders(["claude-code", "cursor"]);
|
|
107
|
+
|
|
108
|
+
await captureConsole(async () => {
|
|
109
|
+
await runProviderDisable({}, "cursor");
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
const providers = await readEnabledProviders();
|
|
113
|
+
expect(providers).not.toContain("cursor");
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("shows success message", async () => {
|
|
117
|
+
const { writeEnabledProviders } = await getProviderFunctions();
|
|
118
|
+
await writeEnabledProviders(["claude-code", "cursor"]);
|
|
119
|
+
|
|
120
|
+
const { stdout } = await captureConsole(async () => {
|
|
121
|
+
await runProviderDisable({}, "cursor");
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
const output = stdout.join("\n");
|
|
125
|
+
expect(output).toContain("✓ Disabled provider: Cursor");
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
});
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { getAllAdapters } from "@omnidev-ai/adapters";
|
|
2
|
+
import type { ProviderId } from "@omnidev-ai/core";
|
|
3
|
+
import {
|
|
4
|
+
disableProvider,
|
|
5
|
+
enableProvider,
|
|
6
|
+
readEnabledProviders,
|
|
7
|
+
syncAgentConfiguration,
|
|
8
|
+
} from "@omnidev-ai/core";
|
|
9
|
+
import { getEnabledAdapters } from "@omnidev-ai/adapters";
|
|
10
|
+
import { buildCommand, buildRouteMap } from "@stricli/core";
|
|
11
|
+
|
|
12
|
+
export async function runProviderList() {
|
|
13
|
+
const enabled = await readEnabledProviders();
|
|
14
|
+
const allAdapters = getAllAdapters();
|
|
15
|
+
|
|
16
|
+
console.log("Available providers:");
|
|
17
|
+
console.log("");
|
|
18
|
+
|
|
19
|
+
for (const adapter of allAdapters) {
|
|
20
|
+
const isEnabled = enabled.includes(adapter.id);
|
|
21
|
+
const marker = isEnabled ? "●" : "○";
|
|
22
|
+
console.log(` ${marker} ${adapter.displayName} (${adapter.id})`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
console.log("");
|
|
26
|
+
console.log("Legend: ● enabled, ○ disabled");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export async function runProviderEnable(_flags: Record<string, never>, providerId?: string) {
|
|
30
|
+
if (!providerId) {
|
|
31
|
+
console.error("Error: Provider ID is required");
|
|
32
|
+
console.error("Usage: omnidev provider enable <provider-id>");
|
|
33
|
+
process.exit(1);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const allAdapters = getAllAdapters();
|
|
37
|
+
const adapter = allAdapters.find((a) => a.id === providerId);
|
|
38
|
+
|
|
39
|
+
if (!adapter) {
|
|
40
|
+
console.error(`Error: Unknown provider "${providerId}"`);
|
|
41
|
+
console.error("Available providers:");
|
|
42
|
+
for (const a of allAdapters) {
|
|
43
|
+
console.error(` - ${a.id}`);
|
|
44
|
+
}
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
await enableProvider(providerId as ProviderId);
|
|
49
|
+
console.log(`✓ Enabled provider: ${adapter.displayName}`);
|
|
50
|
+
|
|
51
|
+
// Sync with newly enabled adapter
|
|
52
|
+
const enabledAdapters = await getEnabledAdapters();
|
|
53
|
+
await syncAgentConfiguration({ silent: false, adapters: enabledAdapters });
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function runProviderDisable(_flags: Record<string, never>, providerId?: string) {
|
|
57
|
+
if (!providerId) {
|
|
58
|
+
console.error("Error: Provider ID is required");
|
|
59
|
+
console.error("Usage: omnidev provider disable <provider-id>");
|
|
60
|
+
process.exit(1);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const allAdapters = getAllAdapters();
|
|
64
|
+
const adapter = allAdapters.find((a) => a.id === providerId);
|
|
65
|
+
|
|
66
|
+
if (!adapter) {
|
|
67
|
+
console.error(`Error: Unknown provider "${providerId}"`);
|
|
68
|
+
console.error("Available providers:");
|
|
69
|
+
for (const a of allAdapters) {
|
|
70
|
+
console.error(` - ${a.id}`);
|
|
71
|
+
}
|
|
72
|
+
process.exit(1);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
await disableProvider(providerId as ProviderId);
|
|
76
|
+
console.log(`✓ Disabled provider: ${adapter.displayName}`);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
const listCommand = buildCommand({
|
|
80
|
+
parameters: {
|
|
81
|
+
flags: {},
|
|
82
|
+
positional: { kind: "tuple" as const, parameters: [] },
|
|
83
|
+
},
|
|
84
|
+
docs: {
|
|
85
|
+
brief: "List all providers and their status",
|
|
86
|
+
},
|
|
87
|
+
func: runProviderList,
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
const enableCommand = buildCommand({
|
|
91
|
+
parameters: {
|
|
92
|
+
flags: {},
|
|
93
|
+
positional: {
|
|
94
|
+
kind: "tuple" as const,
|
|
95
|
+
parameters: [
|
|
96
|
+
{
|
|
97
|
+
brief: "Provider ID to enable",
|
|
98
|
+
parse: String,
|
|
99
|
+
optional: true,
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
docs: {
|
|
105
|
+
brief: "Enable a provider",
|
|
106
|
+
},
|
|
107
|
+
func: runProviderEnable,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
const disableCommand = buildCommand({
|
|
111
|
+
parameters: {
|
|
112
|
+
flags: {},
|
|
113
|
+
positional: {
|
|
114
|
+
kind: "tuple" as const,
|
|
115
|
+
parameters: [
|
|
116
|
+
{
|
|
117
|
+
brief: "Provider ID to disable",
|
|
118
|
+
parse: String,
|
|
119
|
+
optional: true,
|
|
120
|
+
},
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
docs: {
|
|
125
|
+
brief: "Disable a provider",
|
|
126
|
+
},
|
|
127
|
+
func: runProviderDisable,
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
export const providerRoutes = buildRouteMap({
|
|
131
|
+
routes: {
|
|
132
|
+
list: listCommand,
|
|
133
|
+
enable: enableCommand,
|
|
134
|
+
disable: disableCommand,
|
|
135
|
+
},
|
|
136
|
+
docs: {
|
|
137
|
+
brief: "Manage AI provider adapters",
|
|
138
|
+
},
|
|
139
|
+
});
|
package/src/commands/sync.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
|
+
import { getEnabledAdapters } from "@omnidev-ai/adapters";
|
|
1
2
|
import { getActiveProfile, loadConfig, syncAgentConfiguration } from "@omnidev-ai/core";
|
|
2
3
|
import { buildCommand } from "@stricli/core";
|
|
3
4
|
|
|
4
5
|
export const syncCommand = buildCommand({
|
|
5
6
|
docs: {
|
|
6
|
-
brief: "Manually sync all capabilities, roles,
|
|
7
|
+
brief: "Manually sync all capabilities, roles, and instructions",
|
|
7
8
|
},
|
|
8
9
|
parameters: {},
|
|
9
10
|
async func() {
|
|
@@ -19,21 +20,26 @@ export async function runSync(): Promise<void> {
|
|
|
19
20
|
const config = await loadConfig();
|
|
20
21
|
const activeProfile = (await getActiveProfile()) ?? config.active_profile ?? "default";
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
// Get enabled adapters for provider-specific sync
|
|
24
|
+
const adapters = await getEnabledAdapters();
|
|
25
|
+
|
|
26
|
+
const result = await syncAgentConfiguration({ silent: false, adapters });
|
|
23
27
|
|
|
24
28
|
console.log("");
|
|
25
29
|
console.log("✓ Sync completed successfully!");
|
|
26
30
|
console.log("");
|
|
27
31
|
console.log(`Profile: ${activeProfile}`);
|
|
28
32
|
console.log(`Capabilities: ${result.capabilities.join(", ") || "none"}`);
|
|
33
|
+
console.log(`Providers: ${adapters.map((a) => a.displayName).join(", ") || "none"}`);
|
|
29
34
|
console.log("");
|
|
30
35
|
console.log("Synced components:");
|
|
31
36
|
console.log(" • Capability registry");
|
|
32
37
|
console.log(" • Capability sync hooks");
|
|
33
38
|
console.log(" • .omni/.gitignore");
|
|
34
39
|
console.log(" • .omni/instructions.md");
|
|
35
|
-
|
|
36
|
-
|
|
40
|
+
if (adapters.length > 0) {
|
|
41
|
+
console.log(" • Provider-specific files");
|
|
42
|
+
}
|
|
37
43
|
} catch (error) {
|
|
38
44
|
console.error("");
|
|
39
45
|
console.error("✗ Sync failed:");
|
package/src/index.ts
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
/**
|
|
3
3
|
* @omnidev-ai/cli - Command-line interface for OmniDev
|
|
4
4
|
*
|
|
5
|
-
* This package provides the CLI for managing OmniDev configuration
|
|
6
|
-
*
|
|
5
|
+
* This package provides the CLI for managing OmniDev configuration
|
|
6
|
+
* and capabilities.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import { run } from "@stricli/core";
|