@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.
- package/README.md +58 -0
- package/dist/binTemplates.d.ts +7 -0
- package/dist/binTemplates.d.ts.map +1 -0
- package/dist/binTemplates.js +292 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +299 -0
- package/dist/compiler.d.ts +15 -0
- package/dist/compiler.d.ts.map +1 -0
- package/dist/compiler.js +118 -0
- package/dist/diff.d.ts +9 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +183 -0
- package/dist/emit.d.ts +3 -0
- package/dist/emit.d.ts.map +1 -0
- package/dist/emit.js +42 -0
- package/dist/hookRegistration.d.ts +8 -0
- package/dist/hookRegistration.d.ts.map +1 -0
- package/dist/hookRegistration.js +9 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +13 -0
- package/dist/init.d.ts +17 -0
- package/dist/init.d.ts.map +1 -0
- package/dist/init.js +200 -0
- package/dist/installInstructions.d.ts +3 -0
- package/dist/installInstructions.d.ts.map +1 -0
- package/dist/installInstructions.js +150 -0
- package/dist/installSharedGenerator.d.ts +3 -0
- package/dist/installSharedGenerator.d.ts.map +1 -0
- package/dist/installSharedGenerator.js +229 -0
- package/dist/manifestGenerators.d.ts +10 -0
- package/dist/manifestGenerators.d.ts.map +1 -0
- package/dist/manifestGenerators.js +11 -0
- package/dist/marketplaceGenerator.d.ts +3 -0
- package/dist/marketplaceGenerator.d.ts.map +1 -0
- package/dist/marketplaceGenerator.js +46 -0
- package/dist/proxiedHookTemplates.d.ts +10 -0
- package/dist/proxiedHookTemplates.d.ts.map +1 -0
- package/dist/proxiedHookTemplates.js +122 -0
- package/dist/resolve.d.ts +3 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +106 -0
- package/dist/schema.d.ts +231 -0
- package/dist/schema.d.ts.map +1 -0
- package/dist/schema.js +340 -0
- package/dist/sdkConfig.d.ts +20 -0
- package/dist/sdkConfig.d.ts.map +1 -0
- package/dist/sdkConfig.js +41 -0
- package/dist/targets/adapters/base.d.ts +10 -0
- package/dist/targets/adapters/base.d.ts.map +1 -0
- package/dist/targets/adapters/base.js +16 -0
- package/dist/targets/adapters/claude-code.d.ts +9 -0
- package/dist/targets/adapters/claude-code.d.ts.map +1 -0
- package/dist/targets/adapters/claude-code.js +83 -0
- package/dist/targets/adapters/codex.d.ts +13 -0
- package/dist/targets/adapters/codex.d.ts.map +1 -0
- package/dist/targets/adapters/codex.js +103 -0
- package/dist/targets/adapters/cursor.d.ts +9 -0
- package/dist/targets/adapters/cursor.d.ts.map +1 -0
- package/dist/targets/adapters/cursor.js +57 -0
- package/dist/targets/adapters/gemini.d.ts +9 -0
- package/dist/targets/adapters/gemini.d.ts.map +1 -0
- package/dist/targets/adapters/gemini.js +86 -0
- package/dist/targets/adapters/github-copilot.d.ts +9 -0
- package/dist/targets/adapters/github-copilot.d.ts.map +1 -0
- package/dist/targets/adapters/github-copilot.js +61 -0
- package/dist/targets/adapters/hermes.d.ts +13 -0
- package/dist/targets/adapters/hermes.d.ts.map +1 -0
- package/dist/targets/adapters/hermes.js +96 -0
- package/dist/targets/adapters/hooks-utils.d.ts +12 -0
- package/dist/targets/adapters/hooks-utils.d.ts.map +1 -0
- package/dist/targets/adapters/hooks-utils.js +60 -0
- package/dist/targets/adapters/index.d.ts +27 -0
- package/dist/targets/adapters/index.d.ts.map +1 -0
- package/dist/targets/adapters/index.js +64 -0
- package/dist/targets/adapters/interface.d.ts +8 -0
- package/dist/targets/adapters/interface.d.ts.map +1 -0
- package/dist/targets/adapters/interface.js +2 -0
- package/dist/targets/adapters/oh-my-pi.d.ts +11 -0
- package/dist/targets/adapters/oh-my-pi.d.ts.map +1 -0
- package/dist/targets/adapters/oh-my-pi.js +88 -0
- package/dist/targets/adapters/openclaw.d.ts +14 -0
- package/dist/targets/adapters/openclaw.d.ts.map +1 -0
- package/dist/targets/adapters/openclaw.js +165 -0
- package/dist/targets/adapters/opencode.d.ts +10 -0
- package/dist/targets/adapters/opencode.d.ts.map +1 -0
- package/dist/targets/adapters/opencode.js +93 -0
- package/dist/targets/adapters/pi.d.ts +11 -0
- package/dist/targets/adapters/pi.d.ts.map +1 -0
- package/dist/targets/adapters/pi.js +90 -0
- package/dist/targets/index.d.ts +7 -0
- package/dist/targets/index.d.ts.map +1 -0
- package/dist/targets/index.js +77 -0
- package/dist/transform.d.ts +4 -0
- package/dist/transform.d.ts.map +1 -0
- package/dist/transform.js +243 -0
- package/dist/transformEmitters.d.ts +8 -0
- package/dist/transformEmitters.d.ts.map +1 -0
- package/dist/transformEmitters.js +340 -0
- package/dist/transformHelpers.d.ts +13 -0
- package/dist/transformHelpers.d.ts.map +1 -0
- package/dist/transformHelpers.js +239 -0
- package/dist/types.d.ts +204 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/utils.d.ts +42 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +187 -0
- package/dist/validate.d.ts +3 -0
- package/dist/validate.d.ts.map +1 -0
- package/dist/validate.js +188 -0
- package/dist/verify.d.ts +6 -0
- package/dist/verify.d.ts.map +1 -0
- package/dist/verify.js +294 -0
- package/package.json +68 -0
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// OpenCode harness output adapter
|
|
2
|
+
import { BaseHarnessOutputAdapter } from './base.js';
|
|
3
|
+
import { iterateHooks, slugify, applyPattern, resolveHookPath, getPattern, getJsPattern, resolveSdkConfig, } from './hooks-utils.js';
|
|
4
|
+
import { generateOpenCodeAccomplishSkill } from '../../transformHelpers.js';
|
|
5
|
+
export class OpenCodeAdapter extends BaseHarnessOutputAdapter {
|
|
6
|
+
generateHookRegistration(manifest, targetProfile, _diagnostics) {
|
|
7
|
+
const content = generateOpenCodeHooksJson(manifest, targetProfile);
|
|
8
|
+
return { path: targetProfile.hookRegistrationOutputPath || 'hooks/hooks.json', content };
|
|
9
|
+
}
|
|
10
|
+
generateManifestFiles(_sourceDir, manifest, _targetProfile, _diagnostics) {
|
|
11
|
+
const files = [];
|
|
12
|
+
files.push({
|
|
13
|
+
path: 'plugin.json',
|
|
14
|
+
content: generateOpenCodeManifest(manifest, this.targetName),
|
|
15
|
+
});
|
|
16
|
+
return files;
|
|
17
|
+
}
|
|
18
|
+
generateExtraTargetFiles(_sourceDir, manifest, _targetProfile, _diagnostics) {
|
|
19
|
+
const files = [];
|
|
20
|
+
const accomplishSkill = generateOpenCodeAccomplishSkill(manifest);
|
|
21
|
+
if (accomplishSkill) {
|
|
22
|
+
files.push({ path: `accomplish-skills/${manifest.name}/SKILL.md`, content: accomplishSkill });
|
|
23
|
+
}
|
|
24
|
+
return files;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
export function generateOpenCodeManifest(manifest, targetName = 'opencode') {
|
|
28
|
+
const pluginJson = {
|
|
29
|
+
name: manifest.name,
|
|
30
|
+
version: manifest.version,
|
|
31
|
+
description: manifest.description,
|
|
32
|
+
author: manifest.author,
|
|
33
|
+
license: manifest.license,
|
|
34
|
+
harness: targetName,
|
|
35
|
+
hooks: 'hooks/',
|
|
36
|
+
commands: 'commands/',
|
|
37
|
+
skills: 'skills/',
|
|
38
|
+
};
|
|
39
|
+
if (manifest.repository) {
|
|
40
|
+
pluginJson.repository = manifest.repository;
|
|
41
|
+
}
|
|
42
|
+
if (manifest.keywords) {
|
|
43
|
+
pluginJson.keywords = manifest.keywords;
|
|
44
|
+
}
|
|
45
|
+
return JSON.stringify(pluginJson, null, 2) + '\n';
|
|
46
|
+
}
|
|
47
|
+
export function generateOpenCodeHooksJson(manifest, targetProfile) {
|
|
48
|
+
const hooks = {};
|
|
49
|
+
const pat = getPattern(manifest, targetProfile.name);
|
|
50
|
+
const sdk = resolveSdkConfig(manifest);
|
|
51
|
+
iterateHooks(manifest, targetProfile, (canonical, native, handler) => {
|
|
52
|
+
const slug = slugify(canonical);
|
|
53
|
+
const adapter = targetProfile.adapterName;
|
|
54
|
+
if (handler === 'proxy') {
|
|
55
|
+
hooks[native] = [{
|
|
56
|
+
type: 'command',
|
|
57
|
+
command: `${sdk.proxyBinary} invoke --adapter ${adapter} --json`,
|
|
58
|
+
description: `${manifest.name} ${canonical} hook`,
|
|
59
|
+
timeoutMs: canonical === 'ShellEnv' ? 5000 : 30000,
|
|
60
|
+
}];
|
|
61
|
+
}
|
|
62
|
+
else if (handler === true) {
|
|
63
|
+
hooks[native] = [{
|
|
64
|
+
type: 'command',
|
|
65
|
+
command: `echo '{}'`,
|
|
66
|
+
description: `${manifest.name} ${canonical} hook`,
|
|
67
|
+
timeoutMs: canonical === 'ShellEnv' ? 5000 : 30000,
|
|
68
|
+
}];
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
const jsPat = getJsPattern(manifest, targetProfile.name);
|
|
72
|
+
let handlerScript;
|
|
73
|
+
if (jsPat) {
|
|
74
|
+
handlerScript = applyPattern(jsPat, manifest.name, slug, native);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
const p = resolveHookPath(handler, slug, manifest.name, native, pat);
|
|
78
|
+
handlerScript = p ? p.replace(/\.sh$/, '.js') : 'echo {}';
|
|
79
|
+
}
|
|
80
|
+
hooks[native] = [{
|
|
81
|
+
type: 'command',
|
|
82
|
+
script: `./${handlerScript}`,
|
|
83
|
+
description: `${manifest.name} ${canonical} hook`,
|
|
84
|
+
timeoutMs: canonical === 'ShellEnv' ? 5000 : 30000,
|
|
85
|
+
}];
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
return JSON.stringify({
|
|
89
|
+
version: 1,
|
|
90
|
+
description: `${manifest.name} hook registration for OpenCode.`,
|
|
91
|
+
hooks,
|
|
92
|
+
}, null, 2) + '\n';
|
|
93
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { A5cPluginManifest, TargetProfile, TransformedFile, Diagnostic } from '../../types.js';
|
|
2
|
+
import { BaseHarnessOutputAdapter } from './base.js';
|
|
3
|
+
export declare class PiAdapter extends BaseHarnessOutputAdapter {
|
|
4
|
+
generateManifestFiles(_sourceDir: string, manifest: A5cPluginManifest, _targetProfile: TargetProfile, _diagnostics: Diagnostic[]): TransformedFile[];
|
|
5
|
+
}
|
|
6
|
+
type ResolvedManifest = A5cPluginManifest & {
|
|
7
|
+
npmPackageName?: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function generatePiManifest(manifest: ResolvedManifest, targetName?: string): string;
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=pi.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pi.d.ts","sourceRoot":"","sources":["../../../src/targets/adapters/pi.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AACpG,OAAO,EAAE,wBAAwB,EAAE,MAAM,WAAW,CAAC;AAMrD,qBAAa,SAAU,SAAQ,wBAAwB;IAIrD,qBAAqB,CACnB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,iBAAiB,EAC3B,cAAc,EAAE,aAAa,EAC7B,YAAY,EAAE,UAAU,EAAE,GACzB,eAAe,EAAE;CAQrB;AAED,KAAK,gBAAgB,GAAG,iBAAiB,GAAG;IAC1C,cAAc,CAAC,EAAE,MAAM,CAAC;CACzB,CAAC;AAwCF,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,gBAAgB,EAAE,UAAU,SAAO,GAAG,MAAM,CA8CxF"}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Pi harness output adapter
|
|
2
|
+
import { BaseHarnessOutputAdapter } from './base.js';
|
|
3
|
+
import { resolveTargetCliName, resolveTargetNpmPackageName, } from '../../sdkConfig.js';
|
|
4
|
+
export class PiAdapter extends BaseHarnessOutputAdapter {
|
|
5
|
+
generateManifestFiles(_sourceDir, manifest, _targetProfile, _diagnostics) {
|
|
6
|
+
const files = [];
|
|
7
|
+
files.push({
|
|
8
|
+
path: 'package.json',
|
|
9
|
+
content: generatePiManifest(manifest, this.targetName),
|
|
10
|
+
});
|
|
11
|
+
return files;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
function buildNpmRepository(manifest, npmPackageName) {
|
|
15
|
+
if (!manifest.repository)
|
|
16
|
+
return undefined;
|
|
17
|
+
let url = typeof manifest.repository === 'string'
|
|
18
|
+
? manifest.repository
|
|
19
|
+
: manifest.repository.url;
|
|
20
|
+
if (!url.startsWith('git+'))
|
|
21
|
+
url = `git+${url}`;
|
|
22
|
+
if (!url.endsWith('.git'))
|
|
23
|
+
url = `${url}.git`;
|
|
24
|
+
const directory = `plugins/${npmPackageName.split('/').pop()}`;
|
|
25
|
+
return { type: 'git', url, directory };
|
|
26
|
+
}
|
|
27
|
+
function buildNpmHomepage(manifest, npmPackageName) {
|
|
28
|
+
if (!manifest.repository)
|
|
29
|
+
return undefined;
|
|
30
|
+
const url = typeof manifest.repository === 'string'
|
|
31
|
+
? manifest.repository
|
|
32
|
+
: manifest.repository.url;
|
|
33
|
+
const base = url.replace(/\.git$/, '').replace(/^git\+/, '');
|
|
34
|
+
const directory = `plugins/${npmPackageName.split('/').pop()}`;
|
|
35
|
+
return `${base}/tree/main/${directory}#readme`;
|
|
36
|
+
}
|
|
37
|
+
function buildNpmBugs(manifest) {
|
|
38
|
+
if (!manifest.repository)
|
|
39
|
+
return undefined;
|
|
40
|
+
const url = typeof manifest.repository === 'string'
|
|
41
|
+
? manifest.repository
|
|
42
|
+
: manifest.repository.url;
|
|
43
|
+
const base = url.replace(/\.git$/, '').replace(/^git\+/, '');
|
|
44
|
+
return { url: `${base}/issues` };
|
|
45
|
+
}
|
|
46
|
+
export function generatePiManifest(manifest, targetName = 'pi') {
|
|
47
|
+
const target = { name: targetName };
|
|
48
|
+
const packageJson = {
|
|
49
|
+
name: resolveTargetNpmPackageName(manifest, target),
|
|
50
|
+
version: manifest.version,
|
|
51
|
+
type: 'module',
|
|
52
|
+
description: `${manifest.description} — ${targetName}`,
|
|
53
|
+
keywords: [targetName, manifest.name, 'orchestration'],
|
|
54
|
+
[targetName]: {
|
|
55
|
+
extensions: ['./extensions'],
|
|
56
|
+
skills: ['./skills'],
|
|
57
|
+
},
|
|
58
|
+
peerDependencies: {
|
|
59
|
+
'@mariozechner/pi-coding-agent': '*',
|
|
60
|
+
},
|
|
61
|
+
scripts: {
|
|
62
|
+
test: 'npm run validate:ci',
|
|
63
|
+
'test:integration': 'node --test test/integration.test.js',
|
|
64
|
+
'test:packaged-install': 'node test/packaged-install.test.cjs',
|
|
65
|
+
'validate:ci': 'npm run test:integration && npm run test:packaged-install',
|
|
66
|
+
deploy: 'npm publish --access public',
|
|
67
|
+
'deploy:staging': 'npm publish --access public --tag staging',
|
|
68
|
+
},
|
|
69
|
+
bin: { [resolveTargetCliName(manifest, target)]: 'bin/cli.cjs' },
|
|
70
|
+
files: [
|
|
71
|
+
'bin/',
|
|
72
|
+
'package.json',
|
|
73
|
+
'versions.json',
|
|
74
|
+
'README.md',
|
|
75
|
+
'AGENTS.md',
|
|
76
|
+
'extensions/',
|
|
77
|
+
'skills/',
|
|
78
|
+
'commands/',
|
|
79
|
+
'scripts/',
|
|
80
|
+
],
|
|
81
|
+
author: typeof manifest.author === 'string' ? manifest.author : manifest.author.name,
|
|
82
|
+
license: manifest.license,
|
|
83
|
+
publishConfig: { access: 'public' },
|
|
84
|
+
};
|
|
85
|
+
const piPkgName = packageJson.name;
|
|
86
|
+
packageJson.repository = buildNpmRepository(manifest, piPkgName);
|
|
87
|
+
packageJson.homepage = buildNpmHomepage(manifest, piPkgName);
|
|
88
|
+
packageJson.bugs = buildNpmBugs(manifest);
|
|
89
|
+
return JSON.stringify(packageJson, null, 2) + '\n';
|
|
90
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { TargetProfile } from '../types.js';
|
|
2
|
+
export declare const TARGET_REGISTRY: Record<string, TargetProfile>;
|
|
3
|
+
export declare const HOOK_NAME_MAP: Record<string, Record<string, string>>;
|
|
4
|
+
export declare function getTargetProfile(name: string): TargetProfile | null;
|
|
5
|
+
export declare function requireTargetProfile(name: string): TargetProfile;
|
|
6
|
+
export declare function getAllTargets(): string[];
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/targets/index.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAiEjD,eAAO,MAAM,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,aAAa,CAEzD,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAoB,CAAC;AAEtF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,IAAI,CAGnE;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAMhE;AAED,wBAAgB,aAAa,IAAI,MAAM,EAAE,CAExC"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
// Catalog-backed target registry and hook name mapping
|
|
2
|
+
import { getHookNameMap, getPluginTargetDescriptor, listPluginTargetDescriptors, } from '@a5c-ai/agent-catalog';
|
|
3
|
+
function toManifestFormat(format) {
|
|
4
|
+
if (format === 'plugin.json')
|
|
5
|
+
return 'plugin.json';
|
|
6
|
+
if (format === 'state-only' || format.includes('package.json'))
|
|
7
|
+
return 'package.json';
|
|
8
|
+
return 'multiple';
|
|
9
|
+
}
|
|
10
|
+
function toCommandFormat(format) {
|
|
11
|
+
if (format === 'extension-manifest')
|
|
12
|
+
return 'toml';
|
|
13
|
+
if (format === 'none' || format === 'package-json commands')
|
|
14
|
+
return 'none';
|
|
15
|
+
return 'markdown';
|
|
16
|
+
}
|
|
17
|
+
function toHookRegistrationFormat(format) {
|
|
18
|
+
return format || null;
|
|
19
|
+
}
|
|
20
|
+
function toScriptVariants(variants) {
|
|
21
|
+
return (variants ?? []).filter((variant) => variant === 'bash' ||
|
|
22
|
+
variant === 'powershell' ||
|
|
23
|
+
variant === 'javascript' ||
|
|
24
|
+
variant === 'typescript');
|
|
25
|
+
}
|
|
26
|
+
function canonicalTargetName(name) {
|
|
27
|
+
// Try exact match first; if not found, check if any target's adapterName or cliCommand matches
|
|
28
|
+
if (getPluginTargetDescriptor(name))
|
|
29
|
+
return name;
|
|
30
|
+
for (const target of listPluginTargetDescriptors()) {
|
|
31
|
+
if (target.adapterName === name || target.cliCommand === name)
|
|
32
|
+
return target.targetId;
|
|
33
|
+
}
|
|
34
|
+
return name;
|
|
35
|
+
}
|
|
36
|
+
function toTargetProfile(target) {
|
|
37
|
+
return {
|
|
38
|
+
name: target.targetId,
|
|
39
|
+
displayName: target.displayName,
|
|
40
|
+
adapterName: target.adapterName,
|
|
41
|
+
pluginRootEnvVar: target.pluginRootEnvVar ?? null,
|
|
42
|
+
supportedHooks: new Map(Object.entries(target.supportedHooks)),
|
|
43
|
+
commandFormat: toCommandFormat(target.commandFormat),
|
|
44
|
+
skillHandling: target.skillHandling ?? 'none',
|
|
45
|
+
manifestFormat: toManifestFormat(target.manifestFormat),
|
|
46
|
+
hookRegistrationFormat: toHookRegistrationFormat(target.hookRegistrationFormat),
|
|
47
|
+
hookRegistrationOutputPath: target.hookRegistrationOutputPath ?? null,
|
|
48
|
+
hookRegistrationAliasPaths: target.hookRegistrationAliasPaths ?? [],
|
|
49
|
+
harnessManifestPath: target.harnessManifestPath ?? null,
|
|
50
|
+
requiredSurfaceFile: target.requiredSurfaceFile ?? null,
|
|
51
|
+
scriptVariants: toScriptVariants(target.scriptVariants),
|
|
52
|
+
npmPublishable: target.npmPublishable,
|
|
53
|
+
adapterFamily: target.adapterFamily ?? 'shell-hook',
|
|
54
|
+
distribution: target.distribution ?? 'marketplace',
|
|
55
|
+
pluginRootEnvVarForExtension: target.pluginRootEnvVarForExtension ?? undefined,
|
|
56
|
+
marketplacePath: target.marketplacePath,
|
|
57
|
+
installLayout: target.installLayout,
|
|
58
|
+
packageMetadata: target.packageMetadata,
|
|
59
|
+
componentSupport: target.componentSupport,
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
export const TARGET_REGISTRY = Object.fromEntries(listPluginTargetDescriptors().map((target) => [target.targetId, toTargetProfile(target)]));
|
|
63
|
+
export const HOOK_NAME_MAP = getHookNameMap();
|
|
64
|
+
export function getTargetProfile(name) {
|
|
65
|
+
const descriptor = getPluginTargetDescriptor(canonicalTargetName(name));
|
|
66
|
+
return descriptor ? toTargetProfile(descriptor) : null;
|
|
67
|
+
}
|
|
68
|
+
export function requireTargetProfile(name) {
|
|
69
|
+
const profile = getTargetProfile(name);
|
|
70
|
+
if (!profile) {
|
|
71
|
+
throw new Error(`Unknown target profile: ${name}`);
|
|
72
|
+
}
|
|
73
|
+
return profile;
|
|
74
|
+
}
|
|
75
|
+
export function getAllTargets() {
|
|
76
|
+
return listPluginTargetDescriptors().map((target) => target.targetId);
|
|
77
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { A5cPluginManifest, TargetProfile, TransformResult } from './types.js';
|
|
2
|
+
export declare function transform(sourceDir: string, manifest: A5cPluginManifest, targetProfile: TargetProfile): TransformResult;
|
|
3
|
+
export { getCommandPaths } from './utils.js';
|
|
4
|
+
//# sourceMappingURL=transform.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transform.d.ts","sourceRoot":"","sources":["../src/transform.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,iBAAiB,EACjB,aAAa,EACb,eAAe,EAGhB,MAAM,YAAY,CAAC;AA2BpB,wBAAgB,SAAS,CACvB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,GAC3B,eAAe,CAqCjB;AA2HD,OAAO,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
// Stage 3: TRANSFORM - Transform components to target format
|
|
2
|
+
import * as fs from 'fs';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import { buildSkillFromCommand, getCommandPaths, markdownToToml, } from './utils.js';
|
|
5
|
+
import { getAdapter } from './targets/adapters/index.js';
|
|
6
|
+
import { generatePs1Wrapper, generateJsBridge, generateTsHookStub, } from './transformHelpers.js';
|
|
7
|
+
import { generateManifests, copyAgentFiles, copyContextFiles, copyIncludedFiles, generateExtraFiles, } from './transformEmitters.js';
|
|
8
|
+
function toOutputPath(value) {
|
|
9
|
+
return value.replace(/\\/g, '/');
|
|
10
|
+
}
|
|
11
|
+
export function transform(sourceDir, manifest, targetProfile) {
|
|
12
|
+
const files = [];
|
|
13
|
+
const diagnostics = [];
|
|
14
|
+
// Transform commands
|
|
15
|
+
const commandFiles = transformCommands(sourceDir, manifest, targetProfile, diagnostics);
|
|
16
|
+
files.push(...commandFiles);
|
|
17
|
+
// Transform skills
|
|
18
|
+
const skillFiles = transformSkills(sourceDir, manifest, targetProfile, diagnostics);
|
|
19
|
+
files.push(...skillFiles);
|
|
20
|
+
// Transform hooks
|
|
21
|
+
const hookFiles = transformHooks(sourceDir, manifest, targetProfile, diagnostics);
|
|
22
|
+
files.push(...hookFiles);
|
|
23
|
+
// Generate manifests
|
|
24
|
+
const manifestFiles = generateManifests(sourceDir, manifest, targetProfile, diagnostics);
|
|
25
|
+
files.push(...manifestFiles);
|
|
26
|
+
// Copy agent instruction files
|
|
27
|
+
const agentFiles = copyAgentFiles(sourceDir, manifest, targetProfile, diagnostics);
|
|
28
|
+
files.push(...agentFiles);
|
|
29
|
+
// Copy context files
|
|
30
|
+
const contextFiles = copyContextFiles(sourceDir, manifest, targetProfile, diagnostics);
|
|
31
|
+
files.push(...contextFiles);
|
|
32
|
+
// Copy included files (versions.json, assets, etc.) — skip hooks/ since transformHooks handles those
|
|
33
|
+
const includedFiles = copyIncludedFiles(sourceDir, manifest, ['hooks/', 'hooks']);
|
|
34
|
+
files.push(...includedFiles);
|
|
35
|
+
// Generate extra files (Pi/oh-my-pi extensions, etc.)
|
|
36
|
+
const extraFiles = generateExtraFiles(sourceDir, manifest, targetProfile, diagnostics);
|
|
37
|
+
files.push(...extraFiles);
|
|
38
|
+
return { files, diagnostics };
|
|
39
|
+
}
|
|
40
|
+
function transformCommands(sourceDir, manifest, targetProfile, _diagnostics) {
|
|
41
|
+
const files = [];
|
|
42
|
+
if (targetProfile.commandFormat === 'none') {
|
|
43
|
+
return files;
|
|
44
|
+
}
|
|
45
|
+
if (!manifest.commands) {
|
|
46
|
+
return files;
|
|
47
|
+
}
|
|
48
|
+
const commandPaths = [];
|
|
49
|
+
if (typeof manifest.commands === 'string') {
|
|
50
|
+
// Directory path - glob all .md files
|
|
51
|
+
const commandDir = path.join(sourceDir, manifest.commands);
|
|
52
|
+
if (fs.existsSync(commandDir)) {
|
|
53
|
+
const entries = fs.readdirSync(commandDir);
|
|
54
|
+
for (const entry of entries) {
|
|
55
|
+
if (entry.endsWith('.md')) {
|
|
56
|
+
commandPaths.push(toOutputPath(path.join(manifest.commands, entry)));
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
commandPaths.push(...manifest.commands.map(toOutputPath));
|
|
63
|
+
}
|
|
64
|
+
for (const cmdPath of commandPaths) {
|
|
65
|
+
const fullPath = path.join(sourceDir, cmdPath);
|
|
66
|
+
if (!fs.existsSync(fullPath)) {
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
70
|
+
if (targetProfile.commandFormat === 'toml') {
|
|
71
|
+
// Convert to TOML (Gemini)
|
|
72
|
+
const tomlContent = markdownToToml(content);
|
|
73
|
+
const basename = path.basename(cmdPath, '.md');
|
|
74
|
+
files.push({
|
|
75
|
+
path: `commands/${basename}.toml`,
|
|
76
|
+
content: tomlContent,
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
else {
|
|
80
|
+
// Copy as-is (Markdown)
|
|
81
|
+
files.push({
|
|
82
|
+
path: cmdPath,
|
|
83
|
+
content,
|
|
84
|
+
});
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return files;
|
|
88
|
+
}
|
|
89
|
+
function transformSkills(sourceDir, manifest, targetProfile, _diagnostics) {
|
|
90
|
+
const files = [];
|
|
91
|
+
if (targetProfile.skillHandling === 'none') {
|
|
92
|
+
return files;
|
|
93
|
+
}
|
|
94
|
+
// Always copy standalone skills
|
|
95
|
+
if (manifest.skills && Array.isArray(manifest.skills)) {
|
|
96
|
+
for (const skill of manifest.skills) {
|
|
97
|
+
const fullPath = path.join(sourceDir, skill.file);
|
|
98
|
+
if (fs.existsSync(fullPath)) {
|
|
99
|
+
files.push({
|
|
100
|
+
path: skill.file,
|
|
101
|
+
content: fs.readFileSync(fullPath, 'utf-8'),
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
// Derive skills from commands if needed
|
|
107
|
+
if (targetProfile.skillHandling === 'derived-from-commands') {
|
|
108
|
+
const commandPaths = getCommandPaths(sourceDir, manifest);
|
|
109
|
+
// Build set of standalone skill names to avoid duplicating them
|
|
110
|
+
const standaloneSkillNames = new Set();
|
|
111
|
+
if (manifest.skills && Array.isArray(manifest.skills)) {
|
|
112
|
+
for (const skill of manifest.skills) {
|
|
113
|
+
standaloneSkillNames.add(skill.name);
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
for (const cmdPath of commandPaths) {
|
|
117
|
+
const fullPath = path.join(sourceDir, cmdPath);
|
|
118
|
+
if (!fs.existsSync(fullPath))
|
|
119
|
+
continue;
|
|
120
|
+
const basename = path.basename(cmdPath, '.md');
|
|
121
|
+
if (standaloneSkillNames.has(basename)) {
|
|
122
|
+
continue;
|
|
123
|
+
}
|
|
124
|
+
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
125
|
+
const derivedSkill = buildSkillFromCommand(basename, content);
|
|
126
|
+
files.push({
|
|
127
|
+
path: `skills/${basename}/SKILL.md`,
|
|
128
|
+
content: derivedSkill,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return files;
|
|
133
|
+
}
|
|
134
|
+
// Re-export for backward compatibility
|
|
135
|
+
export { getCommandPaths } from './utils.js';
|
|
136
|
+
function transformHooks(sourceDir, manifest, targetProfile, diagnostics) {
|
|
137
|
+
const files = [];
|
|
138
|
+
if (!manifest.hooks || targetProfile.supportedHooks.size === 0) {
|
|
139
|
+
return files;
|
|
140
|
+
}
|
|
141
|
+
const isProgrammatic = targetProfile.adapterFamily === 'programmatic';
|
|
142
|
+
const override = manifest.targets?.[targetProfile.name];
|
|
143
|
+
const hookFilePattern = typeof override?.hookFilePattern === 'string'
|
|
144
|
+
? override.hookFilePattern
|
|
145
|
+
: typeof manifest.hookFilePattern === 'string' ? manifest.hookFilePattern : undefined;
|
|
146
|
+
const hookJsPattern = typeof override?.hookJsPattern === 'string'
|
|
147
|
+
? override.hookJsPattern
|
|
148
|
+
: hookFilePattern ? hookFilePattern.replace(/\.sh$/, '.js') : undefined;
|
|
149
|
+
const toSlug = (s) => s
|
|
150
|
+
.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
|
|
151
|
+
.replace(/[^a-z0-9]+/g, '-').replace(/^-+|-+$/g, '');
|
|
152
|
+
const toNativeSlug = (s) => s.replace(/[._]/g, '-').replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase();
|
|
153
|
+
for (const [canonicalHook, handlerValue] of Object.entries(manifest.hooks)) {
|
|
154
|
+
if (handlerValue === null)
|
|
155
|
+
continue;
|
|
156
|
+
const nativeHook = targetProfile.supportedHooks.get(canonicalHook);
|
|
157
|
+
if (!nativeHook)
|
|
158
|
+
continue;
|
|
159
|
+
if (typeof handlerValue !== 'string' || handlerValue === 'proxy')
|
|
160
|
+
continue;
|
|
161
|
+
const hookSlug = toSlug(canonicalHook);
|
|
162
|
+
const nativeSlug = toNativeSlug(nativeHook);
|
|
163
|
+
const sourceScript = path.join(sourceDir, handlerValue);
|
|
164
|
+
if (!fs.existsSync(sourceScript))
|
|
165
|
+
continue;
|
|
166
|
+
const rawContent = fs.readFileSync(sourceScript, 'utf-8');
|
|
167
|
+
const content = rawContent.replace(/ADAPTER_NAME="\$\{ADAPTER_NAME:\?[^}]*\}"/, `ADAPTER_NAME="\${ADAPTER_NAME:-${targetProfile.adapterName}}"`);
|
|
168
|
+
// Determine bash output filename via hookFilePattern
|
|
169
|
+
let outName;
|
|
170
|
+
if (hookFilePattern) {
|
|
171
|
+
outName = hookFilePattern
|
|
172
|
+
.replace(/\{\{name\}\}/g, manifest.name)
|
|
173
|
+
.replace(/\{\{slug\}\}/g, hookSlug)
|
|
174
|
+
.replace(/\{\{native\}\}/g, nativeSlug);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
outName = path.basename(handlerValue);
|
|
178
|
+
}
|
|
179
|
+
files.push({ path: `hooks/${outName}`, content, executable: true });
|
|
180
|
+
if (targetProfile.scriptVariants.includes('powershell')) {
|
|
181
|
+
const ps1Name = outName.replace(/\.sh$/, '.ps1');
|
|
182
|
+
files.push({ path: `hooks/${ps1Name}`, content: generatePs1Wrapper(hookSlug, targetProfile.adapterName, handlerValue) });
|
|
183
|
+
}
|
|
184
|
+
// JS bridge for programmatic targets — uses hookJsPattern if available
|
|
185
|
+
if (isProgrammatic) {
|
|
186
|
+
let jsName;
|
|
187
|
+
if (hookJsPattern) {
|
|
188
|
+
jsName = hookJsPattern
|
|
189
|
+
.replace(/\{\{name\}\}/g, manifest.name)
|
|
190
|
+
.replace(/\{\{slug\}\}/g, hookSlug)
|
|
191
|
+
.replace(/\{\{native\}\}/g, nativeSlug);
|
|
192
|
+
}
|
|
193
|
+
else {
|
|
194
|
+
jsName = outName.replace(/\.sh$/, '.js');
|
|
195
|
+
}
|
|
196
|
+
files.push({ path: `hooks/${jsName}`, content: generateJsBridge(jsName.replace(/\.js$/, ''), handlerValue, targetProfile), executable: true });
|
|
197
|
+
}
|
|
198
|
+
// TS hook stubs for targets with typescript variant (openclaw)
|
|
199
|
+
if (targetProfile.scriptVariants.includes('typescript')) {
|
|
200
|
+
const tsName = `${nativeSlug}.ts`;
|
|
201
|
+
files.push({
|
|
202
|
+
path: `extensions/hooks/${tsName}`,
|
|
203
|
+
content: generateTsHookStub(nativeHook, nativeSlug, outName, targetProfile),
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// Emit Stop hook script for programmatic targets that declare Stop in the
|
|
208
|
+
// manifest but don't list it in supportedHooks (e.g. openclaw).
|
|
209
|
+
if (targetProfile.adapterFamily === 'programmatic' && typeof manifest.hooks?.Stop === 'string' && !targetProfile.supportedHooks.has('Stop')) {
|
|
210
|
+
const stopSource = path.join(sourceDir, manifest.hooks.Stop);
|
|
211
|
+
if (fs.existsSync(stopSource)) {
|
|
212
|
+
const rawContent = fs.readFileSync(stopSource, 'utf-8');
|
|
213
|
+
const content = rawContent.replace(/ADAPTER_NAME="\$\{ADAPTER_NAME:\?[^}]*\}"/, `ADAPTER_NAME="\${ADAPTER_NAME:-${targetProfile.adapterName}}"`);
|
|
214
|
+
const stopOutName = hookFilePattern
|
|
215
|
+
? hookFilePattern
|
|
216
|
+
.replace(/\{\{name\}\}/g, manifest.name)
|
|
217
|
+
.replace(/\{\{slug\}\}/g, toSlug('Stop'))
|
|
218
|
+
.replace(/\{\{native\}\}/g, 'stop-hook')
|
|
219
|
+
: path.basename(manifest.hooks.Stop);
|
|
220
|
+
const stopPath = `hooks/${stopOutName}`;
|
|
221
|
+
if (!files.some((file) => file.path === stopPath)) {
|
|
222
|
+
files.push({ path: stopPath, content, executable: true });
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
// Generate hook registration file for shell-hook targets
|
|
227
|
+
if (targetProfile.hookRegistrationFormat) {
|
|
228
|
+
const hookRegFile = generateHookRegistrationFile(manifest, targetProfile, diagnostics);
|
|
229
|
+
if (hookRegFile) {
|
|
230
|
+
files.push(hookRegFile);
|
|
231
|
+
for (const aliasPath of targetProfile.hookRegistrationAliasPaths) {
|
|
232
|
+
files.push({ path: aliasPath, content: hookRegFile.content });
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
return files;
|
|
237
|
+
}
|
|
238
|
+
function generateHookRegistrationFile(manifest, targetProfile, diagnostics) {
|
|
239
|
+
const adapter = getAdapter(targetProfile.name);
|
|
240
|
+
if (!adapter)
|
|
241
|
+
return null;
|
|
242
|
+
return adapter.generateHookRegistration(manifest, targetProfile, diagnostics);
|
|
243
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { A5cPluginManifest, TargetProfile, TransformedFile, Diagnostic } from './types.js';
|
|
2
|
+
export declare function generateManifests(sourceDir: string, manifest: A5cPluginManifest, targetProfile: TargetProfile, _diagnostics: Diagnostic[]): TransformedFile[];
|
|
3
|
+
export declare function copyAgentFiles(sourceDir: string, manifest: A5cPluginManifest, targetProfile: TargetProfile, _diagnostics: Diagnostic[]): TransformedFile[];
|
|
4
|
+
export declare function copyContextFiles(sourceDir: string, manifest: A5cPluginManifest, targetProfile: TargetProfile, _diagnostics: Diagnostic[]): TransformedFile[];
|
|
5
|
+
export declare function copyIncludedFiles(sourceDir: string, manifest: A5cPluginManifest, excludePatterns?: string[]): TransformedFile[];
|
|
6
|
+
export declare function collectDir(sourceDir: string, relDir: string, files: TransformedFile[]): void;
|
|
7
|
+
export declare function generateExtraFiles(sourceDir: string, manifest: A5cPluginManifest, targetProfile: TargetProfile, _diagnostics: Diagnostic[]): TransformedFile[];
|
|
8
|
+
//# sourceMappingURL=transformEmitters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"transformEmitters.d.ts","sourceRoot":"","sources":["../src/transformEmitters.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,iBAAiB,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,YAAY,CAAC;AA8EhG,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,UAAU,EAAE,GACzB,eAAe,EAAE,CA2GnB;AAED,wBAAgB,cAAc,CAC5B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,UAAU,EAAE,GACzB,eAAe,EAAE,CAkBnB;AAED,wBAAgB,gBAAgB,CAC9B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,UAAU,EAAE,GACzB,eAAe,EAAE,CAkBnB;AAED,wBAAgB,iBAAiB,CAC/B,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,iBAAiB,EAC3B,eAAe,GAAE,MAAM,EAAO,GAC7B,eAAe,EAAE,CA8CnB;AAED,wBAAgB,UAAU,CACxB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,eAAe,EAAE,GACvB,IAAI,CAeN;AAED,wBAAgB,kBAAkB,CAChC,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,iBAAiB,EAC3B,aAAa,EAAE,aAAa,EAC5B,YAAY,EAAE,UAAU,EAAE,GACzB,eAAe,EAAE,CAmFnB"}
|