@aiwg/cli 2026.9.2 → 2026.9.4
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/README.md +21 -0
- package/agentic/code/providers/antigravity/provider-contract.v1.json +121 -0
- package/agentic/code/providers/capability-matrix.yaml +87 -1
- package/agentic/code/providers/model-capabilities.v1.json +31 -0
- package/agentic/code/providers/model-catalog.v1.json +29 -0
- package/agentic/code/providers/omp/README.md +58 -0
- package/agentic/code/providers/omp/aiwg-bridge.ts +52 -0
- package/dist/src/agents/agent-deployer.js +18 -0
- package/dist/src/agents/agent-packager.js +25 -0
- package/dist/src/artifacts/backends/sqlite-backend.js +18 -10
- package/dist/src/artifacts/query-engine.js +30 -0
- package/dist/src/cli/agent-spawn.js +13 -2
- package/dist/src/cli/handlers/help.js +3 -1
- package/dist/src/cli/handlers/init.js +2 -0
- package/dist/src/cli/handlers/models.js +1 -1
- package/dist/src/cli/handlers/runtime-info.js +8 -1
- package/dist/src/cli/handlers/session.js +5 -4
- package/dist/src/cli/handlers/sessions.js +26 -9
- package/dist/src/cli/handlers/setup.js +9 -2
- package/dist/src/cli/handlers/steward.js +13 -2
- package/dist/src/cli/handlers/subcommands.js +11 -0
- package/dist/src/cli/handlers/team.js +68 -7
- package/dist/src/cli/handlers/use.js +158 -9
- package/dist/src/cli/scope-resolver.js +7 -0
- package/dist/src/config/aiwg-config.js +1 -0
- package/dist/src/dataset/fortemi-live-qualification.d.ts +53 -0
- package/dist/src/dataset/fortemi-live-qualification.js +297 -0
- package/dist/src/dataset/index.d.ts +1 -0
- package/dist/src/dataset/index.js +1 -0
- package/dist/src/mcp/cli.mjs +30 -1
- package/dist/src/mcp/omp-config.mjs +128 -0
- package/dist/src/mcp/registry.js +45 -5
- package/dist/src/mcp/registry.mjs +29 -6
- package/dist/src/models/model-capabilities.v1.json +31 -0
- package/dist/src/models/model-catalog.v1.json +29 -0
- package/dist/src/models/model-discovery.js +46 -5
- package/dist/src/models/provider-policy.js +5 -3
- package/dist/src/plugin/skill-command-translator.js +2 -0
- package/dist/src/providers/capability-matrix.yaml +87 -1
- package/dist/src/providers/omp-agent.mjs +40 -0
- package/dist/src/providers/omp-diagnostics.mjs +15 -0
- package/dist/src/providers/omp-paths.mjs +38 -0
- package/dist/src/providers/provider-definitions.js +83 -0
- package/dist/src/providers/provider-definitions.mjs +25 -1
- package/dist/src/providers/provider-inventory.js +2 -0
- package/dist/src/sessions/adapters/omp.js +203 -0
- package/dist/src/sessions/batch-import.js +7 -0
- package/dist/src/sessions/contracts.js +1 -1
- package/dist/src/sessions/importer.js +4 -3
- package/dist/src/sessions/index.js +1 -0
- package/dist/src/sessions/readers.js +4 -3
- package/dist/src/sessions/workspace-discovery.js +12 -2
- package/dist/src/skills/deployer.js +21 -1
- package/dist/src/smiths/agentsmith/generator.js +1 -0
- package/dist/src/smiths/context-pipeline/parallelism-section.js +2 -0
- package/dist/src/smiths/context-pipeline/provider-policy.js +2 -2
- package/dist/src/smiths/context-pipeline/workspace-context.js +2 -2
- package/dist/src/storage/backends/fortemi.js +142 -17
- package/dist/src/storage/fortemi-qualification-receipt.js +206 -0
- package/dist/src/storage/fortemi-qualification.js +67 -6
- package/dist/src/storage/index.js +1 -0
- package/package.json +2 -1
- package/schemas/dataset/fortemi-live-qualification-receipt.v1.schema.json +132 -0
- package/tools/agents/deploy-agents.mjs +6 -3
- package/tools/agents/providers/antigravity.mjs +147 -0
- package/tools/agents/providers/omp.d.mts +4 -0
- package/tools/agents/providers/omp.mjs +256 -0
- package/tools/providers/antigravity-transport.mjs +124 -0
package/dist/src/mcp/cli.mjs
CHANGED
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
} from './registry.mjs';
|
|
19
19
|
import { McpProfileRegistry } from './profiles.mjs';
|
|
20
20
|
import { getMcpInjectionDefinition } from '../providers/provider-definitions.mjs';
|
|
21
|
+
import { manageOmpMcp } from './omp-config.mjs';
|
|
21
22
|
|
|
22
23
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
23
24
|
|
|
@@ -38,6 +39,7 @@ Usage:
|
|
|
38
39
|
aiwg mcp update <name> [opts] Update a server definition
|
|
39
40
|
aiwg mcp list List registered MCP servers
|
|
40
41
|
aiwg mcp inject [opts] Inject servers into provider configs
|
|
42
|
+
aiwg mcp uninject [opts] Remove unchanged AIWG-owned OMP server entries
|
|
41
43
|
aiwg mcp profile <sub> Manage MCP profiles (named server subsets)
|
|
42
44
|
|
|
43
45
|
Server Options (for add/update):
|
|
@@ -52,7 +54,8 @@ Server Options (for add/update):
|
|
|
52
54
|
--description <text> Optional description
|
|
53
55
|
|
|
54
56
|
Inject Options:
|
|
55
|
-
--provider <name> Target provider (
|
|
57
|
+
--provider <name> Target provider (including antigravity / agy and omp / oh-my-pi)
|
|
58
|
+
--scope <scope> project (default) or user; provider user scope must be documented
|
|
56
59
|
--all Inject into all previously configured providers
|
|
57
60
|
--servers <a,b,...> Only inject specific servers (comma-separated names)
|
|
58
61
|
--dry-run Show what would change without writing
|
|
@@ -651,6 +654,8 @@ async function handleInject(args) {
|
|
|
651
654
|
const serversStr = parseFlag(args, '--servers');
|
|
652
655
|
const dryRun = args.includes('--dry-run');
|
|
653
656
|
const projectDir = parseFlag(args, '--project') || '.';
|
|
657
|
+
const scope = parseFlag(args, '--scope') || 'project';
|
|
658
|
+
if (!['project', 'user'].includes(scope)) throw new Error('Scope must be project or user');
|
|
654
659
|
const profileName = parseFlag(args, '--profile');
|
|
655
660
|
const ephemeral = args.includes('--ephemeral');
|
|
656
661
|
const outPath = parseFlag(args, '--out');
|
|
@@ -782,10 +787,12 @@ async function handleInject(args) {
|
|
|
782
787
|
servers: serverFilter,
|
|
783
788
|
projectDir,
|
|
784
789
|
dryRun,
|
|
790
|
+
scope,
|
|
785
791
|
});
|
|
786
792
|
|
|
787
793
|
if (result.error) {
|
|
788
794
|
console.error(` ${p}: ${result.error}`);
|
|
795
|
+
process.exitCode = 1;
|
|
789
796
|
continue;
|
|
790
797
|
}
|
|
791
798
|
|
|
@@ -1124,6 +1131,15 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
1124
1131
|
}
|
|
1125
1132
|
|
|
1126
1133
|
case 'install': {
|
|
1134
|
+
if (['omp', 'oh-my-pi'].includes(args[1])) {
|
|
1135
|
+
const scope = parseFlag(args, '--scope') || 'project';
|
|
1136
|
+
if (!['project', 'user'].includes(scope)) throw new Error('Scope must be project or user');
|
|
1137
|
+
const projectDir = parseFlag(args, '--project') || (args[2] && !args[2].startsWith('--') ? args[2] : '.');
|
|
1138
|
+
const configPath = getProviderConfigPath('omp', projectDir, { scope });
|
|
1139
|
+
const result = await manageOmpMcp(configPath, [{ name: 'aiwg', type: 'stdio', command: 'aiwg', args: ['mcp', 'serve'] }], { dryRun: args.includes('--dry-run') });
|
|
1140
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1141
|
+
break;
|
|
1142
|
+
}
|
|
1127
1143
|
// Parse install arguments (skip flags)
|
|
1128
1144
|
const installArgs = args.slice(1).filter(a => !a.startsWith('--'));
|
|
1129
1145
|
const target = installArgs[0] || 'claude';
|
|
@@ -1184,6 +1200,19 @@ export async function main(args = process.argv.slice(2)) {
|
|
|
1184
1200
|
await handleInject(subArgs);
|
|
1185
1201
|
break;
|
|
1186
1202
|
|
|
1203
|
+
case 'uninject': {
|
|
1204
|
+
const provider = parseFlag(subArgs, '--provider');
|
|
1205
|
+
if (!['omp', 'oh-my-pi'].includes(provider)) throw new Error('uninject currently supports --provider omp');
|
|
1206
|
+
const scope = parseFlag(subArgs, '--scope') || 'project';
|
|
1207
|
+
if (!['project', 'user'].includes(scope)) throw new Error('Scope must be project or user');
|
|
1208
|
+
const remove = (parseFlag(subArgs, '--servers') || '').split(',').map(s => s.trim()).filter(Boolean);
|
|
1209
|
+
if (!remove.length) throw new Error('uninject requires --servers name[,name]');
|
|
1210
|
+
const configPath = getProviderConfigPath(provider, parseFlag(subArgs, '--project') || '.', { scope });
|
|
1211
|
+
const result = await manageOmpMcp(configPath, [], { remove, dryRun: subArgs.includes('--dry-run') });
|
|
1212
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1213
|
+
break;
|
|
1214
|
+
}
|
|
1215
|
+
|
|
1187
1216
|
case 'profile':
|
|
1188
1217
|
await handleProfile(subArgs);
|
|
1189
1218
|
break;
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { readFile, writeFile, mkdir, rename, lstat, unlink, open } from 'node:fs/promises';
|
|
2
|
+
import { dirname, resolve } from 'node:path';
|
|
3
|
+
import { createHash, randomUUID } from 'node:crypto';
|
|
4
|
+
|
|
5
|
+
const hash = value => createHash('sha256').update(JSON.stringify(value)).digest('hex');
|
|
6
|
+
const record = value => value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
+
async function rejectSymlinkPath(file) {
|
|
8
|
+
let current = resolve(file);
|
|
9
|
+
for (;;) {
|
|
10
|
+
try {
|
|
11
|
+
if ((await lstat(current)).isSymbolicLink()) throw new Error('OMP MCP configuration path cannot traverse a symbolic link');
|
|
12
|
+
} catch (error) { if (error.code !== 'ENOENT') throw error; }
|
|
13
|
+
const parent = dirname(current);
|
|
14
|
+
if (parent === current) return;
|
|
15
|
+
current = parent;
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
async function readObject(file) {
|
|
19
|
+
await rejectSymlinkPath(file);
|
|
20
|
+
try {
|
|
21
|
+
if ((await lstat(file)).isSymbolicLink()) throw new Error('OMP MCP configuration cannot be a symbolic link');
|
|
22
|
+
const data = JSON.parse(await readFile(file, 'utf8'));
|
|
23
|
+
if (!record(data)) throw new Error('OMP MCP configuration must be an object');
|
|
24
|
+
return data;
|
|
25
|
+
} catch (error) {
|
|
26
|
+
if (error.code === 'ENOENT') return {};
|
|
27
|
+
if (error instanceof SyntaxError) throw new Error('OMP MCP configuration is invalid JSON; repair it before injection');
|
|
28
|
+
throw error;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
async function atomic(file, data) {
|
|
32
|
+
await mkdir(dirname(file), { recursive: true });
|
|
33
|
+
const temporary = `${file}.${randomUUID()}.tmp`;
|
|
34
|
+
try {
|
|
35
|
+
await writeFile(temporary, JSON.stringify(data, null, 2) + '\n', { flag: 'wx', mode: 0o600 });
|
|
36
|
+
await rename(temporary, file);
|
|
37
|
+
} finally { await unlink(temporary).catch(() => {}); }
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function ompServerConfig(server) {
|
|
41
|
+
const config = {};
|
|
42
|
+
for (const field of ['command', 'args', 'env', 'cwd', 'url', 'headers', 'enabled', 'timeout', 'requestIdFormat', 'auth', 'oauth', 'type']) {
|
|
43
|
+
if (server[field] !== undefined) config[field] = server[field];
|
|
44
|
+
}
|
|
45
|
+
if (!config.command && !config.url && config.enabled !== false) throw new Error(`OMP MCP server ${server.name} needs command or url`);
|
|
46
|
+
if (config.type !== undefined && !['stdio', 'http', 'sse'].includes(config.type)) throw new Error('Invalid OMP MCP transport');
|
|
47
|
+
if (config.command && config.url) throw new Error('OMP MCP server must choose command or url');
|
|
48
|
+
if (config.enabled !== false && (config.type === 'stdio' && !config.command || ['http', 'sse'].includes(config.type) && !config.url)) throw new Error('OMP MCP transport does not match endpoint');
|
|
49
|
+
for (const field of ['command', 'cwd', 'url']) {
|
|
50
|
+
if (config[field] !== undefined && typeof config[field] !== 'string') throw new Error(`Invalid OMP MCP ${field}`);
|
|
51
|
+
}
|
|
52
|
+
if (config.args !== undefined && (!Array.isArray(config.args) || config.args.some(x => typeof x !== 'string'))) throw new Error('Invalid OMP MCP args');
|
|
53
|
+
for (const field of ['env', 'headers']) {
|
|
54
|
+
if (config[field] !== undefined && (!record(config[field]) || Object.values(config[field]).some(x => typeof x !== 'string'))) throw new Error(`Invalid OMP MCP ${field}`);
|
|
55
|
+
}
|
|
56
|
+
if (config.requestIdFormat !== undefined && !['string', 'number'].includes(config.requestIdFormat)) throw new Error('Invalid OMP MCP requestIdFormat');
|
|
57
|
+
if (config.auth !== undefined && (!record(config.auth) || !['oauth', 'apikey'].includes(config.auth.type))) throw new Error('Invalid OMP MCP auth');
|
|
58
|
+
if (config.oauth !== undefined && !record(config.oauth)) throw new Error('Invalid OMP MCP oauth');
|
|
59
|
+
if (config.timeout !== undefined && (!Number.isFinite(config.timeout) || config.timeout < 0)) throw new Error('Invalid OMP MCP timeout');
|
|
60
|
+
if (config.enabled !== undefined && typeof config.enabled !== 'boolean') throw new Error('Invalid OMP MCP enabled flag');
|
|
61
|
+
for (const field of ['envPolicy', 'envLiteralKeys', 'headerPolicy']) {
|
|
62
|
+
if (server[field] !== undefined) throw new Error(`OMP native mcp.json does not enforce ${field}; this control requires the native SDK/plugin interface`);
|
|
63
|
+
}
|
|
64
|
+
for (const field of ['auth', 'oauth']) {
|
|
65
|
+
if (config[field]) for (const [key, value] of Object.entries(config[field])) {
|
|
66
|
+
if (key === 'callbackPort') { if (!Number.isInteger(value) || value < 0 || value > 65535) throw new Error('Invalid OMP MCP callbackPort'); }
|
|
67
|
+
else if (['type', 'credentialId', 'tokenUrl', 'clientId', 'clientSecret', 'resource', 'scope', 'redirectUri', 'callbackPath', 'prompt'].includes(key) && typeof value !== 'string') throw new Error(`Invalid OMP MCP ${field}.${key}`);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
if (server.headerEnv) {
|
|
71
|
+
config.headers = { ...config.headers };
|
|
72
|
+
for (const [header, variable] of Object.entries(server.headerEnv)) {
|
|
73
|
+
if (!/^[A-Za-z_][A-Za-z0-9_]*$/.test(variable)) throw new Error('Invalid MCP header environment reference');
|
|
74
|
+
config.headers[header] = '${' + variable + '}';
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return config;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** Hash-only receipt: never saves an extra copy of operator configuration. */
|
|
81
|
+
async function manageLockedOmpMcp(configPath, servers, { dryRun = false, remove = [] } = {}) {
|
|
82
|
+
const receiptPath = `${configPath}.aiwg-ownership.json`;
|
|
83
|
+
const existing = await readObject(configPath);
|
|
84
|
+
const receipt = await readObject(receiptPath);
|
|
85
|
+
if (receipt.servers !== undefined && (!record(receipt.servers) || receipt.schema !== 'aiwg.omp-mcp-ownership.v1')) throw new Error('Invalid OMP MCP ownership receipt');
|
|
86
|
+
if (existing.mcpServers !== undefined && !record(existing.mcpServers)) throw new Error('Invalid OMP mcpServers object');
|
|
87
|
+
const next = { ...(existing.mcpServers || {}) };
|
|
88
|
+
const owned = { ...(receipt.servers || {}) };
|
|
89
|
+
const result = { configPath, serversInjected: [], alreadyPresent: [], removed: [] };
|
|
90
|
+
// Validate all collisions before the first write.
|
|
91
|
+
for (const name of [...servers.map(s => s.name), ...remove]) {
|
|
92
|
+
if (typeof name !== 'string' || !name || ['__proto__', 'constructor', 'prototype'].includes(name)) throw new Error('Invalid OMP MCP server name');
|
|
93
|
+
if (Object.hasOwn(next, name) && owned[name] !== hash(next[name])) {
|
|
94
|
+
throw new Error(`OMP MCP server ${name} is operator-owned or modified; preserve it and choose a different name`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
for (const server of servers) {
|
|
98
|
+
if (!server.name || ['__proto__', 'constructor', 'prototype'].includes(server.name)) throw new Error('Invalid OMP MCP server name');
|
|
99
|
+
if (Object.hasOwn(next, server.name)) result.alreadyPresent.push(server.name);
|
|
100
|
+
next[server.name] = ompServerConfig(server);
|
|
101
|
+
owned[server.name] = hash(next[server.name]);
|
|
102
|
+
result.serversInjected.push(server.name);
|
|
103
|
+
}
|
|
104
|
+
for (const name of remove) {
|
|
105
|
+
if (owned[name]) { delete next[name]; delete owned[name]; result.removed.push(name); }
|
|
106
|
+
}
|
|
107
|
+
if (!dryRun) {
|
|
108
|
+
if (hash(await readObject(configPath)) !== hash(existing) || hash(await readObject(receiptPath)) !== hash(receipt)) throw new Error('OMP MCP configuration changed during injection; retry after reviewing the operator edit');
|
|
109
|
+
// If interrupted between writes, a retry fails closed on the hash mismatch.
|
|
110
|
+
await atomic(configPath, { ...existing, mcpServers: next });
|
|
111
|
+
await atomic(receiptPath, { schema: 'aiwg.omp-mcp-ownership.v1', servers: owned });
|
|
112
|
+
}
|
|
113
|
+
return result;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
/** Serialize AIWG writers; operator edits detected before committing a replacement. */
|
|
117
|
+
export async function manageOmpMcp(configPath, servers, options = {}) {
|
|
118
|
+
if (options.dryRun) return manageLockedOmpMcp(configPath, servers, options);
|
|
119
|
+
await rejectSymlinkPath(configPath);
|
|
120
|
+
const lockPath = `${configPath}.aiwg-lock`;
|
|
121
|
+
await rejectSymlinkPath(lockPath);
|
|
122
|
+
await mkdir(dirname(configPath), { recursive: true });
|
|
123
|
+
let lock;
|
|
124
|
+
try { lock = await open(lockPath, 'wx', 0o600); }
|
|
125
|
+
catch (error) { if (error.code === 'EEXIST') throw new Error('OMP MCP injection already locked; wait for the active writer or review a stale lock before retrying'); throw error; }
|
|
126
|
+
try { return await manageLockedOmpMcp(configPath, servers, options); }
|
|
127
|
+
finally { await lock.close(); await unlink(lockPath); }
|
|
128
|
+
}
|
package/dist/src/mcp/registry.js
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { manageOmpMcp } from './omp-config.mjs';
|
|
2
|
+
import { resolveOmpPaths } from '../providers/omp-paths.mjs';
|
|
1
3
|
/**
|
|
2
4
|
* MCP Server Registry
|
|
3
5
|
*
|
|
@@ -156,6 +158,12 @@ export class McpServerRegistry {
|
|
|
156
158
|
function buildServerConfig(server, provider) {
|
|
157
159
|
const adapter = getProviderDefinition(provider)?.adapters.mcpInjection;
|
|
158
160
|
switch (adapter) {
|
|
161
|
+
case 'antigravity': {
|
|
162
|
+
if (server.type === 'stdio') {
|
|
163
|
+
return { command: server.command, args: server.args || [], ...(server.env ? { env: server.env } : {}) };
|
|
164
|
+
}
|
|
165
|
+
return { serverUrl: server.url, ...(server.headers ? { headers: server.headers } : {}) };
|
|
166
|
+
}
|
|
159
167
|
case 'claude-code': {
|
|
160
168
|
if (server.type === 'stdio') {
|
|
161
169
|
return {
|
|
@@ -258,9 +266,21 @@ function buildServerToml(server) {
|
|
|
258
266
|
/**
|
|
259
267
|
* Get the config file path for a provider.
|
|
260
268
|
*/
|
|
261
|
-
export function getProviderConfigPath(provider, projectDir = '.') {
|
|
269
|
+
export function getProviderConfigPath(provider, projectDir = '.', options = {}) {
|
|
270
|
+
if ((provider === 'antigravity' || provider === 'agy') && options.scope === 'user') {
|
|
271
|
+
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
272
|
+
return resolve(homeDir, '.gemini/config/mcp_config.json');
|
|
273
|
+
}
|
|
274
|
+
if ((provider === 'omp' || provider === 'oh-my-pi') && options.scope !== undefined && !['user', 'project'].includes(options.scope))
|
|
275
|
+
throw new Error('OMP MCP scope must be user or project');
|
|
276
|
+
if ((provider === 'omp' || provider === 'oh-my-pi') && options.scope === 'user')
|
|
277
|
+
return resolve(resolveOmpPaths().agentDir, 'mcp.json');
|
|
262
278
|
const homeDir = process.env.HOME || process.env.USERPROFILE || '';
|
|
263
279
|
const pathMap = {
|
|
280
|
+
antigravity: resolve(projectDir, '.agents/mcp_config.json'),
|
|
281
|
+
agy: resolve(projectDir, '.agents/mcp_config.json'),
|
|
282
|
+
omp: resolve(projectDir, '.omp/mcp.json'),
|
|
283
|
+
'oh-my-pi': resolve(projectDir, '.omp/mcp.json'),
|
|
264
284
|
'claude-code': resolve(projectDir, '.claude/settings.local.json'),
|
|
265
285
|
claude: resolve(projectDir, '.claude/settings.local.json'),
|
|
266
286
|
cursor: resolve(projectDir, '.cursor/mcp.json'),
|
|
@@ -281,7 +301,7 @@ export function getProviderConfigPath(provider, projectDir = '.') {
|
|
|
281
301
|
*/
|
|
282
302
|
export async function injectServers(registry, provider, options = {}) {
|
|
283
303
|
const { servers: serverFilter, projectDir = '.', dryRun = false } = options;
|
|
284
|
-
const configPath = getProviderConfigPath(provider, projectDir);
|
|
304
|
+
const configPath = getProviderConfigPath(provider, projectDir, options);
|
|
285
305
|
const result = {
|
|
286
306
|
provider,
|
|
287
307
|
configPath,
|
|
@@ -297,6 +317,18 @@ export async function injectServers(registry, provider, options = {}) {
|
|
|
297
317
|
result.error = 'No servers to inject. Use "aiwg mcp add" first.';
|
|
298
318
|
return result;
|
|
299
319
|
}
|
|
320
|
+
if (provider === 'omp' || provider === 'oh-my-pi') {
|
|
321
|
+
try {
|
|
322
|
+
const managed = await manageOmpMcp(configPath, allServers, { dryRun });
|
|
323
|
+
if (!dryRun)
|
|
324
|
+
for (const server of allServers)
|
|
325
|
+
await registry.recordInjection(server.name, 'omp');
|
|
326
|
+
return { ...result, ...managed };
|
|
327
|
+
}
|
|
328
|
+
catch (error) {
|
|
329
|
+
return { ...result, error: error instanceof Error ? error.message : String(error) };
|
|
330
|
+
}
|
|
331
|
+
}
|
|
300
332
|
// Handle TOML-based providers (Codex/OpenAI) separately
|
|
301
333
|
if (provider === 'codex' || provider === 'openai') {
|
|
302
334
|
return injectToml(registry, allServers, configPath, provider, dryRun, result);
|
|
@@ -311,8 +343,10 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
311
343
|
const content = await readFile(configPath, 'utf-8');
|
|
312
344
|
existing = JSON.parse(content);
|
|
313
345
|
}
|
|
314
|
-
catch {
|
|
315
|
-
|
|
346
|
+
catch (error) {
|
|
347
|
+
if ((provider === 'antigravity' || provider === 'agy') && error?.code !== 'ENOENT') {
|
|
348
|
+
throw new Error(`Refusing to overwrite malformed MCP config ${configPath}: ${error.message}`);
|
|
349
|
+
}
|
|
316
350
|
}
|
|
317
351
|
// Determine the MCP servers key for this provider
|
|
318
352
|
const mcpKey = provider === 'opencode' ? 'mcp' : 'mcpServers';
|
|
@@ -323,6 +357,8 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
323
357
|
if (existingServers[server.name]) {
|
|
324
358
|
// Update existing entry in place
|
|
325
359
|
result.alreadyPresent.push(server.name);
|
|
360
|
+
if (provider === 'antigravity' || provider === 'agy')
|
|
361
|
+
continue;
|
|
326
362
|
}
|
|
327
363
|
newServers[server.name] = buildServerConfig(server, provider);
|
|
328
364
|
result.serversInjected.push(server.name);
|
|
@@ -334,7 +370,9 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
334
370
|
await writeFile(configPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
335
371
|
// Record injection in registry
|
|
336
372
|
for (const server of servers) {
|
|
337
|
-
|
|
373
|
+
if ((provider === 'antigravity' || provider === 'agy') && !result.serversInjected.includes(server.name))
|
|
374
|
+
continue;
|
|
375
|
+
await registry.recordInjection(server.name, provider === 'agy' ? 'antigravity' : provider);
|
|
338
376
|
}
|
|
339
377
|
}
|
|
340
378
|
return result;
|
|
@@ -378,6 +416,8 @@ function escapeRegex(str) {
|
|
|
378
416
|
}
|
|
379
417
|
/** All supported provider names for injection */
|
|
380
418
|
export const SUPPORTED_PROVIDERS = [
|
|
419
|
+
'antigravity',
|
|
420
|
+
'omp',
|
|
381
421
|
'claude-code',
|
|
382
422
|
'cursor',
|
|
383
423
|
'factory',
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { manageOmpMcp } from './omp-config.mjs';
|
|
2
|
+
import { resolveOmpPaths } from '../providers/omp-paths.mjs';
|
|
1
3
|
/**
|
|
2
4
|
* MCP Server Registry (Runtime ESM)
|
|
3
5
|
*
|
|
@@ -206,6 +208,12 @@ function buildServerConfig(server, provider) {
|
|
|
206
208
|
const mcpDefinition = getMcpInjectionDefinition(provider);
|
|
207
209
|
|
|
208
210
|
switch (mcpDefinition?.serverConfigFormat) {
|
|
211
|
+
case 'antigravity': {
|
|
212
|
+
if (server.type === 'stdio') {
|
|
213
|
+
return { command: server.command, args: server.args || [], ...(server.env ? { env: server.env } : {}) };
|
|
214
|
+
}
|
|
215
|
+
return { serverUrl: server.url, ...(server.headers ? { headers: server.headers } : {}) };
|
|
216
|
+
}
|
|
209
217
|
case 'standard': {
|
|
210
218
|
if (server.type === 'stdio') {
|
|
211
219
|
return {
|
|
@@ -281,15 +289,16 @@ function buildServerToml(server) {
|
|
|
281
289
|
return lines.join('\n');
|
|
282
290
|
}
|
|
283
291
|
|
|
284
|
-
export function getProviderConfigPath(provider, projectDir = '.') {
|
|
285
|
-
|
|
292
|
+
export function getProviderConfigPath(provider, projectDir = '.', options = {}) {
|
|
293
|
+
if (normalizeRuntimeProviderId(provider) === 'omp' && options.scope !== undefined && !['user', 'project'].includes(options.scope)) throw new Error('OMP MCP scope must be user or project');
|
|
294
|
+
return resolveMcpConfigPath(provider, projectDir, options);
|
|
286
295
|
}
|
|
287
296
|
|
|
288
297
|
export async function injectServers(registry, provider, options = {}) {
|
|
289
298
|
const { servers: serverFilter, projectDir = '.', dryRun = false } = options;
|
|
290
299
|
const normalizedProvider = normalizeRuntimeProviderId(provider);
|
|
291
300
|
const mcpDefinition = getMcpInjectionDefinition(provider);
|
|
292
|
-
const configPath = getProviderConfigPath(provider, projectDir);
|
|
301
|
+
const configPath = getProviderConfigPath(provider, projectDir, options);
|
|
293
302
|
const result = {
|
|
294
303
|
provider,
|
|
295
304
|
configPath,
|
|
@@ -312,6 +321,16 @@ export async function injectServers(registry, provider, options = {}) {
|
|
|
312
321
|
return result;
|
|
313
322
|
}
|
|
314
323
|
|
|
324
|
+
if (normalizedProvider === 'omp') {
|
|
325
|
+
try {
|
|
326
|
+
const managed = await manageOmpMcp(configPath, allServers, { dryRun });
|
|
327
|
+
if (!dryRun) for (const server of allServers) await registry.recordInjection(server.name, 'omp');
|
|
328
|
+
return { ...result, ...managed };
|
|
329
|
+
} catch (error) {
|
|
330
|
+
return { ...result, error: error instanceof Error ? error.message : String(error) };
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
315
334
|
if (mcpDefinition?.configFormat === 'toml') {
|
|
316
335
|
return injectToml(registry, allServers, configPath, provider, dryRun, result);
|
|
317
336
|
}
|
|
@@ -324,8 +343,10 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
324
343
|
try {
|
|
325
344
|
const content = await readFile(configPath, 'utf-8');
|
|
326
345
|
existing = JSON.parse(content);
|
|
327
|
-
} catch {
|
|
328
|
-
|
|
346
|
+
} catch (error) {
|
|
347
|
+
if (normalizeRuntimeProviderId(provider) === 'antigravity' && error?.code !== 'ENOENT') {
|
|
348
|
+
throw new Error(`Refusing to overwrite malformed MCP config ${configPath}: ${error.message}`);
|
|
349
|
+
}
|
|
329
350
|
}
|
|
330
351
|
|
|
331
352
|
const mcpKey = getMcpInjectionDefinition(provider)?.serversKey || 'mcpServers';
|
|
@@ -335,6 +356,7 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
335
356
|
for (const server of servers) {
|
|
336
357
|
if (existingServers[server.name]) {
|
|
337
358
|
result.alreadyPresent.push(server.name);
|
|
359
|
+
if (normalizeRuntimeProviderId(provider) === 'antigravity') continue;
|
|
338
360
|
}
|
|
339
361
|
newServers[server.name] = buildServerConfig(server, provider);
|
|
340
362
|
result.serversInjected.push(server.name);
|
|
@@ -347,7 +369,8 @@ async function injectJson(registry, servers, configPath, provider, dryRun, resul
|
|
|
347
369
|
await writeFile(configPath, JSON.stringify(merged, null, 2) + '\n', 'utf-8');
|
|
348
370
|
|
|
349
371
|
for (const server of servers) {
|
|
350
|
-
|
|
372
|
+
if (normalizeRuntimeProviderId(provider) === 'antigravity' && !result.serversInjected.includes(server.name)) continue;
|
|
373
|
+
await registry.recordInjection(server.name, normalizeRuntimeProviderId(provider) || provider);
|
|
351
374
|
}
|
|
352
375
|
}
|
|
353
376
|
|
|
@@ -3,6 +3,17 @@
|
|
|
3
3
|
"version": "1.0.0",
|
|
4
4
|
"verifiedAt": "2026-07-20",
|
|
5
5
|
"providers": {
|
|
6
|
+
"antigravity": {
|
|
7
|
+
"agent": "native", "skill": "native", "globalChild": "inherited",
|
|
8
|
+
"identifierSyntax": "model identifier accepted by Antigravity CLI 1.1.26 --model",
|
|
9
|
+
"effortValues": ["low", "medium", "high"],
|
|
10
|
+
"inheritance": "Omitted model and effort inherit the invoking Antigravity session",
|
|
11
|
+
"invalidPinFallback": "Provider validation/error; never assume fallback",
|
|
12
|
+
"configTarget": "agy launch arguments; custom-agent model tiers are not projected from generic AIWG model ids",
|
|
13
|
+
"artifactFormat": "YAML frontmatter plus Markdown; runtime --model and --effort flags",
|
|
14
|
+
"verification": "Pinned offline contract; authenticated model selection was not executed",
|
|
15
|
+
"sourceUrl": "https://antigravity.google/docs/cli/subagents/", "verifiedAt": "2026-09-04"
|
|
16
|
+
},
|
|
6
17
|
"claude": {
|
|
7
18
|
"agent": "native", "skill": "native", "globalChild": "inherited",
|
|
8
19
|
"identifierSyntax": "Claude alias or accepted Anthropic model ID",
|
|
@@ -76,6 +87,26 @@
|
|
|
76
87
|
"verification": "Inspect active profile and run metadata",
|
|
77
88
|
"sourceUrl": "https://docs.warp.dev/agent-platform/capabilities/agent-profiles-permissions", "verifiedAt": "2026-07-20"
|
|
78
89
|
},
|
|
90
|
+
"omp": {
|
|
91
|
+
"agent": "native",
|
|
92
|
+
"skill": "inherited",
|
|
93
|
+
"globalChild": "native",
|
|
94
|
+
"identifierSyntax": "provider/model identifier accepted by OMP --model",
|
|
95
|
+
"effortValues": [
|
|
96
|
+
"minimal",
|
|
97
|
+
"low",
|
|
98
|
+
"medium",
|
|
99
|
+
"high",
|
|
100
|
+
"xhigh"
|
|
101
|
+
],
|
|
102
|
+
"inheritance": "Omitted model and thinking level inherit the invoking Pi session",
|
|
103
|
+
"invalidPinFallback": "Pi resolves against its configured catalog and exits on invalid explicit selection",
|
|
104
|
+
"configTarget": "OMP native agent frontmatter and runtime launch arguments",
|
|
105
|
+
"artifactFormat": "model and thinkingLevel frontmatter; --model and --thinking runtime flags",
|
|
106
|
+
"verification": "Pinned OMP 18.1.10 source and live OpenRouter smoke; individual role defaults remain operator configured",
|
|
107
|
+
"sourceUrl": "https://github.com/can1357/oh-my-pi/tree/5964a0f7649275bcde818f20073193fd032451f2/packages/coding-agent",
|
|
108
|
+
"verifiedAt": "2026-09-04"
|
|
109
|
+
},
|
|
79
110
|
"pi": {
|
|
80
111
|
"agent": "native", "skill": "inherited", "globalChild": "native",
|
|
81
112
|
"identifierSyntax": "provider/model identifier accepted by Pi --model",
|
|
@@ -4,6 +4,14 @@
|
|
|
4
4
|
"refreshedAt": "2026-07-20",
|
|
5
5
|
"staleAfterDays": 90,
|
|
6
6
|
"providers": {
|
|
7
|
+
"antigravity": {
|
|
8
|
+
"roles": {
|
|
9
|
+
"reasoning": { "id": "configured/reasoning", "status": "unverified", "observed": false },
|
|
10
|
+
"coding": { "id": "configured/coding", "status": "unverified", "observed": false },
|
|
11
|
+
"efficiency": { "id": "configured/efficiency", "status": "unverified", "observed": false }
|
|
12
|
+
},
|
|
13
|
+
"sourceUrl": "https://antigravity.google/docs/cli/overview/", "verifiedAt": "2026-09-04"
|
|
14
|
+
},
|
|
7
15
|
"claude": {
|
|
8
16
|
"roles": {
|
|
9
17
|
"reasoning": { "id": "claude-opus-4-7", "status": "active", "observed": false },
|
|
@@ -52,6 +60,27 @@
|
|
|
52
60
|
},
|
|
53
61
|
"sourceUrl": "https://opencode.ai/docs/models", "verifiedAt": "2026-07-20"
|
|
54
62
|
},
|
|
63
|
+
"omp": {
|
|
64
|
+
"roles": {
|
|
65
|
+
"reasoning": {
|
|
66
|
+
"id": "configured/reasoning",
|
|
67
|
+
"status": "unverified",
|
|
68
|
+
"observed": false
|
|
69
|
+
},
|
|
70
|
+
"coding": {
|
|
71
|
+
"id": "configured/coding",
|
|
72
|
+
"status": "unverified",
|
|
73
|
+
"observed": false
|
|
74
|
+
},
|
|
75
|
+
"efficiency": {
|
|
76
|
+
"id": "configured/efficiency",
|
|
77
|
+
"status": "unverified",
|
|
78
|
+
"observed": false
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
"sourceUrl": "https://github.com/can1357/oh-my-pi/tree/5964a0f7649275bcde818f20073193fd032451f2/packages/coding-agent",
|
|
82
|
+
"verifiedAt": "2026-09-04"
|
|
83
|
+
},
|
|
55
84
|
"pi": {
|
|
56
85
|
"roles": {
|
|
57
86
|
"reasoning": { "id": "configured/reasoning", "status": "unverified", "observed": false },
|
|
@@ -67,6 +67,9 @@ export const PROVIDER_DISCOVERY_DECISIONS = {
|
|
|
67
67
|
reason: 'OpenHuman profiles accept semantic model hints but expose no standardized local model-list command.',
|
|
68
68
|
documentation: 'https://github.com/roctinam/openhuman',
|
|
69
69
|
},
|
|
70
|
+
omp: { provider: 'omp', status: 'native', interface: 'omp models --json --no-extensions',
|
|
71
|
+
reason: 'OMP JSON catalog reports credential-available LLM models; ambient extensions are disabled by default.',
|
|
72
|
+
documentation: 'https://github.com/can1357/oh-my-pi/blob/5964a0f7649275bcde818f20073193fd032451f2/packages/coding-agent/src/commands/models.ts' },
|
|
70
73
|
pi: {
|
|
71
74
|
provider: 'pi',
|
|
72
75
|
status: 'native',
|
|
@@ -103,7 +106,7 @@ export function classifyDiscoveryError(message) {
|
|
|
103
106
|
export const runModelDiscoveryCommand = (command, args, options = {}) => new Promise(resolveCommand => {
|
|
104
107
|
const child = spawn(command, args, {
|
|
105
108
|
cwd: options.cwd,
|
|
106
|
-
env: process.env,
|
|
109
|
+
env: options.env ?? process.env,
|
|
107
110
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
108
111
|
});
|
|
109
112
|
let stdout = '';
|
|
@@ -116,8 +119,13 @@ export const runModelDiscoveryCommand = (command, args, options = {}) => new Pro
|
|
|
116
119
|
clearTimeout(timer);
|
|
117
120
|
resolveCommand({ stdout, stderr, exitCode });
|
|
118
121
|
};
|
|
119
|
-
child.stdout.on('data', chunk => { stdout += String(chunk);
|
|
120
|
-
|
|
122
|
+
child.stdout.on('data', chunk => { stdout += String(chunk); if (Buffer.byteLength(stdout) > 8 * 1024 * 1024) {
|
|
123
|
+
stdout = '';
|
|
124
|
+
stderr = 'Model catalog exceeded 8 MiB limit';
|
|
125
|
+
child.kill('SIGKILL');
|
|
126
|
+
finish(1);
|
|
127
|
+
} });
|
|
128
|
+
child.stderr.on('data', chunk => { stderr = (stderr + String(chunk)).slice(-4096); });
|
|
121
129
|
child.on('error', error => {
|
|
122
130
|
stderr = `${stderr}${stderr ? '\n' : ''}${error.message}`;
|
|
123
131
|
finish(127);
|
|
@@ -425,7 +433,7 @@ export async function resolveDynamicModelCatalog(options) {
|
|
|
425
433
|
const homeDir = options.homeDir ?? homedir();
|
|
426
434
|
const cacheFile = options.cacheFile ?? join(homeDir, '.cache/aiwg/model-catalog.v1.json');
|
|
427
435
|
const staticFile = join(options.aiwgRoot, 'agentic/code/providers/model-catalog.v1.json');
|
|
428
|
-
const signature = inventorySignature(options.inventory);
|
|
436
|
+
const signature = inventorySignature(options.inventory) + JSON.stringify({ omp: options.omp, profile: process.env.OMP_PROFILE ?? process.env.PI_PROFILE, config: process.env.PI_CONFIG_DIR, data: process.env.XDG_DATA_HOME, cache: process.env.XDG_CACHE_HOME, agent: process.env.PI_CODING_AGENT_DIR });
|
|
429
437
|
const staticCatalog = await readCatalog(staticFile);
|
|
430
438
|
if (!staticCatalog)
|
|
431
439
|
throw new Error(`Invalid or missing static model catalog: ${staticFile}`);
|
|
@@ -487,6 +495,7 @@ export async function resolveDynamicModelCatalog(options) {
|
|
|
487
495
|
opencode: () => discoverOpenCodeModels(),
|
|
488
496
|
openclaw: () => discoverOpenClawModels(),
|
|
489
497
|
pi: () => discoverPiModels(),
|
|
498
|
+
omp: () => discoverOmpModels(process.env.AIWG_OMP_BIN || 'omp', runModelDiscoveryCommand, options.omp),
|
|
490
499
|
};
|
|
491
500
|
const providerDiscovery = {};
|
|
492
501
|
for (const provider of available) {
|
|
@@ -494,7 +503,7 @@ export async function resolveDynamicModelCatalog(options) {
|
|
|
494
503
|
if (discoverer) {
|
|
495
504
|
try {
|
|
496
505
|
providerDiscovery[provider] = await discoverer();
|
|
497
|
-
const selected = selectRoleModels(providerDiscovery[provider].models);
|
|
506
|
+
const selected = provider === 'omp' ? {} : selectRoleModels(providerDiscovery[provider].models);
|
|
498
507
|
const providerCatalog = catalog.providers[provider];
|
|
499
508
|
if (providerCatalog) {
|
|
500
509
|
for (const role of ['reasoning', 'coding', 'efficiency']) {
|
|
@@ -550,4 +559,36 @@ export async function resolveDynamicModelCatalog(options) {
|
|
|
550
559
|
await atomicWrite(cacheFile, `${JSON.stringify(resolved, null, 2)}\n`);
|
|
551
560
|
return resolved;
|
|
552
561
|
}
|
|
562
|
+
/** Explicit OMP discovery; no ambient extension execution unless requested. */
|
|
563
|
+
export async function discoverOmpModels(command = 'omp', runner = runModelDiscoveryCommand, options = {}) {
|
|
564
|
+
const base = { provider: 'omp', source: 'native', observedAt: new Date().toISOString(), accountScope: 'local-runtime', models: [] };
|
|
565
|
+
const args = [...(options.profile ? ['--profile', options.profile] : []), 'models', '--json'];
|
|
566
|
+
if (!options.extensions)
|
|
567
|
+
args.push('--no-extensions');
|
|
568
|
+
for (const config of options.config ?? [])
|
|
569
|
+
args.push('--config', config);
|
|
570
|
+
try {
|
|
571
|
+
const result = await runner(command, args, { cwd: options.cwd ?? tmpdir(), timeoutMs: 15000 });
|
|
572
|
+
base.runtimeVersion = await runtimeVersion(command, runner);
|
|
573
|
+
if (result.exitCode !== 0)
|
|
574
|
+
return { ...base, errorKind: result.exitCode === 124 ? 'timeout' : /unknown|unsupported|not found/i.test(result.stderr) ? 'unsupported' : classifyDiscoveryError(result.stderr), error: 'OMP model discovery failed; check CLI version, selected profile/config, and credential availability.' };
|
|
575
|
+
const payload = JSON.parse(result.stdout);
|
|
576
|
+
if (!Array.isArray(payload.models) || payload.models.some((m) => !m || typeof m.id !== 'string' || !m.id || typeof m.provider !== 'string' || !m.provider))
|
|
577
|
+
throw new Error('shape');
|
|
578
|
+
base.models = payload.models.map((m) => ({ id: `${m.provider}/${m.id}`, llmProvider: m.provider, displayName: m.name, reasoningEfforts: Array.isArray(m.thinking) ? m.thinking : undefined }));
|
|
579
|
+
return base;
|
|
580
|
+
}
|
|
581
|
+
catch {
|
|
582
|
+
return { ...base, errorKind: 'invalid-output', error: 'OMP returned invalid model catalog JSON or discovery could not run.' };
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
/** Never guess an unrelated model when a requested mapping is unavailable. */
|
|
586
|
+
export function resolveOmpRoleModel(catalog, role, mappings, explicit) {
|
|
587
|
+
if (explicit)
|
|
588
|
+
return explicit;
|
|
589
|
+
const id = mappings[role];
|
|
590
|
+
if (!id || !catalog.models.some(model => model.id === id))
|
|
591
|
+
throw new Error(`OMP ${role} model unavailable; configure a model from omp models --json or supply an explicit model.`);
|
|
592
|
+
return id;
|
|
593
|
+
}
|
|
553
594
|
//# sourceMappingURL=model-discovery.js.map
|
|
@@ -26,8 +26,8 @@ function requireModelResource(filename) {
|
|
|
26
26
|
const capabilityData = requireModelResource('model-capabilities.v1.json');
|
|
27
27
|
const catalogData = requireModelResource('model-catalog.v1.json');
|
|
28
28
|
const ProviderSchema = z.enum([
|
|
29
|
-
'claude', 'codex', 'copilot', 'cursor', 'factory', 'hermes',
|
|
30
|
-
'opencode', 'openclaw', 'openhuman', 'pi', 'warp', 'windsurf',
|
|
29
|
+
'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'factory', 'hermes',
|
|
30
|
+
'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
|
|
31
31
|
]);
|
|
32
32
|
const OutcomeSchema = z.enum([
|
|
33
33
|
'native', 'compiled', 'inherited', 'global-only', 'informational', 'unsupported',
|
|
@@ -107,7 +107,7 @@ export function loadProviderModelCapabilities() {
|
|
|
107
107
|
const expected = new Set(ProviderSchema.options);
|
|
108
108
|
const actual = new Set(Object.keys(registryCache.providers));
|
|
109
109
|
if (actual.size !== expected.size || [...expected].some(id => !actual.has(id))) {
|
|
110
|
-
throw new Error('Provider model capability registry must cover all
|
|
110
|
+
throw new Error('Provider model capability registry must cover all registered providers');
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
return registryCache;
|
|
@@ -153,12 +153,14 @@ function catalogRole(policy) {
|
|
|
153
153
|
}
|
|
154
154
|
function fieldNames(provider) {
|
|
155
155
|
switch (provider) {
|
|
156
|
+
case 'antigravity': return { model: 'model', effort: 'effort' };
|
|
156
157
|
case 'codex': return { model: 'model', effort: 'model_reasoning_effort' };
|
|
157
158
|
case 'factory': return { model: 'model', effort: 'reasoningEffort' };
|
|
158
159
|
case 'claude': return { model: 'model', effort: 'effort' };
|
|
159
160
|
case 'copilot':
|
|
160
161
|
case 'cursor':
|
|
161
162
|
case 'opencode': return { model: 'model' };
|
|
163
|
+
case 'omp': return { model: 'model', effort: 'thinkingLevel' };
|
|
162
164
|
case 'pi': return { model: 'model', effort: 'thinking' };
|
|
163
165
|
case 'openhuman': return { model: 'model_hint' };
|
|
164
166
|
case 'openclaw': return { model: 'subagents.model' };
|
|
@@ -34,11 +34,13 @@ const PROVIDERS_NEEDING_COMMANDS = new Set([
|
|
|
34
34
|
* Providers where skills are deployed natively (no command generation needed).
|
|
35
35
|
*/
|
|
36
36
|
const SKILLS_ONLY_PROVIDERS = new Set([
|
|
37
|
+
'antigravity',
|
|
37
38
|
'claude',
|
|
38
39
|
'cursor',
|
|
39
40
|
'hermes',
|
|
40
41
|
'openhuman',
|
|
41
42
|
'pi',
|
|
43
|
+
'omp',
|
|
42
44
|
]);
|
|
43
45
|
/**
|
|
44
46
|
* Check if a provider needs command files generated from skills.
|