@a5c-ai/extension-mux 5.0.1-staging.078c111a306a

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 (116) hide show
  1. package/README.md +58 -0
  2. package/dist/binTemplates.d.ts +7 -0
  3. package/dist/binTemplates.d.ts.map +1 -0
  4. package/dist/binTemplates.js +292 -0
  5. package/dist/cli.d.ts +8 -0
  6. package/dist/cli.d.ts.map +1 -0
  7. package/dist/cli.js +299 -0
  8. package/dist/compiler.d.ts +15 -0
  9. package/dist/compiler.d.ts.map +1 -0
  10. package/dist/compiler.js +118 -0
  11. package/dist/diff.d.ts +9 -0
  12. package/dist/diff.d.ts.map +1 -0
  13. package/dist/diff.js +183 -0
  14. package/dist/emit.d.ts +3 -0
  15. package/dist/emit.d.ts.map +1 -0
  16. package/dist/emit.js +42 -0
  17. package/dist/hookRegistration.d.ts +8 -0
  18. package/dist/hookRegistration.d.ts.map +1 -0
  19. package/dist/hookRegistration.js +9 -0
  20. package/dist/index.d.ts +13 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +13 -0
  23. package/dist/init.d.ts +17 -0
  24. package/dist/init.d.ts.map +1 -0
  25. package/dist/init.js +200 -0
  26. package/dist/installInstructions.d.ts +3 -0
  27. package/dist/installInstructions.d.ts.map +1 -0
  28. package/dist/installInstructions.js +150 -0
  29. package/dist/installSharedGenerator.d.ts +3 -0
  30. package/dist/installSharedGenerator.d.ts.map +1 -0
  31. package/dist/installSharedGenerator.js +229 -0
  32. package/dist/manifestGenerators.d.ts +10 -0
  33. package/dist/manifestGenerators.d.ts.map +1 -0
  34. package/dist/manifestGenerators.js +11 -0
  35. package/dist/marketplaceGenerator.d.ts +3 -0
  36. package/dist/marketplaceGenerator.d.ts.map +1 -0
  37. package/dist/marketplaceGenerator.js +46 -0
  38. package/dist/proxiedHookTemplates.d.ts +10 -0
  39. package/dist/proxiedHookTemplates.d.ts.map +1 -0
  40. package/dist/proxiedHookTemplates.js +122 -0
  41. package/dist/resolve.d.ts +3 -0
  42. package/dist/resolve.d.ts.map +1 -0
  43. package/dist/resolve.js +106 -0
  44. package/dist/schema.d.ts +231 -0
  45. package/dist/schema.d.ts.map +1 -0
  46. package/dist/schema.js +340 -0
  47. package/dist/sdkConfig.d.ts +20 -0
  48. package/dist/sdkConfig.d.ts.map +1 -0
  49. package/dist/sdkConfig.js +41 -0
  50. package/dist/targets/adapters/base.d.ts +10 -0
  51. package/dist/targets/adapters/base.d.ts.map +1 -0
  52. package/dist/targets/adapters/base.js +16 -0
  53. package/dist/targets/adapters/claude-code.d.ts +9 -0
  54. package/dist/targets/adapters/claude-code.d.ts.map +1 -0
  55. package/dist/targets/adapters/claude-code.js +83 -0
  56. package/dist/targets/adapters/codex.d.ts +13 -0
  57. package/dist/targets/adapters/codex.d.ts.map +1 -0
  58. package/dist/targets/adapters/codex.js +103 -0
  59. package/dist/targets/adapters/cursor.d.ts +9 -0
  60. package/dist/targets/adapters/cursor.d.ts.map +1 -0
  61. package/dist/targets/adapters/cursor.js +57 -0
  62. package/dist/targets/adapters/gemini.d.ts +9 -0
  63. package/dist/targets/adapters/gemini.d.ts.map +1 -0
  64. package/dist/targets/adapters/gemini.js +86 -0
  65. package/dist/targets/adapters/github-copilot.d.ts +9 -0
  66. package/dist/targets/adapters/github-copilot.d.ts.map +1 -0
  67. package/dist/targets/adapters/github-copilot.js +61 -0
  68. package/dist/targets/adapters/hermes.d.ts +13 -0
  69. package/dist/targets/adapters/hermes.d.ts.map +1 -0
  70. package/dist/targets/adapters/hermes.js +96 -0
  71. package/dist/targets/adapters/hooks-utils.d.ts +12 -0
  72. package/dist/targets/adapters/hooks-utils.d.ts.map +1 -0
  73. package/dist/targets/adapters/hooks-utils.js +60 -0
  74. package/dist/targets/adapters/index.d.ts +27 -0
  75. package/dist/targets/adapters/index.d.ts.map +1 -0
  76. package/dist/targets/adapters/index.js +64 -0
  77. package/dist/targets/adapters/interface.d.ts +8 -0
  78. package/dist/targets/adapters/interface.d.ts.map +1 -0
  79. package/dist/targets/adapters/interface.js +2 -0
  80. package/dist/targets/adapters/oh-my-pi.d.ts +11 -0
  81. package/dist/targets/adapters/oh-my-pi.d.ts.map +1 -0
  82. package/dist/targets/adapters/oh-my-pi.js +88 -0
  83. package/dist/targets/adapters/openclaw.d.ts +14 -0
  84. package/dist/targets/adapters/openclaw.d.ts.map +1 -0
  85. package/dist/targets/adapters/openclaw.js +165 -0
  86. package/dist/targets/adapters/opencode.d.ts +10 -0
  87. package/dist/targets/adapters/opencode.d.ts.map +1 -0
  88. package/dist/targets/adapters/opencode.js +93 -0
  89. package/dist/targets/adapters/pi.d.ts +11 -0
  90. package/dist/targets/adapters/pi.d.ts.map +1 -0
  91. package/dist/targets/adapters/pi.js +90 -0
  92. package/dist/targets/index.d.ts +7 -0
  93. package/dist/targets/index.d.ts.map +1 -0
  94. package/dist/targets/index.js +77 -0
  95. package/dist/transform.d.ts +4 -0
  96. package/dist/transform.d.ts.map +1 -0
  97. package/dist/transform.js +243 -0
  98. package/dist/transformEmitters.d.ts +8 -0
  99. package/dist/transformEmitters.d.ts.map +1 -0
  100. package/dist/transformEmitters.js +340 -0
  101. package/dist/transformHelpers.d.ts +13 -0
  102. package/dist/transformHelpers.d.ts.map +1 -0
  103. package/dist/transformHelpers.js +239 -0
  104. package/dist/types.d.ts +204 -0
  105. package/dist/types.d.ts.map +1 -0
  106. package/dist/types.js +2 -0
  107. package/dist/utils.d.ts +42 -0
  108. package/dist/utils.d.ts.map +1 -0
  109. package/dist/utils.js +187 -0
  110. package/dist/validate.d.ts +3 -0
  111. package/dist/validate.d.ts.map +1 -0
  112. package/dist/validate.js +188 -0
  113. package/dist/verify.d.ts +6 -0
  114. package/dist/verify.d.ts.map +1 -0
  115. package/dist/verify.js +294 -0
  116. package/package.json +60 -0
package/README.md ADDED
@@ -0,0 +1,58 @@
1
+ # @a5c-ai/extension-mux
2
+
3
+ Cross-harness plugin compiler for converting a unified `plugin.json` source tree into harness-specific plugin packages.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm install @a5c-ai/extension-mux
9
+ ```
10
+
11
+ CLI usage:
12
+
13
+ ```bash
14
+ npx @a5c-ai/extension-mux extension-mux --help
15
+ ```
16
+
17
+ This package ships the built compiler in `dist/` and this package README for npm auditability.
18
+
19
+ ## CLI Surface
20
+
21
+ The current public CLI commands are:
22
+
23
+ - `compile --target <name|all> --output <dir>` to emit target plugin surfaces
24
+ - `validate --source <dir>` to validate a unified plugin directory without writing output
25
+ - `init --name <name> [--template <minimal|full|hooks-only>] [--output <dir>]` to scaffold a valid unified plugin source tree
26
+ - `list-targets` to print the supported target registry
27
+
28
+ The `diff` command is still reserved and currently exits with a not-implemented error. The supported targets are `claude-code`, `codex`, `cursor`, `gemini`, `github-copilot`, `pi`, `oh-my-pi`, `opencode`, and `openclaw`.
29
+
30
+ ## API Surface
31
+
32
+ ```ts
33
+ import {
34
+ compile,
35
+ compileAll,
36
+ validateDirectory,
37
+ validateSchema,
38
+ } from "@a5c-ai/extension-mux";
39
+ ```
40
+
41
+ The package exports the compiler pipeline and related types:
42
+
43
+ - manifest schema and package types
44
+ - directory validation, target resolution, transform, emit, and verify helpers
45
+ - target registry accessors and compilation entrypoints
46
+
47
+ ## Validation
48
+
49
+ ```bash
50
+ npm run build --workspace=@a5c-ai/extension-mux
51
+ npm run test --workspace=@a5c-ai/extension-mux
52
+ npm run verify:metadata
53
+ npm pack --json --dry-run --workspace=@a5c-ai/extension-mux
54
+ ```
55
+
56
+ ## Release Expectations
57
+
58
+ `@a5c-ai/extension-mux` is published from the central release workflows. Keep this README aligned with the actual command set and compiler exports, and keep `package.json#files` limited to the built compiler plus package documentation.
@@ -0,0 +1,7 @@
1
+ import type { A5cPluginManifest, TargetProfile } from './types.js';
2
+ export declare function generateCliBinScript(manifest: A5cPluginManifest, targetProfile: TargetProfile): string;
3
+ export declare function generateInstallScript(_manifest: A5cPluginManifest, targetProfile: TargetProfile): string;
4
+ declare function generateGeminiInstallScript(manifest: A5cPluginManifest): string;
5
+ export declare function generateUninstallScript(_manifest: A5cPluginManifest, targetProfile: TargetProfile): string;
6
+ export { generateGeminiInstallScript as _generateGeminiInstallScript };
7
+ //# sourceMappingURL=binTemplates.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"binTemplates.d.ts","sourceRoot":"","sources":["../src/binTemplates.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAUnE,wBAAgB,oBAAoB,CAClC,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,GAC3B,MAAM,CAqGR;AAED,wBAAgB,qBAAqB,CACnC,SAAS,EAAE,iBAAiB,EAC5B,aAAa,EAAE,aAAa,GAC3B,MAAM,CA2ER;AAED,iBAAS,2BAA2B,CAAC,QAAQ,EAAE,iBAAiB,GAAG,MAAM,CA8BxE;AAED,wBAAgB,uBAAuB,CACrC,SAAS,EAAE,iBAAiB,EAC5B,aAAa,EAAE,aAAa,GAC3B,MAAM,CA4ER;AAED,OAAO,EAAE,2BAA2B,IAAI,4BAA4B,EAAE,CAAC"}
@@ -0,0 +1,292 @@
1
+ // CLI bin script templates for targets with npm distribution
2
+ import { resolveTargetCliName } from './sdkConfig.js';
3
+ function getExt(targetProfile) {
4
+ return targetProfile.packageMetadata?.binScriptExt ?? '.js';
5
+ }
6
+ function getCliName(manifest, targetProfile) {
7
+ return resolveTargetCliName(manifest, targetProfile);
8
+ }
9
+ export function generateCliBinScript(manifest, targetProfile) {
10
+ const cliName = getCliName(manifest, targetProfile);
11
+ const ext = getExt(targetProfile);
12
+ return `#!/usr/bin/env node
13
+ 'use strict';
14
+
15
+ const path = require('path');
16
+ const { spawnSync } = require('child_process');
17
+
18
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
19
+ let shared;
20
+ try { shared = require('./install-shared'); } catch {}
21
+
22
+ function printUsage() {
23
+ console.error([
24
+ 'Usage:',
25
+ ' ${cliName} install [--global]',
26
+ ' ${cliName} install --workspace [path]',
27
+ ' ${cliName} uninstall',
28
+ ].join('\\n'));
29
+ }
30
+
31
+ function parseInstallArgs(argv) {
32
+ let scope = 'global';
33
+ let workspace = null;
34
+ const passthrough = [];
35
+
36
+ for (let i = 0; i < argv.length; i += 1) {
37
+ const arg = argv[i];
38
+ if (arg === '--global') {
39
+ scope = 'global';
40
+ continue;
41
+ }
42
+ if (arg === '--workspace') {
43
+ scope = 'workspace';
44
+ const next = argv[i + 1];
45
+ if (next && !next.startsWith('-')) {
46
+ workspace = path.resolve(next);
47
+ i += 1;
48
+ } else {
49
+ workspace = process.cwd();
50
+ }
51
+ continue;
52
+ }
53
+ passthrough.push(arg);
54
+ }
55
+
56
+ return { scope, workspace, passthrough };
57
+ }
58
+
59
+ function runNodeScript(scriptPath, args, extraEnv = {}) {
60
+ const result = spawnSync(process.execPath, [scriptPath, ...args], {
61
+ cwd: process.cwd(),
62
+ stdio: 'inherit',
63
+ env: { ...process.env, ...extraEnv },
64
+ });
65
+ process.exitCode = result.status ?? 1;
66
+ }
67
+
68
+ function main() {
69
+ const [command, ...rest] = process.argv.slice(2);
70
+ if (!command || command === '--help' || command === '-h' || command === 'help') {
71
+ printUsage();
72
+ process.exitCode = command ? 0 : 1;
73
+ return;
74
+ }
75
+
76
+ if (command === 'install') {
77
+ if (shared && typeof shared.harnessCliRoute === 'function' && shared.harnessCliRoute(rest, PACKAGE_ROOT, runNodeScript)) {
78
+ return;
79
+ }
80
+ const parsed = parseInstallArgs(rest);
81
+ if (parsed.scope === 'workspace') {
82
+ const args = [];
83
+ if (parsed.workspace) {
84
+ args.push('--workspace', parsed.workspace);
85
+ }
86
+ args.push(...parsed.passthrough);
87
+ runNodeScript(
88
+ path.join(PACKAGE_ROOT, 'scripts', 'team-install${ext}'),
89
+ args,
90
+ { PLUGIN_PACKAGE_ROOT: PACKAGE_ROOT },
91
+ );
92
+ return;
93
+ }
94
+ runNodeScript(path.join(PACKAGE_ROOT, 'bin', 'install${ext}'), parsed.passthrough);
95
+ return;
96
+ }
97
+
98
+ if (command === 'uninstall') {
99
+ runNodeScript(path.join(PACKAGE_ROOT, 'bin', 'uninstall${ext}'), rest);
100
+ return;
101
+ }
102
+
103
+ printUsage();
104
+ process.exitCode = 1;
105
+ }
106
+
107
+ main();
108
+ `;
109
+ }
110
+ export function generateInstallScript(_manifest, targetProfile) {
111
+ if (targetProfile.componentSupport?.agents === 'native' && targetProfile.packageMetadata?.installLifecycle === 'plugin-scripts') {
112
+ return `#!/usr/bin/env node
113
+ 'use strict';
114
+
115
+ const path = require('path');
116
+ const shared = require('./install-shared');
117
+
118
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
119
+
120
+ function main() {
121
+ const pluginRoot = shared.getHomePluginRoot();
122
+ const marketplacePath = shared.getHomeMarketplacePath();
123
+
124
+ console.log(\`[\${shared.PLUGIN_NAME}] Installing plugin to \${pluginRoot}\`);
125
+
126
+ try {
127
+ shared.copyPluginBundle(PACKAGE_ROOT, pluginRoot);
128
+ shared.ensureMarketplaceEntry(marketplacePath, pluginRoot);
129
+ if (typeof shared.registerCopilotPlugin === 'function') {
130
+ shared.registerCopilotPlugin(pluginRoot);
131
+ }
132
+ if (typeof shared.installCopilotSurface === 'function' && typeof shared.getCopilotHome === 'function') {
133
+ shared.installCopilotSurface(PACKAGE_ROOT, shared.getCopilotHome());
134
+ }
135
+ if (typeof shared.warnWindowsHooks === 'function') {
136
+ shared.warnWindowsHooks();
137
+ }
138
+ if (typeof shared.harnessInstall === 'function') {
139
+ shared.harnessInstall(PACKAGE_ROOT, pluginRoot);
140
+ }
141
+ shared.runPostInstall && shared.runPostInstall(pluginRoot);
142
+ console.log(\`[\${shared.PLUGIN_NAME}] Installation complete!\`);
143
+ console.log(\`[\${shared.PLUGIN_NAME}] Restart your IDE/CLI to pick up the plugin.\`);
144
+ } catch (err) {
145
+ console.error(\`[\${shared.PLUGIN_NAME}] Failed to install: \${err.message}\`);
146
+ process.exitCode = 1;
147
+ }
148
+ }
149
+
150
+ main();
151
+ `;
152
+ }
153
+ return `#!/usr/bin/env node
154
+ 'use strict';
155
+
156
+ const path = require('path');
157
+ const shared = require('./install-shared');
158
+
159
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
160
+
161
+ function main() {
162
+ const pluginRoot = shared.getHomePluginRoot();
163
+ const marketplacePath = shared.getHomeMarketplacePath();
164
+
165
+ console.log(\`[\${shared.PLUGIN_NAME}] Installing plugin to \${pluginRoot}\`);
166
+
167
+ try {
168
+ shared.copyPluginBundle(PACKAGE_ROOT, pluginRoot);
169
+ shared.ensureMarketplaceEntry(marketplacePath, pluginRoot);
170
+ if (typeof shared.harnessInstall === 'function') {
171
+ shared.harnessInstall(PACKAGE_ROOT, pluginRoot);
172
+ }
173
+ shared.runPostInstall && shared.runPostInstall(pluginRoot);
174
+ console.log(\`[\${shared.PLUGIN_NAME}] Installation complete!\`);
175
+ console.log(\`[\${shared.PLUGIN_NAME}] Restart your IDE/CLI to pick up the plugin.\`);
176
+ } catch (err) {
177
+ console.error(\`[\${shared.PLUGIN_NAME}] Failed to install: \${err.message}\`);
178
+ process.exitCode = 1;
179
+ }
180
+ }
181
+
182
+ main();
183
+ `;
184
+ }
185
+ function generateGeminiInstallScript(manifest) {
186
+ const cliName = resolveTargetCliName(manifest, { name: 'gemini' });
187
+ return `#!/usr/bin/env node
188
+ 'use strict';
189
+
190
+ const path = require('path');
191
+ const { spawnSync } = require('child_process');
192
+ const PACKAGE_ROOT = path.resolve(__dirname, '..');
193
+
194
+ function main() {
195
+ console.log('[${cliName}] Installing extension...');
196
+ const result = spawnSync('gemini', ['extensions', 'install', PACKAGE_ROOT], {
197
+ stdio: 'inherit', timeout: 60000
198
+ });
199
+ if (result.status === 0) {
200
+ console.log('[${cliName}] Extension installed via Gemini CLI.');
201
+ } else {
202
+ const linkResult = spawnSync('gemini', ['extensions', 'link', PACKAGE_ROOT], {
203
+ stdio: 'inherit', timeout: 60000
204
+ });
205
+ if (linkResult.status === 0) {
206
+ console.log('[${cliName}] Extension linked via Gemini CLI.');
207
+ } else {
208
+ console.error('[${cliName}] Gemini CLI not available. Install manually: gemini extensions install ' + PACKAGE_ROOT);
209
+ }
210
+ }
211
+ }
212
+
213
+ main();
214
+ `;
215
+ }
216
+ export function generateUninstallScript(_manifest, targetProfile) {
217
+ if (targetProfile.componentSupport?.agents === 'native' && targetProfile.packageMetadata?.installLifecycle === 'plugin-scripts') {
218
+ return `#!/usr/bin/env node
219
+ 'use strict';
220
+
221
+ const path = require('path');
222
+ const fs = require('fs');
223
+ const shared = require('./install-shared');
224
+
225
+ function main() {
226
+ const pluginRoot = shared.getHomePluginRoot();
227
+ const marketplacePath = typeof shared.getHomeMarketplacePath === 'function'
228
+ ? shared.getHomeMarketplacePath()
229
+ : null;
230
+ const copilotHome = typeof shared.getCopilotHome === 'function'
231
+ ? shared.getCopilotHome()
232
+ : null;
233
+
234
+ if (!fs.existsSync(pluginRoot)) {
235
+ console.log(\`[\${shared.PLUGIN_NAME}] Plugin not installed at \${pluginRoot}\`);
236
+ } else {
237
+ try {
238
+ fs.rmSync(pluginRoot, { recursive: true, force: true });
239
+ console.log(\`[\${shared.PLUGIN_NAME}] Uninstalled from \${pluginRoot}\`);
240
+ } catch (err) {
241
+ console.error(\`[\${shared.PLUGIN_NAME}] Failed to uninstall: \${err.message}\`);
242
+ process.exitCode = 1;
243
+ return;
244
+ }
245
+ }
246
+
247
+ try {
248
+ if (typeof shared.deregisterCopilotPlugin === 'function') {
249
+ shared.deregisterCopilotPlugin(pluginRoot);
250
+ }
251
+ if (copilotHome && typeof shared.removeManagedHooks === 'function') {
252
+ shared.removeManagedHooks(copilotHome);
253
+ }
254
+ if (marketplacePath && typeof shared.removeMarketplaceEntry === 'function') {
255
+ shared.removeMarketplaceEntry(marketplacePath);
256
+ }
257
+ } catch (err) {
258
+ console.error(\`[\${shared.PLUGIN_NAME}] Failed to clean up uninstall state: \${err.message}\`);
259
+ process.exitCode = 1;
260
+ }
261
+ }
262
+
263
+ main();
264
+ `;
265
+ }
266
+ return `#!/usr/bin/env node
267
+ 'use strict';
268
+
269
+ const fs = require('fs');
270
+ const shared = require('./install-shared');
271
+
272
+ function main() {
273
+ const pluginRoot = shared.getHomePluginRoot();
274
+
275
+ if (!fs.existsSync(pluginRoot)) {
276
+ console.log(\`[\${shared.PLUGIN_NAME}] Plugin not installed at \${pluginRoot}\`);
277
+ return;
278
+ }
279
+
280
+ try {
281
+ fs.rmSync(pluginRoot, { recursive: true, force: true });
282
+ console.log(\`[\${shared.PLUGIN_NAME}] Uninstalled from \${pluginRoot}\`);
283
+ } catch (err) {
284
+ console.error(\`[\${shared.PLUGIN_NAME}] Failed to uninstall: \${err.message}\`);
285
+ process.exitCode = 1;
286
+ }
287
+ }
288
+
289
+ main();
290
+ `;
291
+ }
292
+ export { generateGeminiInstallScript as _generateGeminiInstallScript };
package/dist/cli.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env node
2
+ interface CliIo {
3
+ stdout: (message: string) => void;
4
+ stderr: (message: string) => void;
5
+ }
6
+ export declare function runCli(args: string[], io?: CliIo): number;
7
+ export {};
8
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAaA,UAAU,KAAK;IACb,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,MAAM,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;CACnC;AAyRD,wBAAgB,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,GAAE,KAAiB,GAAG,MAAM,CAkCpE"}
package/dist/cli.js ADDED
@@ -0,0 +1,299 @@
1
+ #!/usr/bin/env node
2
+ // CLI for extension-mux compiler
3
+ import * as path from 'path';
4
+ import * as process from 'process';
5
+ import { fileURLToPath } from 'url';
6
+ import { compile, compileAll } from './compiler.js';
7
+ import { diffTarget, formatDiffResult } from './diff.js';
8
+ import { INIT_TEMPLATES, scaffoldPlugin } from './init.js';
9
+ import { validate } from './validate.js';
10
+ import { getAllTargets } from './targets/index.js';
11
+ const defaultIo = {
12
+ stdout: (message) => console.log(message),
13
+ stderr: (message) => console.error(message),
14
+ };
15
+ function showUsage(io) {
16
+ io.stdout(`
17
+ extension-mux - Cross-harness plugin compiler for AI coding agents
18
+
19
+ Usage:
20
+ extension-mux compile --target <name|all> --output <dir> [options]
21
+ extension-mux validate [options]
22
+ extension-mux diff --target <name> --existing <dir> [options]
23
+ extension-mux init --name <name> [options]
24
+ extension-mux list-targets [options]
25
+
26
+ Commands:
27
+ compile Compile UPF source to target format(s)
28
+ validate Validate UPF source without compiling
29
+ diff Compare compiled output against existing directory
30
+ init Scaffold a new UPF plugin
31
+ list-targets List available compilation targets
32
+
33
+ Options:
34
+ --source <dir> UPF source directory (default: current directory)
35
+ --target <name> Target harness name or "all"
36
+ --output <dir> Output directory
37
+ --existing <dir> Path to existing plugin directory (for diff)
38
+ --name <name> Plugin name (for init)
39
+ --template <name> Template to use: ${INIT_TEMPLATES.join(', ')}
40
+ --verify Run verification checks after compilation
41
+ --dry-run Show what would be emitted without writing files
42
+ --json Output structured JSON result
43
+ --verbose Verbose logging
44
+ --help, -h Show this help message
45
+
46
+ Valid targets:
47
+ claude-code, codex, cursor, gemini, github-copilot,
48
+ pi, oh-my-pi, opencode, openclaw
49
+ `);
50
+ }
51
+ function parseArgs(args) {
52
+ const parsed = {};
53
+ for (let i = 0; i < args.length; i++) {
54
+ const arg = args[i];
55
+ if (arg.startsWith('--')) {
56
+ const key = arg.slice(2);
57
+ if (key === 'verify' ||
58
+ key === 'dry-run' ||
59
+ key === 'json' ||
60
+ key === 'verbose' ||
61
+ key === 'help') {
62
+ parsed[key] = true;
63
+ }
64
+ else {
65
+ const value = args[i + 1];
66
+ if (value && !value.startsWith('--')) {
67
+ parsed[key] = value;
68
+ i++;
69
+ }
70
+ }
71
+ }
72
+ else if (arg === '-h') {
73
+ parsed.help = true;
74
+ }
75
+ else if (!parsed.command) {
76
+ parsed.command = arg;
77
+ }
78
+ }
79
+ return parsed;
80
+ }
81
+ function printDiagnostics(diagnostics, verbose = false) {
82
+ const errors = diagnostics.filter((d) => d.level === 'error');
83
+ const warnings = diagnostics.filter((d) => d.level === 'warning');
84
+ const infos = diagnostics.filter((d) => d.level === 'info');
85
+ for (const diag of errors) {
86
+ console.error(`\x1b[31m[ERROR]\x1b[0m ${diag.message}`);
87
+ if (diag.source)
88
+ console.error(` Source: ${diag.source}`);
89
+ if (diag.suggestion)
90
+ console.error(` Suggestion: ${diag.suggestion}`);
91
+ }
92
+ for (const diag of warnings) {
93
+ console.warn(`\x1b[33m[WARNING]\x1b[0m ${diag.message}`);
94
+ if (diag.source && verbose)
95
+ console.warn(` Source: ${diag.source}`);
96
+ }
97
+ if (verbose) {
98
+ for (const diag of infos) {
99
+ console.log(`\x1b[36m[INFO]\x1b[0m ${diag.message}`);
100
+ }
101
+ }
102
+ if (errors.length > 0 || warnings.length > 0 || infos.length > 0) {
103
+ console.log(`\nSummary: ${errors.length} error(s), ${warnings.length} warning(s), ${infos.length} info`);
104
+ }
105
+ }
106
+ function runCompile(parsed, io) {
107
+ const source = parsed.source || process.cwd();
108
+ const target = parsed.target;
109
+ const output = parsed.output;
110
+ const dryRun = parsed['dry-run'];
111
+ const verifyOutput = parsed.verify;
112
+ const jsonOutput = parsed.json;
113
+ const verbose = parsed.verbose;
114
+ if (!target || !output) {
115
+ io.stderr('Error: --target and --output are required');
116
+ return 1;
117
+ }
118
+ if (target === 'all') {
119
+ const results = compileAll(source, output, { dryRun, verifyOutput });
120
+ if (jsonOutput) {
121
+ io.stdout(JSON.stringify(results, null, 2));
122
+ }
123
+ else {
124
+ for (const result of results) {
125
+ io.stdout(`\n=== Target: ${result.target} ===`);
126
+ io.stdout(`Status: ${result.status}`);
127
+ io.stdout(`Output: ${result.outputDir}`);
128
+ io.stdout(`Emitted files: ${result.emittedFiles.length}`);
129
+ printDiagnostics(result.diagnostics, verbose);
130
+ }
131
+ const failed = results.filter((r) => r.status === 'error').length;
132
+ const warnings = results.filter((r) => r.status === 'warning').length;
133
+ const success = results.filter((r) => r.status === 'success').length;
134
+ io.stdout(`\n=== Overall ===\n${success} succeeded, ${warnings} with warnings, ${failed} failed`);
135
+ }
136
+ const hasErrors = results.some((r) => r.status === 'error');
137
+ return hasErrors ? 1 : 0;
138
+ }
139
+ else {
140
+ const result = compile({
141
+ source,
142
+ target,
143
+ output,
144
+ dryRun,
145
+ verifyOutput,
146
+ });
147
+ if (jsonOutput) {
148
+ io.stdout(JSON.stringify(result, null, 2));
149
+ }
150
+ else {
151
+ io.stdout(`Target: ${result.target}`);
152
+ io.stdout(`Status: ${result.status}`);
153
+ io.stdout(`Output: ${result.outputDir}`);
154
+ io.stdout(`Emitted files: ${result.emittedFiles.length}`);
155
+ if (result.verificationChecklist.length > 0 && verbose) {
156
+ io.stdout('\nVerification:');
157
+ for (const check of result.verificationChecklist) {
158
+ io.stdout(` ${check}`);
159
+ }
160
+ }
161
+ printDiagnostics(result.diagnostics, verbose);
162
+ }
163
+ return result.status === 'error' ? 1 : 0;
164
+ }
165
+ }
166
+ function runValidate(parsed, io) {
167
+ const source = parsed.source || process.cwd();
168
+ const jsonOutput = parsed.json;
169
+ const verbose = parsed.verbose;
170
+ const result = validate(source);
171
+ if (jsonOutput) {
172
+ io.stdout(JSON.stringify(result, null, 2));
173
+ }
174
+ else {
175
+ io.stdout(`Valid: ${result.valid}`);
176
+ printDiagnostics(result.diagnostics, verbose);
177
+ }
178
+ return result.valid ? 0 : 1;
179
+ }
180
+ function runListTargets(parsed, io) {
181
+ const jsonOutput = parsed.json;
182
+ const targets = getAllTargets();
183
+ if (jsonOutput) {
184
+ io.stdout(JSON.stringify(targets, null, 2));
185
+ }
186
+ else {
187
+ io.stdout('Available targets:');
188
+ for (const target of targets) {
189
+ io.stdout(` - ${target}`);
190
+ }
191
+ }
192
+ return 0;
193
+ }
194
+ function runDiff(parsed, io) {
195
+ const source = parsed.source || process.cwd();
196
+ const target = parsed.target;
197
+ const existing = parsed.existing;
198
+ const jsonOutput = parsed.json;
199
+ const verbose = parsed.verbose;
200
+ if (!target || !existing) {
201
+ io.stderr('Error: --target and --existing are required');
202
+ return 1;
203
+ }
204
+ if (target === 'all') {
205
+ io.stderr('Error: diff currently supports a single target; pass a specific --target name');
206
+ return 1;
207
+ }
208
+ const result = diffTarget({ source, target, existing });
209
+ if (jsonOutput) {
210
+ io.stdout(JSON.stringify(result, null, 2));
211
+ }
212
+ else {
213
+ io.stdout(formatDiffResult(result));
214
+ if (result.diagnostics.length > 0) {
215
+ printDiagnostics(result.diagnostics, verbose);
216
+ }
217
+ }
218
+ return result.status === 'match' ? 0 : 1;
219
+ }
220
+ function runInit(parsed, io) {
221
+ const name = parsed.name;
222
+ const template = parsed.template;
223
+ const output = parsed.output ?? process.cwd();
224
+ const dryRun = parsed['dry-run'];
225
+ const jsonOutput = parsed.json;
226
+ if (!name) {
227
+ io.stderr('Error: --name is required');
228
+ return 1;
229
+ }
230
+ const result = scaffoldPlugin({
231
+ name,
232
+ template: template,
233
+ output,
234
+ dryRun,
235
+ });
236
+ if (jsonOutput) {
237
+ io.stdout(JSON.stringify(result, null, 2));
238
+ }
239
+ else {
240
+ io.stdout(`Scaffolded template: ${result.template}`);
241
+ io.stdout(`Output: ${result.outputDir}`);
242
+ io.stdout(`Files: ${result.writtenFiles.length}`);
243
+ if (parsed.verbose) {
244
+ for (const file of result.writtenFiles) {
245
+ io.stdout(` - ${file}`);
246
+ }
247
+ }
248
+ if (dryRun) {
249
+ io.stdout('Dry run only. No files were written.');
250
+ }
251
+ }
252
+ return 0;
253
+ }
254
+ export function runCli(args, io = defaultIo) {
255
+ const parsed = parseArgs(args);
256
+ if (parsed.help || !parsed.command) {
257
+ showUsage(io);
258
+ return 0;
259
+ }
260
+ const command = parsed.command;
261
+ try {
262
+ switch (command) {
263
+ case 'compile':
264
+ return runCompile(parsed, io);
265
+ case 'validate':
266
+ return runValidate(parsed, io);
267
+ case 'list-targets':
268
+ return runListTargets(parsed, io);
269
+ case 'diff':
270
+ return runDiff(parsed, io);
271
+ case 'init':
272
+ return runInit(parsed, io);
273
+ default:
274
+ io.stderr(`Unknown command: ${command}`);
275
+ showUsage(io);
276
+ return 1;
277
+ }
278
+ }
279
+ catch (error) {
280
+ io.stderr(`Fatal error: ${error.message}`);
281
+ if (parsed.verbose) {
282
+ io.stderr(error.stack ?? '');
283
+ }
284
+ return 1;
285
+ }
286
+ }
287
+ function isExecutedDirectly() {
288
+ const entryPoint = process.argv[1];
289
+ if (!entryPoint) {
290
+ return false;
291
+ }
292
+ return path.resolve(entryPoint) === fileURLToPath(import.meta.url);
293
+ }
294
+ function main() {
295
+ process.exit(runCli(process.argv.slice(2)));
296
+ }
297
+ if (isExecutedDirectly()) {
298
+ main();
299
+ }
@@ -0,0 +1,15 @@
1
+ import type { CompilationResult } from './types.js';
2
+ export interface CompileOptions {
3
+ source: string;
4
+ target: string;
5
+ output: string;
6
+ outputBaseDir?: string;
7
+ dryRun?: boolean;
8
+ verifyOutput?: boolean;
9
+ }
10
+ export declare function compile(options: CompileOptions): CompilationResult;
11
+ export declare function compileAll(source: string, outputBaseDir: string, options?: {
12
+ dryRun?: boolean;
13
+ verifyOutput?: boolean;
14
+ }): CompilationResult[];
15
+ //# sourceMappingURL=compiler.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compiler.d.ts","sourceRoot":"","sources":["../src/compiler.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AASpD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,OAAO,CAAC,OAAO,EAAE,cAAc,GAAG,iBAAiB,CAiHlE;AAED,wBAAgB,UAAU,CACxB,MAAM,EAAE,MAAM,EACd,aAAa,EAAE,MAAM,EACrB,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAO,GACzD,iBAAiB,EAAE,CAgBrB"}