mirror of
https://github.com/elder-plinius/P4RS3LT0NGV3.git
synced 2026-07-12 15:36:32 +02:00
add uv-powered agent cli
This commit is contained in:
@@ -0,0 +1,217 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const vm = require('vm');
|
||||
|
||||
const projectRoot = path.join(__dirname, '..');
|
||||
const transformsRoot = path.join(projectRoot, 'src', 'transformers');
|
||||
const transforms = require(path.join(projectRoot, 'src', 'transformers', 'loader-node.js'));
|
||||
|
||||
function buildRegistry() {
|
||||
const skipFiles = new Set(['BaseTransformer.js', 'index.js', 'loader-node.js', 'README.md']);
|
||||
const categories = fs.readdirSync(transformsRoot, { withFileTypes: true })
|
||||
.filter((entry) => entry.isDirectory())
|
||||
.map((entry) => entry.name)
|
||||
.sort();
|
||||
|
||||
const registry = [];
|
||||
for (const category of categories) {
|
||||
const categoryPath = path.join(transformsRoot, category);
|
||||
const files = fs.readdirSync(categoryPath)
|
||||
.filter((file) => file.endsWith('.js') && !skipFiles.has(file))
|
||||
.sort();
|
||||
|
||||
for (const file of files) {
|
||||
const key = file.replace('.js', '').replace(/-/g, '_');
|
||||
const transform = transforms[key];
|
||||
if (!transform) {
|
||||
continue;
|
||||
}
|
||||
|
||||
registry.push({
|
||||
key,
|
||||
category,
|
||||
name: transform.name,
|
||||
priority: transform.priority ?? 0,
|
||||
canDecode: Boolean(transform.reverse),
|
||||
description: transform.description || '',
|
||||
inputKind: transform.inputKind || 'textarea',
|
||||
configurableOptions: (transform.configurableOptions || []).map((opt) => ({
|
||||
id: opt.id,
|
||||
label: opt.label,
|
||||
type: opt.type,
|
||||
default: opt.default,
|
||||
min: opt.min,
|
||||
max: opt.max,
|
||||
step: opt.step,
|
||||
options: opt.options || undefined
|
||||
}))
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return registry;
|
||||
}
|
||||
|
||||
function getDefaultOptions(transform) {
|
||||
if (!transform || !transform.configurableOptions || !transform.configurableOptions.length) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const defaults = {};
|
||||
for (const opt of transform.configurableOptions) {
|
||||
let value = opt.default;
|
||||
if (value === undefined || value === null) {
|
||||
if (opt.type === 'boolean') {
|
||||
value = false;
|
||||
} else if (opt.type === 'select' && opt.options && opt.options.length) {
|
||||
value = opt.options[0].value;
|
||||
} else if (opt.type === 'number') {
|
||||
value = 0;
|
||||
} else {
|
||||
value = '';
|
||||
}
|
||||
}
|
||||
defaults[opt.id] = value;
|
||||
}
|
||||
|
||||
return defaults;
|
||||
}
|
||||
|
||||
function loadUniversalDecoder() {
|
||||
const transformOptionsCode = fs.readFileSync(path.join(projectRoot, 'js', 'core', 'transformOptions.js'), 'utf8');
|
||||
const decoderCode = fs.readFileSync(path.join(projectRoot, 'js', 'core', 'decoder.js'), 'utf8');
|
||||
const emojiWordMapCode = fs.readFileSync(path.join(projectRoot, 'src', 'emojiWordMap.js'), 'utf8');
|
||||
const emojiUtilsCode = fs.readFileSync(path.join(projectRoot, 'js', 'utils', 'emoji.js'), 'utf8');
|
||||
|
||||
const mockSteganography = {
|
||||
hasEmojiInText: () => false,
|
||||
decodeEmoji: () => null,
|
||||
decodeInvisible: () => null
|
||||
};
|
||||
|
||||
const sandbox = {
|
||||
window: {
|
||||
transforms,
|
||||
steganography: mockSteganography,
|
||||
emojiLibrary: {},
|
||||
emojiKeywords: {},
|
||||
emojiData: {}
|
||||
},
|
||||
console,
|
||||
TextEncoder,
|
||||
TextDecoder,
|
||||
Intl,
|
||||
btoa: (str) => Buffer.from(str, 'binary').toString('base64'),
|
||||
atob: (str) => Buffer.from(str, 'base64').toString('binary')
|
||||
};
|
||||
|
||||
vm.createContext(sandbox);
|
||||
vm.runInContext(emojiUtilsCode, sandbox);
|
||||
vm.runInContext(emojiWordMapCode, sandbox);
|
||||
vm.runInContext(transformOptionsCode, sandbox);
|
||||
vm.runInContext(decoderCode, sandbox);
|
||||
|
||||
return sandbox.universalDecode;
|
||||
}
|
||||
|
||||
function normalizeError(error) {
|
||||
if (error && typeof error.message === 'string') {
|
||||
return error.message;
|
||||
}
|
||||
return String(error);
|
||||
}
|
||||
|
||||
function readPayload() {
|
||||
const raw = fs.readFileSync(0, 'utf8');
|
||||
return raw ? JSON.parse(raw) : {};
|
||||
}
|
||||
|
||||
function writeResult(result, exitCode = 0) {
|
||||
process.stdout.write(`${JSON.stringify(result)}\n`);
|
||||
process.exit(exitCode);
|
||||
}
|
||||
|
||||
function main() {
|
||||
const payload = readPayload();
|
||||
const command = payload.command;
|
||||
const registry = buildRegistry();
|
||||
|
||||
if (command === 'list') {
|
||||
writeResult({ ok: true, transforms: registry });
|
||||
}
|
||||
|
||||
const transformKey = payload.transform;
|
||||
const transform = transformKey ? transforms[transformKey] : null;
|
||||
|
||||
if (command === 'inspect') {
|
||||
if (!transform || !transformKey) {
|
||||
writeResult({ ok: false, error: `Unknown transform: ${transformKey}` }, 1);
|
||||
}
|
||||
|
||||
const meta = registry.find((entry) => entry.key === transformKey);
|
||||
writeResult({
|
||||
ok: true,
|
||||
transform: {
|
||||
...meta,
|
||||
defaultOptions: getDefaultOptions(transform)
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (command === 'run') {
|
||||
if (!transform || !transformKey) {
|
||||
writeResult({ ok: false, error: `Unknown transform: ${transformKey}` }, 1);
|
||||
}
|
||||
|
||||
const action = payload.action || 'encode';
|
||||
const text = payload.text || '';
|
||||
const options = {
|
||||
...getDefaultOptions(transform),
|
||||
...(payload.options || {})
|
||||
};
|
||||
|
||||
try {
|
||||
let output;
|
||||
if (action === 'encode') {
|
||||
output = transform.func(text, options);
|
||||
} else if (action === 'decode') {
|
||||
if (!transform.reverse) {
|
||||
throw new Error(`${transform.name} does not support decode`);
|
||||
}
|
||||
output = transform.reverse(text, options);
|
||||
} else if (action === 'preview') {
|
||||
output = transform.preview(text, options);
|
||||
} else {
|
||||
throw new Error(`Unsupported action: ${action}`);
|
||||
}
|
||||
|
||||
writeResult({
|
||||
ok: true,
|
||||
action,
|
||||
transform: transformKey,
|
||||
name: transform.name,
|
||||
options,
|
||||
output
|
||||
});
|
||||
} catch (error) {
|
||||
writeResult({ ok: false, error: normalizeError(error) }, 1);
|
||||
}
|
||||
}
|
||||
|
||||
if (command === 'auto-decode') {
|
||||
const decode = loadUniversalDecoder();
|
||||
try {
|
||||
const result = decode(payload.text || '', {});
|
||||
writeResult({ ok: true, result });
|
||||
} catch (error) {
|
||||
writeResult({ ok: false, error: normalizeError(error) }, 1);
|
||||
}
|
||||
}
|
||||
|
||||
writeResult({ ok: false, error: `Unknown command: ${command}` }, 1);
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
Reference in New Issue
Block a user