mirror of
https://github.com/Termix-SSH/Termix.git
synced 2026-10-15 08:09:16 +00:00
* feat: AI translations at release, 7 new languages and regional fallback * fix: proper plural forms for count strings and full translations * fix: plural forms for selected, hidden and active counts * fix: synced plugin updates failing on desktop and server-only plugins shown as stopped * fix: restore rounded corners on app icons and favicon * feat: desktop app auto updates with automatic, ask first or never modes * feat: community and custom plugin registries * feat: plugin guide for AI tools in the SDK with a lint check * fix: keep the terminal WebSocket open past nginx's 60s default (#1588) * chore: update changelog * feat: show plugin download counts only and stop CI builds inflating them * feat: hide installed plugins in the browse tab by default * chore: pin bundled plugins to latest releases * chore: update translations * fix: focusing a saved password field and saving no longer erases it * fix: tell desktop users when their 2.8 data needs 2.9 first * fix: point windows update info at the x64 installer * fix: keep desktop client tunnel sockets alive behind proxies * chore: pin bundled plugins to latest releases * fix: cover client tunnel keepalive in the c2s runtime tests * fix: typing after opening a host no longer goes to the host search * fix: accept tab and = separators in SSH config import (#1598) * chore: update changelog * chore: drop plugin versions from core changelog * chore: update translations * chore: lint, format, and bump version to 26.10.1 --------- Co-authored-by: Darnel Hunter <68697450+innotelinc@users.noreply.github.com> Co-authored-by: Iain <Iain1970@protonmail.com>
118 lines
3.3 KiB
JavaScript
118 lines
3.3 KiB
JavaScript
#!/usr/bin/env node
|
|
/**
|
|
* packages/plugin-sdk/PLUGIN-GUIDE.md ships with the SDK and is what plugin
|
|
* authors and their AI tools read first. Fails when it misses a CLI command,
|
|
* a capability or an entry point, or when its header names an older SDK or
|
|
* plugin API version, so the guide is touched with every SDK release.
|
|
*/
|
|
|
|
const fs = require("node:fs");
|
|
const path = require("node:path");
|
|
|
|
const ROOT = path.resolve(__dirname, "..");
|
|
const SDK = path.join(ROOT, "packages", "plugin-sdk");
|
|
|
|
// Exports that are plumbing, not something a plugin author imports.
|
|
const INTERNAL_EXPORTS = new Set([
|
|
"./testing/setup",
|
|
"./testing-host",
|
|
"./tsconfig.plugin.json",
|
|
"./schema/manifest.schema.json",
|
|
"./theme.css",
|
|
]);
|
|
|
|
function cliCommands(source) {
|
|
const block = source.match(/const COMMANDS = \{([\s\S]*?)\n\};/);
|
|
if (!block) return [];
|
|
return [...block[1].matchAll(/^ {2}([a-z-]+)[:,]/gm)].map((m) => m[1]);
|
|
}
|
|
|
|
function capabilityIds(source) {
|
|
return [
|
|
...new Set(
|
|
[...source.matchAll(/entry\("([a-z-]+:[a-z-]+)"/g)].map((m) => m[1]),
|
|
),
|
|
];
|
|
}
|
|
|
|
function entryPoints(pkg) {
|
|
return Object.keys(pkg.exports ?? {})
|
|
.filter((key) => key !== "." && !INTERNAL_EXPORTS.has(key))
|
|
.map((key) => `@termix-ssh/plugin-sdk/${key.slice(2)}`);
|
|
}
|
|
|
|
function apiVersion(source) {
|
|
return source.match(/PLUGIN_API_VERSION = "([^"]+)"/)?.[1] ?? null;
|
|
}
|
|
|
|
function findProblems({
|
|
guide,
|
|
commands,
|
|
capabilities,
|
|
entries,
|
|
sdkVersion,
|
|
api,
|
|
}) {
|
|
const problems = [];
|
|
for (const command of commands) {
|
|
// `sign <file>` counts as well as `sign`.
|
|
if (!new RegExp(`\`${command}[\` ]`).test(guide))
|
|
problems.push(`CLI command "${command}" is not covered`);
|
|
}
|
|
for (const id of capabilities) {
|
|
if (!guide.includes(`\`${id}\``))
|
|
problems.push(`capability "${id}" is not covered`);
|
|
}
|
|
for (const entry of entries) {
|
|
if (!guide.includes(`\`${entry}\``))
|
|
problems.push(`entry point "${entry}" is not covered`);
|
|
}
|
|
const header = guide.match(/^SDK (\S+) \| Plugin API (\S+)$/m);
|
|
if (!header) {
|
|
problems.push('missing the "SDK x.y.z | Plugin API x.y.z" header line');
|
|
} else {
|
|
if (header[1] !== sdkVersion) {
|
|
problems.push(`header says SDK ${header[1]}, package is ${sdkVersion}`);
|
|
}
|
|
if (api && header[2] !== api) {
|
|
problems.push(`header says Plugin API ${header[2]}, SDK has ${api}`);
|
|
}
|
|
}
|
|
return problems;
|
|
}
|
|
|
|
function main() {
|
|
const read = (file) => fs.readFileSync(path.join(SDK, file), "utf8");
|
|
const pkg = JSON.parse(read("package.json"));
|
|
const problems = findProblems({
|
|
guide: read("PLUGIN-GUIDE.md"),
|
|
commands: cliCommands(read("cli/index.mjs")),
|
|
capabilities: capabilityIds(read("src/capabilities.ts")),
|
|
entries: entryPoints(pkg),
|
|
sdkVersion: pkg.version,
|
|
api: apiVersion(read("src/manifest.ts")),
|
|
});
|
|
if (!pkg.files?.includes("PLUGIN-GUIDE.md")) {
|
|
problems.push(
|
|
'"PLUGIN-GUIDE.md" is not in the SDK package.json files list',
|
|
);
|
|
}
|
|
if (problems.length > 0) {
|
|
console.error(
|
|
"check-sdk-guide: update packages/plugin-sdk/PLUGIN-GUIDE.md",
|
|
);
|
|
for (const problem of problems) console.error(` ${problem}`);
|
|
process.exit(1);
|
|
}
|
|
}
|
|
|
|
if (require.main === module) main();
|
|
|
|
module.exports = {
|
|
cliCommands,
|
|
capabilityIds,
|
|
entryPoints,
|
|
apiVersion,
|
|
findProblems,
|
|
};
|