@a5c-ai/extension-mux 5.0.1-staging.04ca6ab00d21

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 +68 -0
@@ -0,0 +1,340 @@
1
+ // Manifest generators and file copy functions for the transform stage
2
+ import * as fs from 'fs';
3
+ import * as path from 'path';
4
+ import { getAdapter } from './targets/adapters/index.js';
5
+ import { generateProgrammaticExtension } from './proxiedHookTemplates.js';
6
+ import { generateCliBinScript, generateInstallScript, generateUninstallScript } from './binTemplates.js';
7
+ import { generateInstallInstructions } from './installInstructions.js';
8
+ import { generateTeamInstall, resolveExtraFiles, } from './transformHelpers.js';
9
+ import { generateInstallShared } from './installSharedGenerator.js';
10
+ import { resolveSdkConfig, resolveTargetCliName, resolveTargetNpmPackageName, } from './sdkConfig.js';
11
+ import { getCommandPaths } from './utils.js';
12
+ function toOutputPath(value) {
13
+ return value.replace(/\\/g, '/');
14
+ }
15
+ function getRequiredSurfaceFilename(targetProfile) {
16
+ return targetProfile.requiredSurfaceFile ?? null;
17
+ }
18
+ function buildSurfaceFallback(manifest, targetProfile, filename) {
19
+ return `# ${filename}
20
+
21
+ This file was generated by @a5c-ai/extension-mux for target \`${targetProfile.name}\`.
22
+
23
+ The plugin manifest for \`${manifest.name}\` does not declare a dedicated ${filename} source file.
24
+ Add \`agents\` and/or \`contextFiles.${targetProfile.name}\` in \`plugin.json\` to replace this placeholder with real target guidance.
25
+ `;
26
+ }
27
+ function readExistingTextFile(sourceDir, relativePath) {
28
+ const fullPath = path.join(sourceDir, relativePath);
29
+ if (!fs.existsSync(fullPath) || !fs.statSync(fullPath).isFile()) {
30
+ return null;
31
+ }
32
+ return fs.readFileSync(fullPath, 'utf-8');
33
+ }
34
+ function resolveAgentSurfaceContent(sourceDir, manifest) {
35
+ if (!manifest.agents) {
36
+ return null;
37
+ }
38
+ const agentPaths = typeof manifest.agents === 'string' ? [manifest.agents] : manifest.agents;
39
+ const contents = agentPaths
40
+ .map((agentPath) => readExistingTextFile(sourceDir, agentPath))
41
+ .filter((content) => content !== null);
42
+ if (contents.length === 0) {
43
+ return null;
44
+ }
45
+ return contents.join('\n\n');
46
+ }
47
+ function generateCjsWrapper(moduleBasename, exportOnly = false) {
48
+ if (exportOnly) {
49
+ return `'use strict';\n\nmodule.exports = require('./${moduleBasename}.js');\n`;
50
+ }
51
+ return `#!/usr/bin/env node
52
+ 'use strict';
53
+
54
+ require('./${moduleBasename}.js');
55
+ `;
56
+ }
57
+ export function generateManifests(sourceDir, manifest, targetProfile, _diagnostics) {
58
+ const files = [];
59
+ // Filter manifest hooks to only those supported by this target
60
+ // and resolve handler paths through hookFilePattern
61
+ const sdkCfg = resolveSdkConfig(manifest);
62
+ const filteredManifest = { ...manifest };
63
+ if (manifest.hooks) {
64
+ const hookFilePattern = manifest.targets?.[targetProfile.name]?.hookFilePattern
65
+ ?? manifest.hookFilePattern;
66
+ const pat = typeof hookFilePattern === 'string' ? hookFilePattern : undefined;
67
+ const toSlug = (s) => s
68
+ .replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
69
+ .replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
70
+ const toNativeSlug = (s) => s.replace(/[._]/g, '-').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
71
+ const filtered = {};
72
+ for (const [canonical, handler] of Object.entries(manifest.hooks)) {
73
+ if (handler === null || !targetProfile.supportedHooks.has(canonical))
74
+ continue;
75
+ if (typeof handler === 'string' && handler !== 'proxy' && pat) {
76
+ const native = targetProfile.supportedHooks.get(canonical) || canonical;
77
+ const resolved = 'hooks/' + pat
78
+ .replace(/\{\{name\}\}/g, manifest.name)
79
+ .replace(/\{\{slug\}\}/g, toSlug(canonical))
80
+ .replace(/\{\{native\}\}/g, toNativeSlug(native));
81
+ filtered[canonical] = resolved;
82
+ }
83
+ else {
84
+ filtered[canonical] = handler;
85
+ }
86
+ }
87
+ filteredManifest.hooks = filtered;
88
+ }
89
+ // Add target name to end of keywords if not already present
90
+ if (filteredManifest.keywords) {
91
+ const kw = [...filteredManifest.keywords];
92
+ if (!kw.includes(targetProfile.name)) {
93
+ kw.push(targetProfile.name);
94
+ }
95
+ filteredManifest.keywords = kw;
96
+ }
97
+ const adapter = getAdapter(targetProfile.name);
98
+ if (adapter) {
99
+ const adapterFiles = adapter.generateManifestFiles(sourceDir, filteredManifest, targetProfile, _diagnostics, manifest);
100
+ files.push(...adapterFiles);
101
+ }
102
+ // Generate package.json for npm-distributed targets that don't already have one
103
+ if ((targetProfile.distribution === 'npm-cli' || (targetProfile.distribution === 'both' && targetProfile.npmPublishable)) &&
104
+ !files.some(f => f.path === 'package.json')) {
105
+ const packageMetadata = targetProfile.packageMetadata ?? {};
106
+ const npmPkg = resolveTargetNpmPackageName(manifest, targetProfile);
107
+ const cliName = resolveTargetCliName(manifest, targetProfile);
108
+ const isEsm = packageMetadata.moduleType === 'module';
109
+ const ext = packageMetadata.binScriptExt ?? (isEsm ? '.cjs' : '.js');
110
+ const scripts = {
111
+ deploy: 'npm publish --access public',
112
+ 'deploy:staging': 'npm publish --access public --tag staging',
113
+ };
114
+ if (packageMetadata.installLifecycle === 'plugin-scripts') {
115
+ scripts['plugin:install'] = `node bin/install${ext} --global`;
116
+ scripts['plugin:uninstall'] = `node bin/uninstall${ext} --global`;
117
+ }
118
+ else if (packageMetadata.installLifecycle === 'postinstall') {
119
+ scripts.postinstall = `node bin/install${ext}`;
120
+ scripts.preuninstall = `node bin/uninstall${ext}`;
121
+ }
122
+ scripts['team:install'] = `node scripts/team-install${ext}`;
123
+ for (const [scriptName, scriptValue] of Object.entries(packageMetadata.extraScripts ?? {})) {
124
+ scripts[scriptName] = scriptValue;
125
+ }
126
+ const packageFiles = ['bin/', ...(packageMetadata.extraPackageFiles ?? [])];
127
+ packageFiles.push('hooks/', 'skills/', 'commands/', 'scripts/', 'plugin.json');
128
+ packageFiles.push('README.md', 'versions.json', 'package.json');
129
+ const pkgJson = {
130
+ name: npmPkg,
131
+ version: manifest.version,
132
+ description: manifest.description,
133
+ scripts,
134
+ bin: { [cliName]: `bin/cli${ext}` },
135
+ files: packageFiles,
136
+ keywords: [manifest.name, targetProfile.name, 'orchestration'],
137
+ author: manifest.author,
138
+ license: manifest.license,
139
+ publishConfig: { access: 'public' },
140
+ dependencies: { [sdkCfg.package]: manifest.version },
141
+ };
142
+ if (isEsm)
143
+ pkgJson.type = 'module';
144
+ if (manifest.repository) {
145
+ let repoUrl = typeof manifest.repository === 'string' ? manifest.repository : manifest.repository.url;
146
+ if (!repoUrl.startsWith('git+'))
147
+ repoUrl = `git+${repoUrl}`;
148
+ if (!repoUrl.endsWith('.git'))
149
+ repoUrl = `${repoUrl}.git`;
150
+ const directory = `plugins/${npmPkg.split('/').pop()}`;
151
+ const baseUrl = repoUrl.replace(/\.git$/, '').replace(/^git\+/, '');
152
+ pkgJson.repository = { type: 'git', url: repoUrl, directory };
153
+ pkgJson.homepage = `${baseUrl}/tree/main/${directory}#readme`;
154
+ pkgJson.bugs = { url: `${baseUrl}/issues` };
155
+ }
156
+ if (targetProfile.adapterFamily === 'programmatic') {
157
+ const peerPkg = packageMetadata.peerDependencyPackage;
158
+ if (peerPkg)
159
+ pkgJson.peerDependencies = { [peerPkg]: '*' };
160
+ }
161
+ files.push({ path: 'package.json', content: JSON.stringify(pkgJson, null, 2) + '\n' });
162
+ }
163
+ return files;
164
+ }
165
+ export function copyAgentFiles(sourceDir, manifest, targetProfile, _diagnostics) {
166
+ if (targetProfile.componentSupport?.agents !== 'native') {
167
+ return [];
168
+ }
169
+ if (getRequiredSurfaceFilename(targetProfile) === 'AGENTS.md') {
170
+ return [];
171
+ }
172
+ const content = resolveAgentSurfaceContent(sourceDir, manifest);
173
+ if (!content) {
174
+ return [];
175
+ }
176
+ return [{
177
+ path: 'AGENTS.md',
178
+ content,
179
+ }];
180
+ }
181
+ export function copyContextFiles(sourceDir, manifest, targetProfile, _diagnostics) {
182
+ const requiredFilename = getRequiredSurfaceFilename(targetProfile);
183
+ if (!requiredFilename) {
184
+ return [];
185
+ }
186
+ const contextPath = manifest.contextFiles?.[targetProfile.name]
187
+ ?? (targetProfile.name === 'gemini-cli' ? manifest.contextFiles?.gemini : undefined);
188
+ const declaredContextContent = contextPath ? readExistingTextFile(sourceDir, contextPath) : null;
189
+ const agentContent = resolveAgentSurfaceContent(sourceDir, manifest);
190
+ const content = declaredContextContent
191
+ ?? agentContent
192
+ ?? buildSurfaceFallback(manifest, targetProfile, requiredFilename);
193
+ return [{
194
+ path: toOutputPath(requiredFilename),
195
+ content,
196
+ }];
197
+ }
198
+ export function copyIncludedFiles(sourceDir, manifest, excludePatterns = []) {
199
+ const files = [];
200
+ if (!manifest.include || manifest.include.length === 0) {
201
+ return files;
202
+ }
203
+ for (const pattern of manifest.include) {
204
+ if (excludePatterns.some(ex => pattern === ex || pattern.startsWith(ex)))
205
+ continue;
206
+ if (!pattern.includes('*')) {
207
+ const fullPath = path.join(sourceDir, pattern);
208
+ if (fs.existsSync(fullPath)) {
209
+ const stat = fs.statSync(fullPath);
210
+ if (stat.isFile()) {
211
+ files.push({
212
+ path: toOutputPath(pattern),
213
+ content: fs.readFileSync(fullPath, 'utf-8'),
214
+ });
215
+ }
216
+ else if (stat.isDirectory()) {
217
+ collectDir(sourceDir, pattern, files);
218
+ }
219
+ }
220
+ continue;
221
+ }
222
+ // Simple *.ext glob in a directory
223
+ const dir = path.dirname(pattern);
224
+ const ext = path.extname(pattern);
225
+ const fullDir = path.join(sourceDir, dir);
226
+ if (fs.existsSync(fullDir) && fs.statSync(fullDir).isDirectory()) {
227
+ for (const entry of fs.readdirSync(fullDir)) {
228
+ if (ext && !entry.endsWith(ext))
229
+ continue;
230
+ const entryPath = toOutputPath(path.join(dir, entry));
231
+ const fullEntry = path.join(sourceDir, entryPath);
232
+ if (fs.statSync(fullEntry).isFile()) {
233
+ files.push({
234
+ path: entryPath,
235
+ content: fs.readFileSync(fullEntry, 'utf-8'),
236
+ });
237
+ }
238
+ }
239
+ }
240
+ }
241
+ return files;
242
+ }
243
+ export function collectDir(sourceDir, relDir, files) {
244
+ const fullDir = path.join(sourceDir, relDir);
245
+ for (const entry of fs.readdirSync(fullDir)) {
246
+ const relPath = toOutputPath(path.join(relDir, entry));
247
+ const fullPath = path.join(sourceDir, relPath);
248
+ const stat = fs.statSync(fullPath);
249
+ if (stat.isFile()) {
250
+ files.push({
251
+ path: relPath,
252
+ content: fs.readFileSync(fullPath, 'utf-8'),
253
+ });
254
+ }
255
+ else if (stat.isDirectory()) {
256
+ collectDir(sourceDir, relPath, files);
257
+ }
258
+ }
259
+ }
260
+ export function generateExtraFiles(sourceDir, manifest, targetProfile, _diagnostics) {
261
+ const files = [];
262
+ const sdkCfg = resolveSdkConfig(manifest);
263
+ // Generate programmatic extensions (Pi, oh-my-pi, and other programmatic targets)
264
+ if (targetProfile.adapterFamily === 'programmatic') {
265
+ const cmdPaths = getCommandPaths(sourceDir, manifest);
266
+ const extensionsContent = generateProgrammaticExtension(manifest, targetProfile, cmdPaths);
267
+ files.push({
268
+ path: 'extensions/index.ts',
269
+ content: extensionsContent,
270
+ });
271
+ }
272
+ // Generate CLI bin scripts for npm-cli distribution targets
273
+ if (targetProfile.distribution === 'npm-cli' || (targetProfile.distribution === 'both' && targetProfile.npmPublishable)) {
274
+ const packageMetadata = targetProfile.packageMetadata ?? {};
275
+ const isEsm = packageMetadata.moduleType === 'module';
276
+ const ext = packageMetadata.binScriptExt ?? (isEsm ? '.cjs' : '.js');
277
+ files.push({ path: `bin/cli${ext}`, content: generateCliBinScript(manifest, targetProfile), executable: true });
278
+ files.push({ path: `bin/install${ext}`, content: generateInstallScript(manifest, targetProfile), executable: true });
279
+ files.push({ path: `bin/uninstall${ext}`, content: generateUninstallScript(manifest, targetProfile), executable: true });
280
+ files.push({ path: `bin/install-shared${ext}`, content: generateInstallShared(manifest, targetProfile, sourceDir) });
281
+ files.push({ path: `scripts/team-install${ext}`, content: generateTeamInstall(manifest, targetProfile, ext), executable: true });
282
+ if (packageMetadata.emitCjsWrappers && ext !== '.cjs') {
283
+ files.push({ path: 'bin/cli.cjs', content: generateCjsWrapper('cli'), executable: true });
284
+ files.push({ path: 'bin/install.cjs', content: generateCjsWrapper('install'), executable: true });
285
+ files.push({ path: 'bin/uninstall.cjs', content: generateCjsWrapper('uninstall'), executable: true });
286
+ files.push({ path: 'bin/install-shared.cjs', content: generateCjsWrapper('install-shared', true) });
287
+ }
288
+ }
289
+ // Generate installation instructions for all targets
290
+ files.push({
291
+ path: 'README.md',
292
+ content: generateInstallInstructions(manifest, targetProfile, sourceDir),
293
+ });
294
+ // .gitignore
295
+ files.push({
296
+ path: '.gitignore',
297
+ content: `node_modules/\ndist/\n${sdkCfg.stateDir}/runs/\n${sdkCfg.stateDir}/logs/\n${sdkCfg.stateDir}/processes/\n${sdkCfg.stateDir}/artifacts/\n${sdkCfg.stateDir}/session.json\n${sdkCfg.stateDir}/current-run.json\n${sdkCfg.stateDir}/observer.json\n${sdkCfg.stateDir}/index/\n${sdkCfg.stateDir}/team/\n${sdkCfg.stateDir}/config/rules.local.json\n*.sqlite\n*.sqlite-shm\n*.sqlite-wal\n*.log\n.DS_Store\n`,
298
+ });
299
+ // Emit target-override extraFiles
300
+ const extraFiles = resolveExtraFiles(manifest, targetProfile);
301
+ if (Object.keys(extraFiles).length > 0) {
302
+ for (const [outputPath, value] of Object.entries(extraFiles)) {
303
+ if (value.startsWith('file:')) {
304
+ const srcPath = value.slice(5);
305
+ const fullPath = path.join(sourceDir, srcPath);
306
+ if (fs.existsSync(fullPath)) {
307
+ const isBinary = /\.(png|jpg|jpeg|gif|ico|woff2?|ttf|eot|svg|pdf)$/i.test(outputPath);
308
+ if (isBinary) {
309
+ files.push({
310
+ path: outputPath,
311
+ content: '',
312
+ binaryContent: fs.readFileSync(fullPath),
313
+ });
314
+ }
315
+ else {
316
+ files.push({
317
+ path: outputPath,
318
+ content: fs.readFileSync(fullPath, 'utf-8'),
319
+ });
320
+ }
321
+ }
322
+ }
323
+ else {
324
+ files.push({ path: outputPath, content: value });
325
+ }
326
+ }
327
+ }
328
+ if (manifest.postInstall) {
329
+ const postInstallPath = path.join(sourceDir, manifest.postInstall);
330
+ if (fs.existsSync(postInstallPath)) {
331
+ files.push({ path: 'scripts/post-install.js', content: fs.readFileSync(postInstallPath, 'utf-8'), executable: true });
332
+ }
333
+ }
334
+ const adapter = getAdapter(targetProfile.name);
335
+ if (adapter) {
336
+ const adapterExtraFiles = adapter.generateExtraTargetFiles(sourceDir, manifest, targetProfile, _diagnostics);
337
+ files.push(...adapterExtraFiles);
338
+ }
339
+ return files;
340
+ }
@@ -0,0 +1,13 @@
1
+ import type { A5cPluginManifest, TargetProfile } from './types.js';
2
+ export declare function resolveExtraFiles(manifest: A5cPluginManifest, targetProfile: TargetProfile): Record<string, string>;
3
+ export declare function resolveHarnessInstallSurfaceExports(manifest: A5cPluginManifest, targetProfile: TargetProfile): string[];
4
+ export declare function generatePs1Wrapper(hookSlug: string, adapterName: string, _sourceScript: string): string;
5
+ export declare function generateJsBridge(_name: string, shellScript: string, targetProfile: TargetProfile): string;
6
+ export declare function generateHarnessManifest(manifest: A5cPluginManifest, targetProfile: TargetProfile): string;
7
+ export declare function generateTeamInstall(manifest: A5cPluginManifest, _targetProfile: TargetProfile, ext?: string): string;
8
+ export declare function generateOpenClawNativeHooksSection(manifest: A5cPluginManifest, targetProfile: TargetProfile): Record<string, string>;
9
+ export declare function generateOpenCodeAccomplishSkill(manifest: A5cPluginManifest): string | null;
10
+ export declare function generateTsHookStub(nativeHook: string, nativeSlug: string, shellScriptName: string, targetProfile: TargetProfile): string;
11
+ export declare function generateGeminiPostinstall(pluginName: string): string;
12
+ export declare function generateGeminiPreuninstall(pluginName: string): string;
13
+ //# sourceMappingURL=transformHelpers.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transformHelpers.d.ts","sourceRoot":"","sources":["../src/transformHelpers.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAwBnE,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,GAC3B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAkBxB;AAED,wBAAgB,mCAAmC,CACjD,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,GAC3B,MAAM,EAAE,CAmBV;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,MAAM,GACpB,MAAM,CAcR;AAED,wBAAgB,gBAAgB,CAC9B,KAAK,EAAE,MAAM,EACb,WAAW,EAAE,MAAM,EACnB,aAAa,EAAE,aAAa,GAC3B,MAAM,CA4BR;AAED,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,GAC3B,MAAM,CAkBR;AAGD,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,iBAAiB,EAC3B,cAAc,EAAE,aAAa,EAC7B,GAAG,SAAQ,GACV,MAAM,CA0BR;AAED,wBAAgB,kCAAkC,CAChD,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,GAC3B,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAexB;AAED,wBAAgB,+BAA+B,CAC7C,QAAQ,EAAE,iBAAiB,GAC1B,MAAM,GAAG,IAAI,CAkBf;AAED,wBAAgB,kBAAkB,CAChC,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,eAAe,EAAE,MAAM,EACvB,aAAa,EAAE,aAAa,GAC3B,MAAM,CAyBR;AAED,wBAAgB,yBAAyB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAoBpE;AAED,wBAAgB,0BAA0B,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAiBrE"}
@@ -0,0 +1,239 @@
1
+ // Helper functions for the transform stage
2
+ // Extracted to keep transform.ts under the max-lines limit
3
+ function buildTemplateVars(manifest, targetProfile) {
4
+ const override = manifest.targets?.[targetProfile.name];
5
+ const overrideVars = override?.templateVars ?? {};
6
+ const targetDir = typeof overrideVars.targetDir === 'string' ? overrideVars.targetDir : targetProfile.name;
7
+ return {
8
+ target: targetProfile.name,
9
+ targetName: targetProfile.name,
10
+ targetDir,
11
+ ...overrideVars,
12
+ };
13
+ }
14
+ function interpolateTemplate(value, vars) {
15
+ return value.replace(/\{\{([a-zA-Z0-9_-]+)\}\}/g, (match, key) => vars[key] ?? match);
16
+ }
17
+ export function resolveExtraFiles(manifest, targetProfile) {
18
+ const override = manifest.targets?.[targetProfile.name];
19
+ const vars = buildTemplateVars(manifest, targetProfile);
20
+ const resolved = {};
21
+ for (const setName of override?.extraFileSets ?? []) {
22
+ const set = manifest.extraFileSets?.[setName];
23
+ if (!set)
24
+ continue;
25
+ for (const [outputPath, value] of Object.entries(set)) {
26
+ resolved[interpolateTemplate(outputPath, vars)] = interpolateTemplate(value, vars);
27
+ }
28
+ }
29
+ for (const [outputPath, value] of Object.entries(override?.extraFiles ?? {})) {
30
+ resolved[interpolateTemplate(outputPath, vars)] = interpolateTemplate(value, vars);
31
+ }
32
+ return resolved;
33
+ }
34
+ export function resolveHarnessInstallSurfaceExports(manifest, targetProfile) {
35
+ const override = manifest.targets?.[targetProfile.name];
36
+ const resolved = [];
37
+ const seen = new Set();
38
+ const addEntries = (entries) => {
39
+ if (!Array.isArray(entries))
40
+ return;
41
+ for (const entry of entries) {
42
+ if (typeof entry !== 'string' || seen.has(entry))
43
+ continue;
44
+ seen.add(entry);
45
+ resolved.push(entry);
46
+ }
47
+ };
48
+ for (const setName of override?.harnessInstallSurfaceExportSets ?? []) {
49
+ addEntries(manifest.harnessInstallSurfaceExportSets?.[setName]);
50
+ }
51
+ addEntries(override?.harnessInstallSurfaceExports);
52
+ return resolved;
53
+ }
54
+ export function generatePs1Wrapper(hookSlug, adapterName, _sourceScript) {
55
+ return `# PowerShell hook wrapper — sets env vars and delegates to bash
56
+ $env:HOOK_TYPE = '${hookSlug}'
57
+ $env:ADAPTER_NAME = '${adapterName}'
58
+ $env:PLUGIN_ROOT = Split-Path -Parent (Split-Path -Parent $PSScriptRoot)
59
+
60
+ $input_data = [Console]::In.ReadToEnd()
61
+ $result = $input_data | & bash "$PSScriptRoot/../$($MyInvocation.MyCommand.Name -replace '\\.ps1$','.sh')" 2>$null
62
+ if ($LASTEXITCODE -eq 0 -and $result) {
63
+ Write-Output $result
64
+ } else {
65
+ Write-Output '{}'
66
+ }
67
+ `;
68
+ }
69
+ export function generateJsBridge(_name, shellScript, targetProfile) {
70
+ const pluginRootEnvVar = targetProfile.pluginRootEnvVarForExtension || 'PLUGIN_ROOT';
71
+ const defaultAdapterName = targetProfile.adapterName;
72
+ return `#!/usr/bin/env node
73
+ "use strict";
74
+ var execSync = require("child_process").execSync;
75
+ var path = require("path");
76
+ var readFileSync = require("fs").readFileSync;
77
+
78
+ var PLUGIN_ROOT = process.env.${pluginRootEnvVar} || process.env.PLUGIN_ROOT || path.resolve(__dirname, "..");
79
+ var stdin = "";
80
+ try { stdin = readFileSync(0, "utf8"); } catch {}
81
+ try {
82
+ var result = execSync("bash " + JSON.stringify(path.join(PLUGIN_ROOT, "${shellScript}")), {
83
+ input: stdin,
84
+ stdio: ["pipe", "pipe", "pipe"],
85
+ timeout: 30000,
86
+ env: Object.assign({}, process.env, {
87
+ HOOK_TYPE: process.env.HOOK_TYPE || "",
88
+ ADAPTER_NAME: process.env.ADAPTER_NAME || "${defaultAdapterName}",
89
+ PLUGIN_ROOT: PLUGIN_ROOT
90
+ })
91
+ });
92
+ process.stdout.write(result);
93
+ } catch (e) {
94
+ process.stdout.write("{}\\n");
95
+ }
96
+ `;
97
+ }
98
+ export function generateHarnessManifest(manifest, targetProfile) {
99
+ const override = manifest.targets?.[targetProfile.name];
100
+ const base = {
101
+ name: manifest.name,
102
+ version: manifest.version,
103
+ description: manifest.description,
104
+ author: manifest.author,
105
+ license: manifest.license,
106
+ };
107
+ if (manifest.repository)
108
+ base.repository = manifest.repository;
109
+ if (manifest.keywords)
110
+ base.keywords = manifest.keywords;
111
+ if (override?.harnessManifest) {
112
+ Object.assign(base, override.harnessManifest);
113
+ }
114
+ return JSON.stringify(base, null, 2) + '\n';
115
+ }
116
+ export function generateTeamInstall(manifest, _targetProfile, ext = '.js') {
117
+ const sharedRequire = ext === '.js' ? '../bin/install-shared' : `../bin/install-shared${ext}`;
118
+ return `#!/usr/bin/env node
119
+ 'use strict';
120
+
121
+ var path = require('path');
122
+ var shared = require('${sharedRequire}');
123
+
124
+ var workspace = process.cwd();
125
+ for (var i = 0; i < process.argv.length; i++) {
126
+ if (process.argv[i] === '--workspace' && process.argv[i + 1]) {
127
+ workspace = path.resolve(process.argv[i + 1]);
128
+ }
129
+ }
130
+
131
+ var src = process.env.PLUGIN_PACKAGE_ROOT || path.resolve(__dirname, '..');
132
+ var dest = shared.getHomePluginRoot('workspace');
133
+ console.log('[${manifest.name}] Team install to ' + dest);
134
+
135
+ shared.copyPluginBundle(src, dest);
136
+ if (typeof shared.harnessTeamInstall === 'function') {
137
+ shared.harnessTeamInstall(src, dest, workspace);
138
+ }
139
+ shared.runPostInstall(dest);
140
+ console.log('[${manifest.name}] Team install complete.');
141
+ `;
142
+ }
143
+ export function generateOpenClawNativeHooksSection(manifest, targetProfile) {
144
+ const hooks = {};
145
+ if (manifest.hooks) {
146
+ for (const [canonicalHook, handlerPath] of Object.entries(manifest.hooks)) {
147
+ if (handlerPath === null)
148
+ continue;
149
+ const nativeHook = targetProfile.supportedHooks.get(canonicalHook);
150
+ if (nativeHook) {
151
+ hooks[nativeHook] = `extensions/hooks/${nativeHook.replace(/[._]/g, '-').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase()}.ts`;
152
+ }
153
+ }
154
+ }
155
+ return hooks;
156
+ }
157
+ export function generateOpenCodeAccomplishSkill(manifest) {
158
+ if (!manifest.skills || manifest.skills.length === 0)
159
+ return null;
160
+ const primarySkill = manifest.skills[0];
161
+ return `---
162
+ name: ${manifest.name}
163
+ description: ${manifest.description}
164
+ command: /${primarySkill.name}
165
+ verified: true
166
+ ---
167
+
168
+ # ${manifest.name}
169
+
170
+ ${manifest.description}
171
+
172
+ (This is a specialized accomplish-mode variant for OpenCode's accomplish workflow.)
173
+ `;
174
+ }
175
+ export function generateTsHookStub(nativeHook, nativeSlug, shellScriptName, targetProfile) {
176
+ const handlerName = nativeHook
177
+ .replace(/[._]([a-z])/g, (_, c) => c.toUpperCase())
178
+ + 'Handler';
179
+ return `/**
180
+ * ${targetProfile.displayName} ${nativeHook} hook — delegates to shell script.
181
+ */
182
+ import { execFileSync } from "node:child_process";
183
+ import { resolve, dirname } from "node:path";
184
+ import { fileURLToPath } from "node:url";
185
+
186
+ const __dirname = dirname(fileURLToPath(import.meta.url));
187
+ const PLUGIN_ROOT = resolve(__dirname, "../..");
188
+
189
+ export async function ${handlerName}(context: Record<string, unknown>): Promise<void> {
190
+ try {
191
+ execFileSync("bash", [resolve(PLUGIN_ROOT, "hooks/${shellScriptName}")], {
192
+ input: JSON.stringify(context),
193
+ stdio: ["pipe", "pipe", "pipe"],
194
+ timeout: 30000,
195
+ env: { ...process.env, ADAPTER_NAME: "${targetProfile.adapterName}", PLUGIN_ROOT },
196
+ });
197
+ } catch { /* best-effort */ }
198
+ }
199
+ `;
200
+ }
201
+ export function generateGeminiPostinstall(pluginName) {
202
+ return `#!/usr/bin/env node
203
+ 'use strict';
204
+ var path = require('path');
205
+ var spawnSync = require('child_process').spawnSync;
206
+ var fs = require('fs');
207
+
208
+ var PACKAGE_ROOT = path.resolve(__dirname, '..');
209
+ var extDir = path.join(require('os').homedir(), '.gemini', 'extensions', '${pluginName}');
210
+
211
+ if (!process.env.npm_config_global) process.exit(0);
212
+ try { if (fs.lstatSync(extDir).isSymbolicLink()) process.exit(0); } catch {}
213
+
214
+ try {
215
+ var result = spawnSync('gemini', ['extensions', 'install', PACKAGE_ROOT], { stdio: 'inherit', timeout: 60000 });
216
+ if (result.status === 0) process.exit(0);
217
+ } catch {}
218
+
219
+ console.log('[${pluginName}-gemini] Gemini CLI not found. Run: ${pluginName}-gemini install');
220
+ `;
221
+ }
222
+ export function generateGeminiPreuninstall(pluginName) {
223
+ return `#!/usr/bin/env node
224
+ 'use strict';
225
+ var path = require('path');
226
+ var spawnSync = require('child_process').spawnSync;
227
+ var fs = require('fs');
228
+
229
+ var extDir = path.join(require('os').homedir(), '.gemini', 'extensions', '${pluginName}');
230
+
231
+ try { if (!fs.existsSync(extDir) || fs.lstatSync(extDir).isSymbolicLink()) process.exit(0); } catch {}
232
+
233
+ try {
234
+ spawnSync('gemini', ['extensions', 'uninstall', '${pluginName}'], { stdio: 'inherit', timeout: 30000 });
235
+ } catch {
236
+ try { fs.rmSync(extDir, { recursive: true, force: true }); } catch {}
237
+ }
238
+ `;
239
+ }