@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.
Files changed (67) hide show
  1. package/agentic/code/providers/antigravity/provider-contract.v1.json +121 -0
  2. package/agentic/code/providers/capability-matrix.yaml +87 -1
  3. package/agentic/code/providers/model-capabilities.v1.json +31 -0
  4. package/agentic/code/providers/model-catalog.v1.json +29 -0
  5. package/agentic/code/providers/omp/README.md +58 -0
  6. package/agentic/code/providers/omp/aiwg-bridge.ts +52 -0
  7. package/dist/src/agents/agent-deployer.js +18 -0
  8. package/dist/src/agents/agent-packager.js +25 -0
  9. package/dist/src/artifacts/backends/sqlite-backend.js +18 -10
  10. package/dist/src/artifacts/query-engine.js +30 -0
  11. package/dist/src/cli/agent-spawn.js +13 -2
  12. package/dist/src/cli/handlers/help.js +3 -1
  13. package/dist/src/cli/handlers/init.js +2 -0
  14. package/dist/src/cli/handlers/models.js +1 -1
  15. package/dist/src/cli/handlers/runtime-info.js +8 -1
  16. package/dist/src/cli/handlers/session.js +5 -4
  17. package/dist/src/cli/handlers/sessions.js +26 -9
  18. package/dist/src/cli/handlers/setup.js +9 -2
  19. package/dist/src/cli/handlers/steward.js +13 -2
  20. package/dist/src/cli/handlers/subcommands.js +11 -0
  21. package/dist/src/cli/handlers/team.js +68 -7
  22. package/dist/src/cli/handlers/use.js +121 -9
  23. package/dist/src/cli/scope-resolver.js +7 -0
  24. package/dist/src/config/aiwg-config.js +1 -0
  25. package/dist/src/dataset/fortemi-live-qualification.d.ts +53 -0
  26. package/dist/src/dataset/fortemi-live-qualification.js +297 -0
  27. package/dist/src/dataset/index.d.ts +1 -0
  28. package/dist/src/dataset/index.js +1 -0
  29. package/dist/src/mcp/cli.mjs +30 -1
  30. package/dist/src/mcp/omp-config.mjs +128 -0
  31. package/dist/src/mcp/registry.js +45 -5
  32. package/dist/src/mcp/registry.mjs +29 -6
  33. package/dist/src/models/model-capabilities.v1.json +31 -0
  34. package/dist/src/models/model-catalog.v1.json +29 -0
  35. package/dist/src/models/model-discovery.js +46 -5
  36. package/dist/src/models/provider-policy.js +5 -3
  37. package/dist/src/plugin/skill-command-translator.js +2 -0
  38. package/dist/src/providers/capability-matrix.yaml +87 -1
  39. package/dist/src/providers/omp-agent.mjs +40 -0
  40. package/dist/src/providers/omp-diagnostics.mjs +15 -0
  41. package/dist/src/providers/omp-paths.mjs +38 -0
  42. package/dist/src/providers/provider-definitions.js +83 -0
  43. package/dist/src/providers/provider-definitions.mjs +25 -1
  44. package/dist/src/providers/provider-inventory.js +2 -0
  45. package/dist/src/sessions/adapters/omp.js +203 -0
  46. package/dist/src/sessions/batch-import.js +7 -0
  47. package/dist/src/sessions/contracts.js +1 -1
  48. package/dist/src/sessions/importer.js +4 -3
  49. package/dist/src/sessions/index.js +1 -0
  50. package/dist/src/sessions/readers.js +4 -3
  51. package/dist/src/sessions/workspace-discovery.js +12 -2
  52. package/dist/src/skills/deployer.js +21 -1
  53. package/dist/src/smiths/agentsmith/generator.js +1 -0
  54. package/dist/src/smiths/context-pipeline/parallelism-section.js +2 -0
  55. package/dist/src/smiths/context-pipeline/provider-policy.js +2 -2
  56. package/dist/src/smiths/context-pipeline/workspace-context.js +2 -2
  57. package/dist/src/storage/backends/fortemi.js +142 -17
  58. package/dist/src/storage/fortemi-qualification-receipt.js +206 -0
  59. package/dist/src/storage/fortemi-qualification.js +67 -6
  60. package/dist/src/storage/index.js +1 -0
  61. package/package.json +2 -1
  62. package/schemas/dataset/fortemi-live-qualification-receipt.v1.schema.json +132 -0
  63. package/tools/agents/deploy-agents.mjs +6 -3
  64. package/tools/agents/providers/antigravity.mjs +147 -0
  65. package/tools/agents/providers/omp.d.mts +4 -0
  66. package/tools/agents/providers/omp.mjs +256 -0
  67. package/tools/providers/antigravity-transport.mjs +124 -0
@@ -0,0 +1,132 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://aiwg.io/schemas/dataset/fortemi-live-qualification-receipt.v1.schema.json",
4
+ "title": "AIWG Fortemi Dataset Live Qualification Receipt v1",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "contract",
9
+ "outcome",
10
+ "diagnostic",
11
+ "receiptDigest",
12
+ "bindings",
13
+ "observed",
14
+ "namespace",
15
+ "operations",
16
+ "mutation",
17
+ "resources",
18
+ "startedAt",
19
+ "endedAt"
20
+ ],
21
+ "properties": {
22
+ "contract": { "const": "aiwg.fortemi-dataset-live-qualification/v1" },
23
+ "outcome": { "enum": ["pending", "supported"] },
24
+ "diagnostic": {
25
+ "enum": [
26
+ "CONFORMANCE_FORTEMI_DATASET_CONTRACT_UNAVAILABLE",
27
+ "CONFORMANCE_FORTEMI_DATASET_PREFLIGHT_SUPPORTED"
28
+ ]
29
+ },
30
+ "receiptDigest": { "$ref": "#/$defs/digest" },
31
+ "bindings": {
32
+ "type": "object",
33
+ "additionalProperties": false,
34
+ "required": ["aiwgCommit", "endpointFingerprint", "toolSchemaDigest"],
35
+ "properties": {
36
+ "aiwgCommit": { "type": "string", "pattern": "^[0-9a-f]{40}$" },
37
+ "endpointFingerprint": { "$ref": "#/$defs/digest" },
38
+ "toolSchemaDigest": { "$ref": "#/$defs/digest" }
39
+ }
40
+ },
41
+ "observed": {
42
+ "type": "object",
43
+ "additionalProperties": false,
44
+ "required": ["serverName", "serverVersion"],
45
+ "properties": {
46
+ "serverName": { "$ref": "#/$defs/safe" },
47
+ "serverVersion": { "$ref": "#/$defs/safe" }
48
+ }
49
+ },
50
+ "namespace": {
51
+ "type": "string",
52
+ "pattern": "^aiwg-dataset-qualification-[0-9a-f-]{36}$"
53
+ },
54
+ "operations": {
55
+ "type": "array",
56
+ "minItems": 2,
57
+ "maxItems": 2,
58
+ "items": {
59
+ "type": "object",
60
+ "additionalProperties": false,
61
+ "required": ["tool", "compatible", "code"],
62
+ "properties": {
63
+ "tool": { "enum": ["dataset_capabilities", "dataset_execute"] },
64
+ "compatible": { "type": "boolean" },
65
+ "code": {
66
+ "enum": [
67
+ "FORTEMI_DATASET_TOOL_SCHEMA_COMPATIBLE",
68
+ "FORTEMI_DATASET_TOOL_SCHEMA_DRIFT",
69
+ "FORTEMI_DATASET_TOOL_MISSING"
70
+ ]
71
+ }
72
+ }
73
+ }
74
+ },
75
+ "mutation": {
76
+ "type": "object",
77
+ "additionalProperties": false,
78
+ "required": ["authorized", "attempted"],
79
+ "properties": {
80
+ "authorized": { "const": false },
81
+ "attempted": { "const": false }
82
+ }
83
+ },
84
+ "resources": {
85
+ "type": "object",
86
+ "additionalProperties": false,
87
+ "required": [
88
+ "maxDurationMs",
89
+ "durationMs",
90
+ "maxToolCount",
91
+ "observedToolCount",
92
+ "maxSchemaBytes",
93
+ "observedSchemaBytes",
94
+ "networkAttempts",
95
+ "toolCalls"
96
+ ],
97
+ "properties": {
98
+ "maxDurationMs": {
99
+ "type": "integer",
100
+ "minimum": 250,
101
+ "maximum": 30000
102
+ },
103
+ "durationMs": { "type": "integer", "minimum": 0 },
104
+ "maxToolCount": { "const": 256 },
105
+ "observedToolCount": {
106
+ "type": "integer",
107
+ "minimum": 0,
108
+ "maximum": 256
109
+ },
110
+ "maxSchemaBytes": { "const": 1048576 },
111
+ "observedSchemaBytes": {
112
+ "type": "integer",
113
+ "minimum": 0,
114
+ "maximum": 1048576
115
+ },
116
+ "networkAttempts": { "const": 1 },
117
+ "toolCalls": { "const": 0 }
118
+ }
119
+ },
120
+ "startedAt": { "$ref": "#/$defs/time" },
121
+ "endedAt": { "$ref": "#/$defs/time" }
122
+ },
123
+ "$defs": {
124
+ "digest": { "type": "string", "pattern": "^sha256:[0-9a-f]{64}$" },
125
+ "safe": {
126
+ "type": "string",
127
+ "minLength": 1,
128
+ "pattern": "^[A-Za-z0-9._:/-]+$"
129
+ },
130
+ "time": { "type": "string", "format": "date-time", "pattern": "Z$" }
131
+ }
132
+ }
@@ -20,7 +20,7 @@
20
20
  * --rules-only Deploy only rules (skip agents)
21
21
  * --dry-run Show what would be deployed without writing
22
22
  * --force Overwrite existing files
23
- * --provider <name> Target provider: claude (default), openai, codex, cursor, opencode, copilot, factory, pi, warp, devin, hermes, or openclaw
23
+ * --provider <name> Target provider: antigravity (agy), claude (default), openai, codex, cursor, opencode, copilot, factory, pi, omp, warp, devin, hermes, or openclaw
24
24
  * --model <name> Override model for all tiers (blanket)
25
25
  * --reasoning-model <name> Override model for reasoning tasks
26
26
  * --coding-model <name> Override model for coding tasks
@@ -53,6 +53,7 @@
53
53
  * windsurf - Deprecated alias for devin
54
54
  * openclaw - OpenClaw - ~/.openclaw/agents/, ~/.openclaw/commands/, ~/.openclaw/skills/, ~/.openclaw/rules/, ~/.openclaw/behaviors/
55
55
  * pi - Pi Coding Agent - .agents/skills/, .pi/skills/, .pi/prompts/, AGENTS.md
56
+ * omp - Oh My Pi - .omp/agents/, .omp/prompts/, .agents/skills/, .omp/AGENTS.md
56
57
  *
57
58
  * Defaults:
58
59
  * --source resolves relative to this script's repo root (../..)
@@ -104,15 +105,17 @@ function getDeployVersion(srcRoot) {
104
105
  // ============================================================================
105
106
 
106
107
  const PROVIDER_ALIASES = {
108
+ agy: 'antigravity',
107
109
  'openai': 'codex',
108
110
  'devin': 'windsurf',
109
111
  'devin-desktop': 'windsurf',
110
112
  'devin-local': 'windsurf',
111
113
  'cascade': 'windsurf',
112
114
  'pi-coding-agent': 'pi',
115
+ 'oh-my-pi': 'omp',
113
116
  };
114
117
 
115
- const AVAILABLE_PROVIDERS = ['claude', 'factory', 'codex', 'opencode', 'copilot', 'cursor', 'pi', 'warp', 'windsurf', 'hermes', 'openclaw', 'openhuman'];
118
+ const AVAILABLE_PROVIDERS = ['antigravity', 'claude', 'factory', 'codex', 'opencode', 'copilot', 'cursor', 'pi', 'omp', 'warp', 'windsurf', 'hermes', 'openclaw', 'openhuman'];
116
119
 
117
120
  const UNSUPPORTED_PROVIDER_HINTS = {
118
121
  'devin-cli': [
@@ -154,7 +157,7 @@ const MIRRORED_KERNEL_COMMAND_SKILLS = new Set([
154
157
  ]);
155
158
 
156
159
  function providerUsesSkillsNatively(providerName) {
157
- return ['claude', 'cursor', 'hermes', 'openhuman', 'pi'].includes(providerName);
160
+ return ['antigravity', 'claude', 'cursor', 'hermes', 'openhuman', 'pi', 'omp'].includes(providerName);
158
161
  }
159
162
 
160
163
  function shouldMirrorStandardCommandSkill(skillName) {
@@ -0,0 +1,147 @@
1
+ /** Google Antigravity CLI project resource deployment, qualified against 1.1.26. */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import {
5
+ collectFrameworkArtifacts,
6
+ createAgentsMdFromTemplate,
7
+ deployFiles,
8
+ deploySkillsWithKernelRouting,
9
+ ensureDir,
10
+ getAddonAgentFiles,
11
+ getAddonSkillDirs,
12
+ listMdFiles,
13
+ listSkillDirs,
14
+ normalizeDeploymentMode,
15
+ resolveAiwgRoot,
16
+ } from './base.mjs';
17
+
18
+ export const name = 'antigravity';
19
+ export const aliases = ['agy'];
20
+ export const paths = { agents: '.agents/agents', commands: '', skills: '.agents/skills', rules: '' };
21
+ export const kernelSkillsPath = '.agents/skills';
22
+ export const support = { agents: 'degraded', commands: 'unsupported', skills: 'native', rules: 'context' };
23
+ export const capabilities = {
24
+ skills: true,
25
+ rules: false,
26
+ yamlFormat: true,
27
+ aggregatedOutput: false,
28
+ homeDirectoryDeploy: false,
29
+ parallelCommandAndSkillSurfaces: false,
30
+ };
31
+
32
+ export const mapModel = model => model;
33
+
34
+ const ANTIGRAVITY_TOOL_MAP = new Map([
35
+ ['Read', 'view_file'],
36
+ ['Write', 'write_to_file'],
37
+ ['Edit', 'replace_file_content'],
38
+ ['Grep', 'grep_search'],
39
+ ['Bash', 'run_command'],
40
+ ]);
41
+
42
+ function mapTools(value) {
43
+ if (!value) return [];
44
+ return value
45
+ .replace(/^\[|\]$/g, '')
46
+ .split(',')
47
+ .map(tool => ANTIGRAVITY_TOOL_MAP.get(tool.trim()))
48
+ .filter(Boolean);
49
+ }
50
+
51
+ export function transformAgent(_source, content) {
52
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
53
+ if (!match) return content;
54
+ const frontmatter = match[1];
55
+ const body = match[2].trim();
56
+ const name = frontmatter.match(/^name:\s*(.+)$/m)?.[1]?.trim();
57
+ const description = frontmatter.match(/^description:\s*(.+)$/m)?.[1]?.trim();
58
+ const tools = mapTools(frontmatter.match(/^tools:\s*(.+)$/m)?.[1]?.trim());
59
+ return [
60
+ '---',
61
+ ...(name ? [`name: ${name}`] : []),
62
+ ...(description ? [`description: ${description}`] : []),
63
+ ...(tools.length ? ['tools:', ...tools.map(tool => ` - ${tool}`)] : []),
64
+ '---',
65
+ '',
66
+ body,
67
+ '',
68
+ ].join('\n');
69
+ }
70
+
71
+ export function deployAgents(files, target, opts = {}) {
72
+ const destination = path.join(target, paths.agents);
73
+ ensureDir(destination, opts.dryRun);
74
+ return deployFiles(files, destination, { ...opts, provider: name }, transformAgent);
75
+ }
76
+
77
+ export function deploySkills(dirs, target, opts = {}) {
78
+ return deploySkillsWithKernelRouting(
79
+ dirs,
80
+ path.join(target, '.agents/.aiwg/skills'),
81
+ path.join(target, kernelSkillsPath),
82
+ { ...opts, provider: name, copyStandardSkills: opts.copyStandardSkills === true },
83
+ );
84
+ }
85
+
86
+ export function deployCommands() { return 0; }
87
+ export function deployRules() { return 0; }
88
+
89
+ export function createAgentsMd(target, srcRoot, dryRun) {
90
+ const root = resolveAiwgRoot(srcRoot) || srcRoot;
91
+ createAgentsMdFromTemplate(target, root, 'antigravity/AGENTS.md.aiwg-template', dryRun);
92
+ }
93
+
94
+ export async function postDeploy(target, opts) {
95
+ if (opts.global || opts.user || opts.scope === 'user') {
96
+ throw new Error('Antigravity global skill deployment is disabled: official 1.1.26 path documentation conflicts');
97
+ }
98
+ if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) {
99
+ createAgentsMd(target, opts.srcRoot, opts.dryRun);
100
+ }
101
+ if (!opts.quiet) {
102
+ console.log('Antigravity resources are project scoped. Restart agy after resource changes; authenticate with the provider separately.');
103
+ }
104
+ }
105
+
106
+ export function getFileExtension() { return '.md'; }
107
+
108
+ export async function deploy(opts) {
109
+ if (opts.global || opts.user || opts.scope === 'user') {
110
+ throw new Error('Antigravity global skill deployment is disabled: official 1.1.26 path documentation conflicts');
111
+ }
112
+ const mode = normalizeDeploymentMode(opts.mode);
113
+ const agents = [];
114
+ const skills = [];
115
+ const directSource = ['agents', 'skills'].some(type => fs.existsSync(path.join(opts.srcRoot, type)));
116
+ if (directSource) {
117
+ agents.push(...listMdFiles(path.join(opts.srcRoot, 'agents')));
118
+ if (opts.deploySkills || opts.skillsOnly) skills.push(...listSkillDirs(path.join(opts.srcRoot, 'skills')));
119
+ } else if (['general', 'sdlc', 'both', 'all'].includes(mode)) {
120
+ agents.push(...getAddonAgentFiles(opts.srcRoot));
121
+ if (opts.deploySkills || opts.skillsOnly) skills.push(...getAddonSkillDirs(opts.srcRoot));
122
+ }
123
+ const framework = directSource ? { agents: [], skills: [] } : collectFrameworkArtifacts(opts.srcRoot, mode, {
124
+ includeAgents: true,
125
+ includeCommands: false,
126
+ includeSkills: opts.deploySkills || opts.skillsOnly,
127
+ includeRules: false,
128
+ });
129
+ agents.push(...framework.agents);
130
+ skills.push(...framework.skills);
131
+ let count = 0;
132
+ if (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly) {
133
+ count += deployAgents(agents, opts.target, opts).filter(action => action.type === 'deploy').length;
134
+ }
135
+ if ((opts.deploySkills || opts.skillsOnly) && !opts.commandsOnly && !opts.rulesOnly) {
136
+ const result = deploySkills(skills, opts.target, opts);
137
+ count += result.kernel + result.standardCopied;
138
+ }
139
+ await postDeploy(opts.target, opts);
140
+ return count;
141
+ }
142
+
143
+ export default {
144
+ name, aliases, paths, kernelSkillsPath, support, capabilities, mapModel,
145
+ transformAgent, deployAgents, deploySkills, deployCommands, deployRules,
146
+ createAgentsMd, postDeploy, getFileExtension, deploy,
147
+ };
@@ -0,0 +1,4 @@
1
+ export interface OmpUninstallOptions { dryRun?: boolean; scope?: 'user' | 'project'; home?: string; env?: NodeJS.ProcessEnv; quiet?: boolean }
2
+ export function uninstall(target: string, opts?: OmpUninstallOptions): number;
3
+
4
+ export function deploySkillSupportAsset(source: string, destination: string, opts?: { dryRun?: boolean; quiet?: boolean }): number;
@@ -0,0 +1,256 @@
1
+ /** OMP native deployment, verified against 18.1.10 (5964a0f). */
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { createHash } from 'node:crypto';
5
+ import YAML from 'yaml';
6
+ import { resolveOmpPaths } from '../../../src/providers/omp-paths.mjs';
7
+ import { collectFrameworkArtifacts, getAddonFiles, isKernelSkill, listMdFiles, listSkillDirs, normalizeDeploymentMode, resolveAiwgRoot } from './base.mjs';
8
+ export const name = 'omp';
9
+ export const aliases = ['oh-my-pi'];
10
+ export const paths = { agents: '.omp/agents', commands: '.omp/prompts', skills: '.agents/skills', rules: '.omp/rules' };
11
+ export const kernelSkillsPath = '.agents/skills';
12
+ export const support = { agents: 'native', commands: 'native', skills: 'native', rules: 'native' };
13
+ export const capabilities = { skills: true, rules: true, yamlFormat: true, aggregatedOutput: false, homeDirectoryDeploy: false, parallelCommandAndSkillSurfaces: true };
14
+ const hash = value => createHash('sha256').update(value).digest('hex');
15
+ function parse(content) {
16
+ const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
17
+ return match ? { metadata: YAML.parse(match[1]) || {}, body: match[2] } : { metadata: {}, body: content };
18
+ }
19
+ const render = (metadata, body) => `---\n${YAML.stringify(metadata)}---\n\n${body.trim()}\n`;
20
+ function diagnostic(opts, message) { opts.diagnostics?.push(message); if (!opts.quiet) console.warn(`OMP: ${message}`); }
21
+ import { transformAgent, mapModel } from '../../../src/providers/omp-agent.mjs';
22
+ export { transformAgent, mapModel };
23
+ const array = value => Array.isArray(value) ? value : typeof value === 'string' ? value.split(',').map(s => s.trim()).filter(Boolean) : [];
24
+ export function transformCommand(src, content, opts = {}) {
25
+ const { metadata: m, body } = parse(content);
26
+ const metadata = { description: String(m.description || `AIWG ${path.basename(src, '.md')} prompt`) };
27
+ if (m['argument-hint']) metadata['argument-hint'] = m['argument-hint'];
28
+ for (const key of Object.keys(m)) if (!['description','argument-hint','name','platforms','allowed-tools','model'].includes(key)) diagnostic(opts, `prompt ${path.basename(src)}: metadata ${key} omitted`);
29
+ const normalized = body.replace(/\$\{(ARGUMENTS|@|\d+)\}/g, (_, name) => `$${name}`);
30
+ return render(metadata, normalized + (m['argument-hint'] && !/\$(?:ARGUMENTS|@|\d+)/.test(normalized) ? '\n\nInvocation arguments: $@' : ''));
31
+ }
32
+ export function transformRule(src, content) {
33
+ const { metadata: m, body } = parse(content);
34
+ const out = { description: String(m.description || path.basename(src, '.md')) };
35
+ for (const key of ['enabled','globs','alwaysApply','condition','astCondition','scope','agents','interruptMode']) if (m[key] !== undefined) out[key] = m[key];
36
+ if (out.globs === undefined && m.paths) out.globs = array(m.paths);
37
+ return render(out, body);
38
+ }
39
+ function roots(target, opts = {}) {
40
+ const resolved = resolveOmpPaths({ cwd: target, env: opts.env, home: opts.home });
41
+ const user = opts.global || opts.user || opts.scope === 'user';
42
+ return { native: user ? resolved.agentDir : path.join(target, '.omp'), agents: user ? resolved.resourceDirs.agents : path.join(target, '.omp/agents'), kernel: user ? path.join(resolved.agentDir, 'skills') : path.join(target, kernelSkillsPath) };
43
+ }
44
+ function assertNoSymlink(destination) {
45
+ let current = path.resolve(destination);
46
+ while (true) {
47
+ try { if (fs.lstatSync(current).isSymbolicLink()) throw new Error(`OMP preserves symlink destination: ${current}`); }
48
+ catch (error) { if (error.code !== 'ENOENT') throw error; }
49
+ const parent = path.dirname(current); if (parent === current) break; current = parent;
50
+ }
51
+ }
52
+ function readReceipt(dir) {
53
+ const filename = path.join(dir, '.aiwg-manifest.json');
54
+ assertNoSymlink(filename);
55
+ if (!fs.existsSync(filename)) return { managed: {} };
56
+ let parsed;
57
+ try { parsed = JSON.parse(fs.readFileSync(filename, 'utf8')); }
58
+ catch { throw new Error(`OMP preserves malformed receipt: ${filename}`); }
59
+ if (!parsed || !parsed.managed || typeof parsed.managed !== 'object' || Array.isArray(parsed.managed)
60
+ || Object.values(parsed.managed).some(entry => !entry || typeof entry !== 'object' || Array.isArray(entry))) {
61
+ throw new Error(`OMP preserves malformed receipt: ${filename}`);
62
+ }
63
+ return parsed;
64
+ }
65
+ /** Reconcile only the named standard skill's unchanged OMP-owned files. */
66
+ function removeStandardSkillCopy(destination, opts) {
67
+ if (!fs.existsSync(destination)) return 0;
68
+ assertNoSymlink(destination);
69
+ const plans = [];
70
+ function plan(dir) {
71
+ const receipt = readReceipt(dir);
72
+ const files = [];
73
+ for (const [filename, entry] of Object.entries(receipt.managed)) {
74
+ if (path.basename(filename) !== filename || entry.provider !== 'omp' || entry.transformation !== 'omp-skill') continue;
75
+ const file = path.join(dir, filename);
76
+ if (!fs.existsSync(file) || fs.lstatSync(file).isSymbolicLink() || !fs.lstatSync(file).isFile()) continue;
77
+ if (entry.hash === `sha256:${hash(fs.readFileSync(file))}`) files.push(filename);
78
+ else diagnostic(opts, `preserved modified standard skill file ${file}`);
79
+ }
80
+ plans.push({ dir, receipt, files });
81
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) if (entry.isDirectory()) plan(path.join(dir, entry.name));
82
+ }
83
+ plan(destination);
84
+ const count = plans.reduce((sum, item) => sum + item.files.length, 0);
85
+ if (opts.dryRun) return count;
86
+ for (const { dir, receipt, files } of plans.reverse()) {
87
+ for (const filename of files) { fs.unlinkSync(path.join(dir, filename)); delete receipt.managed[filename]; }
88
+ if (files.length) {
89
+ const receiptPath = path.join(dir, '.aiwg-manifest.json');
90
+ if (Object.keys(receipt.managed).length) fs.writeFileSync(receiptPath, `${JSON.stringify(receipt, null, 2)}\n`);
91
+ else fs.unlinkSync(receiptPath);
92
+ }
93
+ // Directory ownership is not recorded; leave empty directories intact.
94
+ }
95
+ return count;
96
+ }
97
+ /** Per-file hash receipts preserve operator creations and subsequent edits, including --force. */
98
+ function writeOwned(dest, content, source, opts = {}, transformation = 'identity') {
99
+ assertNoSymlink(dest);
100
+ const dir = path.dirname(dest); const receiptPath = path.join(dir, '.aiwg-manifest.json');
101
+ const receipt = readReceipt(dir);
102
+ const base = path.basename(dest); const prior = receipt.managed[base];
103
+ if (fs.existsSync(dest)) {
104
+ const current = fs.readFileSync(dest);
105
+ if (current.equals(Buffer.from(content))) return 0;
106
+ if (!prior || prior.provider !== 'omp' || prior.hash !== `sha256:${hash(current)}`) { diagnostic(opts, `preserved operator file ${dest}`); return 0; }
107
+ }
108
+ if (opts.dryRun) return 1;
109
+ fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(dest, content);
110
+ receipt.managed[base] = { hash: `sha256:${hash(content)}`, source, provider: name, transformation, version: opts.deployVersion || 'unknown', ...(opts.diagnostics?.length ? { degraded: true, diagnostics: [...opts.diagnostics] } : {}) };
111
+ fs.writeFileSync(receiptPath, `${JSON.stringify(receipt, null, 2)}\n`); return 1;
112
+ }
113
+ export function deploySkillSupportAsset(source, destination, opts = {}) {
114
+ return writeOwned(destination, fs.readFileSync(source), source, opts, 'omp-skill');
115
+ }
116
+ function deployType(files, target, opts, type, transform) {
117
+ let count = 0; const seen = new Set();
118
+ for (const src of files) {
119
+ const basename = path.basename(src);
120
+ if (seen.has(basename)) throw new Error(`OMP ${type} collision: ${basename}`);
121
+ seen.add(basename);
122
+ const diagnostics = [];
123
+ const transformed = transform(src, fs.readFileSync(src, 'utf8'), { ...opts, diagnostics });
124
+ opts.diagnostics?.push(...diagnostics);
125
+ count += writeOwned(path.join(type === 'agents' ? roots(target, opts).agents : path.join(roots(target, opts).native, type), basename), transformed, src, { ...opts, diagnostics }, `omp-${type}`);
126
+ }
127
+ return count;
128
+ }
129
+ export const deployAgents = (files, target, opts = {}) => deployType(files, target, opts, 'agents', transformAgent);
130
+ export const deployCommands = (files, target, opts = {}) => deployType(files, target, opts, 'prompts', transformCommand);
131
+ export const deployRules = (files, target, opts = {}) => deployType(files, target, opts, 'rules', transformRule);
132
+ export function deploySkills(dirs, target, opts = {}) {
133
+ let count = 0; const seen = new Map(); const root = roots(target, opts);
134
+ for (const dir of [...new Set(dirs)]) {
135
+ const base = path.basename(dir); const previous = seen.get(base);
136
+ if (previous && previous !== dir) throw new Error(`OMP skill collision: ${base} (${previous}, ${dir})`);
137
+ seen.set(base, dir);
138
+ if (!isKernelSkill(dir) && !opts.copyStandardSkills) {
139
+ const removed = removeStandardSkillCopy(path.join(root.kernel, base), opts);
140
+ if (removed && !opts.quiet) console.log(`OMP: ${opts.dryRun ? 'would remove' : 'removed'} ${removed} unchanged standard skill files for ${base}`);
141
+ continue;
142
+ }
143
+ // Exactly one native level, sharing kernel directory for both modes avoids double discovery.
144
+ const dest = path.join(root.kernel, base);
145
+ function copy(current, relative = '') {
146
+ for (const entry of fs.readdirSync(current, { withFileTypes: true })) {
147
+ const src = path.join(current, entry.name); const rel = path.join(relative, entry.name);
148
+ if (entry.isDirectory()) copy(src, rel);
149
+ else if (entry.isFile()) count += writeOwned(path.join(dest, rel), fs.readFileSync(src), src, opts, 'omp-skill');
150
+ }
151
+ }
152
+ copy(dir);
153
+ }
154
+ return count;
155
+ }
156
+ export function createAgentsMd(target, srcRoot, dryRun = false) {
157
+ const dest = path.join(target, '.omp/AGENTS.md');
158
+ const start = '<!-- AIWG:omp-bootstrap:start -->'; const end = '<!-- AIWG:omp-bootstrap:end -->';
159
+ const block = `${start}\n@../WORKSPACE.md\n@../AIWG.md\n${end}`;
160
+ assertNoSymlink(dest);
161
+ const receipt = readReceipt(path.dirname(dest));
162
+ const current = fs.existsSync(dest) ? fs.readFileSync(dest, 'utf8') : '';
163
+ const starts = current.split(start).length - 1; const ends = current.split(end).length - 1;
164
+ if (starts !== ends || starts > 1 || (starts && current.indexOf(start) > current.indexOf(end))) throw new Error(`OMP preserves malformed bootstrap markers: ${dest}`);
165
+ const content = current.includes(start) && current.includes(end) ? current.slice(0, current.indexOf(start)) + block + current.slice(current.indexOf(end) + end.length) : `${current}${current ? '\n\n' : ''}${block}\n`;
166
+ if (!dryRun) {
167
+ fs.mkdirSync(path.dirname(dest), { recursive: true });
168
+ if (content !== current) fs.writeFileSync(dest, content);
169
+ const receiptPath = path.join(path.dirname(dest), '.aiwg-manifest.json');
170
+ // Block ownership must never claim the operator's complete context file.
171
+ receipt.managed['AGENTS.md'] = { blockHash: `sha256:${hash(block)}`, source: 'omp-bootstrap', provider: 'omp', transformation: 'managed-block' };
172
+ fs.writeFileSync(receiptPath, `${JSON.stringify(receipt, null, 2)}\n`);
173
+ }
174
+ }
175
+ /** Remove only unchanged OMP receipt entries and the native bootstrap block. */
176
+ export function uninstall(target, opts = {}) {
177
+ let removed = 0;
178
+ const root = roots(target, opts);
179
+ const context = path.join(root.native, 'AGENTS.md');
180
+ assertNoSymlink(context);
181
+ const contextReceipt = readReceipt(root.native).managed['AGENTS.md'];
182
+ const contextPrior = fs.existsSync(context) ? fs.readFileSync(context, 'utf8') : '';
183
+ const contextStart = '<!-- AIWG:omp-bootstrap:start -->'; const contextEnd = '<!-- AIWG:omp-bootstrap:end -->';
184
+ const starts = contextPrior.split(contextStart).length - 1; const ends = contextPrior.split(contextEnd).length - 1;
185
+ if (starts !== ends || starts > 1 || (starts && contextPrior.indexOf(contextStart) > contextPrior.indexOf(contextEnd))) throw new Error(`OMP preserves malformed bootstrap markers: ${context}`);
186
+ const contextBlock = contextPrior.match(/<!-- AIWG:omp-bootstrap:start -->[\s\S]*?<!-- AIWG:omp-bootstrap:end -->/)?.[0];
187
+ function clean(dir) {
188
+ if (!fs.existsSync(dir)) return;
189
+ assertNoSymlink(dir);
190
+ for (const entry of fs.readdirSync(dir, { withFileTypes: true })) if (entry.isDirectory() && !entry.isSymbolicLink()) clean(path.join(dir, entry.name));
191
+ const receiptPath = path.join(dir, '.aiwg-manifest.json');
192
+ if (!fs.existsSync(receiptPath)) return;
193
+ const receipt = readReceipt(dir);
194
+ for (const [name, entry] of Object.entries(receipt.managed || {})) {
195
+ if (entry.provider !== 'omp' || path.basename(name) !== name) continue;
196
+ const file = path.join(dir, name);
197
+ if (fs.existsSync(file) && !fs.lstatSync(file).isSymbolicLink() && fs.lstatSync(file).isFile() && entry.hash === `sha256:${hash(fs.readFileSync(file))}`) {
198
+ removed++; if (!opts.dryRun) { fs.unlinkSync(file); delete receipt.managed[name]; }
199
+ }
200
+ }
201
+ if (!opts.dryRun) {
202
+ if (Object.keys(receipt.managed).length) fs.writeFileSync(receiptPath, `${JSON.stringify(receipt, null, 2)}\n`);
203
+ else fs.unlinkSync(receiptPath);
204
+ }
205
+ }
206
+ clean(root.native); if (!root.agents.startsWith(`${root.native}${path.sep}`)) clean(root.agents); if (root.kernel !== path.join(root.native, 'skills')) clean(root.kernel);
207
+ if (contextBlock && contextReceipt?.provider === 'omp' && contextReceipt.blockHash === `sha256:${hash(contextBlock)}` && !opts.dryRun) {
208
+ const next = contextPrior.replace(`${contextBlock}\n`, '').replace(contextBlock, '');
209
+ if (next.trim()) fs.writeFileSync(context, next); else fs.unlinkSync(context);
210
+ const receipt = readReceipt(root.native); delete receipt.managed['AGENTS.md'];
211
+ const receiptPath = path.join(root.native, '.aiwg-manifest.json');
212
+ if (Object.keys(receipt.managed).length) fs.writeFileSync(receiptPath, `${JSON.stringify(receipt, null, 2)}\n`);
213
+ else if (fs.existsSync(receiptPath)) fs.unlinkSync(receiptPath);
214
+ }
215
+ return removed;
216
+ }
217
+ export const extensionBridge = 'agentic/code/providers/omp/aiwg-bridge.ts';
218
+ export function deployExtensionBridge(target, opts = {}) {
219
+ const src = path.join(resolveAiwgRoot(opts.srcRoot) || opts.srcRoot, extensionBridge);
220
+ return writeOwned(path.join(roots(target, opts).native, 'extensions/aiwg-bridge.ts'), fs.readFileSync(src, 'utf8'), src, opts, 'omp-extension');
221
+ }
222
+ export async function postDeploy(target, opts) {
223
+ if (opts.createAgentsMd || (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly)) createAgentsMd(target, opts.srcRoot, opts.dryRun);
224
+ }
225
+ export const getFileExtension = () => '.md';
226
+ export async function deploy(opts) {
227
+ const mode = normalizeDeploymentMode(opts.mode);
228
+ const include = { includeAgents: true, includeCommands: opts.deployCommands || opts.commandsOnly, includeSkills: opts.deploySkills || opts.skillsOnly, includeRules: opts.deployRules || opts.rulesOnly };
229
+ const directSource = ['agents', 'commands', 'skills', 'rules'].some(type => fs.existsSync(path.join(opts.srcRoot, type)));
230
+ const framework = directSource ? {
231
+ agents: listMdFiles(path.join(opts.srcRoot, 'agents')),
232
+ commands: include.includeCommands ? listMdFiles(path.join(opts.srcRoot, 'commands')) : [],
233
+ skills: include.includeSkills ? listSkillDirs(path.join(opts.srcRoot, 'skills')) : [],
234
+ rules: include.includeRules ? listMdFiles(path.join(opts.srcRoot, 'rules')) : [],
235
+ } : collectFrameworkArtifacts(opts.srcRoot, mode, include);
236
+ const addon = !directSource && ['general','sdlc','both','all'].includes(mode) ? getAddonFiles(opts.srcRoot, include) : { agents: [], commands: [], skills: [], rules: [] };
237
+ const selected = type => {
238
+ const frameworkNames = new Set(framework[type].map(file => path.basename(file)));
239
+ const addonByName = new Map();
240
+ for (const file of [...addon[type]].sort()) {
241
+ const basename = path.basename(file);
242
+ if (frameworkNames.has(basename)) continue;
243
+ if (addonByName.has(basename)) { diagnostic(opts, `bundled ${type} duplicate ${basename}; keeping ${addonByName.get(basename)}`); continue; }
244
+ addonByName.set(basename, file);
245
+ }
246
+ return [...new Set([...addonByName.values(), ...framework[type]])];
247
+ };
248
+ let count = 0;
249
+ if (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly) count += deployAgents(selected('agents'), opts.target, opts);
250
+ if (include.includeCommands && !opts.skillsOnly && !opts.rulesOnly) count += deployCommands(selected('commands'), opts.target, opts);
251
+ if (include.includeSkills && !opts.commandsOnly && !opts.rulesOnly) count += deploySkills(selected('skills'), opts.target, opts);
252
+ if (include.includeRules && !opts.commandsOnly && !opts.skillsOnly) count += deployRules(selected('rules'), opts.target, opts);
253
+ if (!opts.commandsOnly && !opts.skillsOnly && !opts.rulesOnly) count += deployExtensionBridge(opts.target, opts);
254
+ await postDeploy(opts.target, opts); return count;
255
+ }
256
+ export default { name, aliases, paths, kernelSkillsPath, support, capabilities, mapModel, transformAgent, transformCommand, transformRule, deployAgents, deployCommands, deploySkills, deployRules, deployExtensionBridge, createAgentsMd, postDeploy, getFileExtension, deploy, uninstall };