@aiwg/cli 2026.9.2 → 2026.9.3
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/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 +121 -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/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.
|
|
@@ -361,7 +361,7 @@ providers:
|
|
|
361
361
|
|
|
362
362
|
hermes:
|
|
363
363
|
display_name: Hermes
|
|
364
|
-
status:
|
|
364
|
+
status: stable
|
|
365
365
|
daemon_tier: unsupported
|
|
366
366
|
daemon_pty_adapter: false
|
|
367
367
|
artifact_paths:
|
|
@@ -470,6 +470,51 @@ providers:
|
|
|
470
470
|
deploy_target: mixed
|
|
471
471
|
aggregated_output: true
|
|
472
472
|
|
|
473
|
+
antigravity:
|
|
474
|
+
display_name: Google Antigravity CLI
|
|
475
|
+
aliases:
|
|
476
|
+
- agy
|
|
477
|
+
status: experimental
|
|
478
|
+
executable: agy
|
|
479
|
+
qualified_version: 1.1.26
|
|
480
|
+
qualification_evidence: agentic/code/providers/antigravity/provider-contract.v1.json
|
|
481
|
+
daemon_tier: unsupported
|
|
482
|
+
daemon_pty_adapter: false
|
|
483
|
+
artifact_paths:
|
|
484
|
+
agents: .agents/agents/
|
|
485
|
+
commands: "(not deployed; no qualified native command surface)"
|
|
486
|
+
skills: .agents/skills/
|
|
487
|
+
rules: AGENTS.md
|
|
488
|
+
behaviors: "(not supported)"
|
|
489
|
+
mcp_project: .agents/mcp_config.json
|
|
490
|
+
mcp_user: "~/.gemini/config/mcp_config.json"
|
|
491
|
+
native_features:
|
|
492
|
+
cron: false
|
|
493
|
+
agent_teams: false
|
|
494
|
+
tasks: false
|
|
495
|
+
mcp: true
|
|
496
|
+
behaviors: false
|
|
497
|
+
mission_control: false
|
|
498
|
+
daemon: false
|
|
499
|
+
emulation:
|
|
500
|
+
cron: external-trigger
|
|
501
|
+
agent_teams: aiwg-mc
|
|
502
|
+
tasks: aiwg-mc
|
|
503
|
+
mcp: native
|
|
504
|
+
behaviors: null
|
|
505
|
+
mission_control: aiwg-mc
|
|
506
|
+
daemon: null
|
|
507
|
+
hook_wiring:
|
|
508
|
+
at_link_support: false
|
|
509
|
+
fallback: full-inject
|
|
510
|
+
context_file: AGENTS.md
|
|
511
|
+
interaction:
|
|
512
|
+
structured_questions: none
|
|
513
|
+
fallback: markdown
|
|
514
|
+
notes: No stable structured-question tool contract was qualified for CLI 1.1.26.
|
|
515
|
+
deploy_target: project
|
|
516
|
+
aggregated_output: false
|
|
517
|
+
|
|
473
518
|
pi:
|
|
474
519
|
display_name: Pi Coding Agent
|
|
475
520
|
aliases:
|
|
@@ -511,6 +556,47 @@ providers:
|
|
|
511
556
|
deploy_target: project
|
|
512
557
|
aggregated_output: false
|
|
513
558
|
|
|
559
|
+
omp:
|
|
560
|
+
display_name: Oh My Pi
|
|
561
|
+
aliases:
|
|
562
|
+
- oh-my-pi
|
|
563
|
+
status: experimental
|
|
564
|
+
daemon_tier: unsupported
|
|
565
|
+
daemon_pty_adapter: false
|
|
566
|
+
artifact_paths:
|
|
567
|
+
agents: .omp/agents/
|
|
568
|
+
commands: .omp/prompts/
|
|
569
|
+
skills: .agents/skills/
|
|
570
|
+
skills_cross_agent: .agents/skills/
|
|
571
|
+
rules: .omp/rules/
|
|
572
|
+
behaviors: .omp/extensions/
|
|
573
|
+
native_features:
|
|
574
|
+
cron: false
|
|
575
|
+
agent_teams: true
|
|
576
|
+
tasks: true
|
|
577
|
+
mcp: true
|
|
578
|
+
behaviors: true
|
|
579
|
+
mission_control: false
|
|
580
|
+
daemon: false
|
|
581
|
+
emulation:
|
|
582
|
+
cron: external-trigger
|
|
583
|
+
agent_teams: null
|
|
584
|
+
tasks: null
|
|
585
|
+
mcp: null
|
|
586
|
+
behaviors: null
|
|
587
|
+
mission_control: aiwg-mc
|
|
588
|
+
daemon: null
|
|
589
|
+
hook_wiring:
|
|
590
|
+
at_link_support: true
|
|
591
|
+
fallback: full-inject
|
|
592
|
+
context_file: .omp/AGENTS.md
|
|
593
|
+
interaction:
|
|
594
|
+
structured_questions: none
|
|
595
|
+
fallback: markdown
|
|
596
|
+
notes: OMP integration uses Markdown questions; native UI questions require an interactive runtime.
|
|
597
|
+
deploy_target: project
|
|
598
|
+
aggregated_output: false
|
|
599
|
+
|
|
514
600
|
# Feature definitions — documents what each feature key means and
|
|
515
601
|
# what emulation strategies are available when native support is absent.
|
|
516
602
|
features:
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import YAML from 'yaml';
|
|
3
|
+
function parse(content) {
|
|
4
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
5
|
+
return match ? { metadata: YAML.parse(match[1]) || {}, body: match[2] } : { metadata: {}, body: content };
|
|
6
|
+
}
|
|
7
|
+
const render = (metadata, body) => `---\n${YAML.stringify(metadata)}---\n\n${body.trim()}\n`;
|
|
8
|
+
function diagnostic(opts, message) { opts.diagnostics?.push(message); if (!opts.quiet) console.warn(`OMP: ${message}`); }
|
|
9
|
+
export function mapModel(model, config = {}) {
|
|
10
|
+
if (!model || model === 'inherit') return undefined;
|
|
11
|
+
const mapped = config.omp?.[model]?.model || config.omp?.[model];
|
|
12
|
+
if (typeof mapped === 'string') return mapped;
|
|
13
|
+
if (['opus', 'sonnet', 'haiku', 'reasoning', 'coding', 'efficiency', 'heavy', 'medium', 'light'].includes(model)) return undefined;
|
|
14
|
+
return model;
|
|
15
|
+
}
|
|
16
|
+
const toolMap = { Read: 'read', Write: 'write', Edit: 'edit', MultiEdit: 'edit', Bash: 'bash', Grep: 'grep', Glob: 'glob', WebSearch: 'web_search', Task: 'task', TodoWrite: 'todo' };
|
|
17
|
+
const nativeTools = new Set(['read','security_scan','bash','edit','ast_grep','ast_edit','ask','debug','eval','github','glob','grep','lsp','checkpoint','rewind','task','hub','todo','web_search','write','memory_edit','retain','recall','reflect','learn','manage_skill','think','yield','goal']);
|
|
18
|
+
const array = value => Array.isArray(value) ? value : typeof value === 'string' ? value.split(',').map(s => s.trim()).filter(Boolean) : [];
|
|
19
|
+
export function transformAgent(src, content, opts = {}) {
|
|
20
|
+
const { metadata: m, body } = parse(content);
|
|
21
|
+
const agentName = m.name ?? path.basename(src, '.md');
|
|
22
|
+
if (typeof agentName !== 'string' || !agentName.trim()) throw new Error('OMP agent name must be a nonempty string');
|
|
23
|
+
const out = { name: agentName.trim(), description: String(m.description || `AIWG ${path.basename(src, '.md')} agent`) };
|
|
24
|
+
if (['main','sub'].includes(out.name.toLowerCase())) throw new Error(`OMP reserves agent name ${out.name}`);
|
|
25
|
+
const tools = array(m.tools).flatMap(tool => {
|
|
26
|
+
const mapped = toolMap[tool] || (nativeTools.has(tool) ? tool : undefined);
|
|
27
|
+
if (!mapped) diagnostic(opts, `${out.name}: unsupported tool ${tool}; omitted (degraded)`);
|
|
28
|
+
return mapped ? [mapped] : [];
|
|
29
|
+
});
|
|
30
|
+
// OMP treats empty spawns as undefined; remove task unless explicit delegation is configured.
|
|
31
|
+
out.spawns = m.spawns === '*' ? '*' : array(m.spawns);
|
|
32
|
+
out.tools = [...new Set(tools)].filter(tool => tool !== 'task' || out.spawns === '*' || out.spawns.length > 0);
|
|
33
|
+
if (m.model) {
|
|
34
|
+
const models = array(m.model).flatMap(model => { const mapped = mapModel(model, opts.modelsConfig || opts.modelConfig || {}); if (!mapped && model !== 'inherit') diagnostic(opts, `${out.name}: unmapped model role ${model}; inherits session model (degraded)`); return mapped ? [mapped] : []; });
|
|
35
|
+
if (models.length) out.model = models.length === 1 ? models[0] : models;
|
|
36
|
+
}
|
|
37
|
+
for (const key of ['thinkingLevel', 'blocking', 'output', 'autoloadSkills', 'readSummarize', 'prewalk', 'advisor']) if (m[key] !== undefined) out[key] = m[key];
|
|
38
|
+
if (!out.thinkingLevel && m.thinking) out.thinkingLevel = m.thinking;
|
|
39
|
+
return render(out, body);
|
|
40
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { resolveOmpPaths } from './omp-paths.mjs';
|
|
4
|
+
const execute = promisify(execFile);
|
|
5
|
+
/** Reports only parsed version and non-secret paths; never reflects runtime output. */
|
|
6
|
+
export async function diagnoseOmpRuntime({ cwd = process.cwd(), env = process.env, binary = env.AIWG_OMP_BIN || 'omp', runner = execute } = {}) {
|
|
7
|
+
const paths = resolveOmpPaths({ cwd, env });
|
|
8
|
+
const result = { executable: binary, available: false, version: null, paths, reason: 'OMP executable unavailable; install the supported binary or set AIWG_OMP_BIN.' };
|
|
9
|
+
try {
|
|
10
|
+
const output = await runner(binary, ['--version'], { cwd, env: { PATH: env.PATH || '', PI_CODING_AGENT_DIR: paths.agentDir, NO_COLOR: '1', ...(env.SystemRoot ? { SystemRoot: env.SystemRoot } : {}) }, timeout: 5000, maxBuffer: 16384, encoding: 'utf8' });
|
|
11
|
+
const version = output.stdout.trim().match(/^(?:omp\/)?(\d+\.\d+\.\d+(?:[-+][a-zA-Z0-9.-]+)?)$/)?.[1];
|
|
12
|
+
if (!version) { result.reason = 'OMP returned an unrecognized version; verify the selected executable.'; return result; }
|
|
13
|
+
return { ...result, available: true, version, reason: null };
|
|
14
|
+
} catch { return result; }
|
|
15
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
/** OMP 18.1.10 profile contract; independent of original Pi configuration. */
|
|
6
|
+
export function normalizeOmpProfile(value) {
|
|
7
|
+
const name = value?.trim();
|
|
8
|
+
if (!name || name === 'default') return undefined;
|
|
9
|
+
if (!/^[a-z0-9][a-z0-9._-]{0,63}$/.test(name) || name.endsWith('.')
|
|
10
|
+
|| /^(?:con|prn|aux|nul|com[0-9]|lpt[0-9])(?:\..*)?$/i.test(name)) {
|
|
11
|
+
throw new Error('Invalid OMP profile: use 1–64 lowercase letters, digits, dots, hyphens or underscores; reserved device names are forbidden');
|
|
12
|
+
}
|
|
13
|
+
return name;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Resolve without reading credentials or importing the OMP runtime. */
|
|
17
|
+
export function resolveOmpPaths({ env = process.env, home = homedir(), cwd = process.cwd(),
|
|
18
|
+
platform = process.platform, exists = existsSync } = {}) {
|
|
19
|
+
const profile = normalizeOmpProfile(env.OMP_PROFILE !== undefined ? env.OMP_PROFILE : env.PI_PROFILE);
|
|
20
|
+
const directory = env.PI_CONFIG_DIR || '.omp';
|
|
21
|
+
const base = path.join(home, directory);
|
|
22
|
+
const configRoot = profile ? path.join(base, 'profiles', profile) : base;
|
|
23
|
+
const defaultAgent = path.join(configRoot, 'agent');
|
|
24
|
+
const agentDir = !profile && env.PI_CODING_AGENT_DIR
|
|
25
|
+
? path.resolve(cwd, env.PI_CODING_AGENT_DIR) : defaultAgent;
|
|
26
|
+
const xdg = (variable) => {
|
|
27
|
+
if (!['linux', 'darwin'].includes(platform) || agentDir !== defaultAgent || !env[variable]) return undefined;
|
|
28
|
+
const root = path.join(env[variable], 'omp');
|
|
29
|
+
const candidate = profile ? path.join(root, 'profiles', profile) : root;
|
|
30
|
+
return exists(candidate) ? candidate : undefined;
|
|
31
|
+
};
|
|
32
|
+
const dataDir = xdg('XDG_DATA_HOME') || agentDir;
|
|
33
|
+
const stateDir = xdg('XDG_STATE_HOME') || agentDir;
|
|
34
|
+
const cacheDir = xdg('XDG_CACHE_HOME') || agentDir;
|
|
35
|
+
const resourceDirs = { agents: path.join(defaultAgent, 'agents'), skills: path.join(agentDir, 'skills'), commands: path.join(agentDir, 'prompts'), rules: path.join(agentDir, 'rules'), behaviors: path.join(agentDir, 'extensions') };
|
|
36
|
+
return { profile, configRoot, agentDir, resourceDirs, projectDir: path.join(cwd, '.omp'),
|
|
37
|
+
dataDir, stateDir, cacheDir, sessionsDir: path.join(dataDir, 'sessions') };
|
|
38
|
+
}
|