feat: initial commit - Jhonny Editor
- Adicionado estrutura completa do projeto - Configurado MCP server para Premiere Pro - Adicionado documentação e skills - Configurado Gitignore para o projeto
This commit is contained in:
@@ -0,0 +1,176 @@
|
||||
import { readFile, writeFile } from "node:fs/promises";
|
||||
import { resolve } from "node:path";
|
||||
import { pathToFileURL } from "node:url";
|
||||
import { Client, InMemoryTransport } from "@modelcontextprotocol/client";
|
||||
import { createServer } from "../dist/server.js";
|
||||
|
||||
const DEFAULT_CAPABILITIES = "inspect,edit,export,filesystem";
|
||||
const FULL_CAPABILITIES = `${DEFAULT_CAPABILITIES},unsafe-script`;
|
||||
const OUTPUT_PATH = resolve("docs/supported-actions.md");
|
||||
|
||||
const disabledTelemetry = {
|
||||
enabled: false,
|
||||
capture() {},
|
||||
async shutdown() {},
|
||||
};
|
||||
|
||||
const mockUxpBridge = {
|
||||
async request() {
|
||||
return {};
|
||||
},
|
||||
getState() {
|
||||
return { status: "connected", connected: true };
|
||||
},
|
||||
};
|
||||
|
||||
async function collectRegisteredTools(capabilities, includeUxp) {
|
||||
const previousCapabilities = process.env.PREMIERE_MCP_CAPABILITIES;
|
||||
process.env.PREMIERE_MCP_CAPABILITIES = capabilities;
|
||||
const server = createServer({}, {
|
||||
telemetry: disabledTelemetry,
|
||||
...(includeUxp ? { uxpBridge: mockUxpBridge } : {}),
|
||||
});
|
||||
const client = new Client({ name: "supported-actions-generator", version: "1.0.0" });
|
||||
const [clientTransport, serverTransport] = InMemoryTransport.createLinkedPair();
|
||||
|
||||
try {
|
||||
await Promise.all([server.connect(serverTransport), client.connect(clientTransport)]);
|
||||
const tools = [];
|
||||
let cursor;
|
||||
do {
|
||||
const response = await client.listTools(cursor ? { cursor } : undefined);
|
||||
tools.push(...response.tools);
|
||||
cursor = response.nextCursor;
|
||||
} while (cursor);
|
||||
return tools.sort((left, right) => left.name.localeCompare(right.name));
|
||||
} finally {
|
||||
await client.close();
|
||||
await server.close();
|
||||
if (previousCapabilities === undefined) delete process.env.PREMIERE_MCP_CAPABILITIES;
|
||||
else process.env.PREMIERE_MCP_CAPABILITIES = previousCapabilities;
|
||||
}
|
||||
}
|
||||
|
||||
function escapeCell(value) {
|
||||
return String(value ?? "")
|
||||
.replace(/\s+/g, " ")
|
||||
.trim()
|
||||
.replaceAll("|", "\\|");
|
||||
}
|
||||
|
||||
function code(value) {
|
||||
return `\`${String(value).replaceAll("`", "\\`")}\``;
|
||||
}
|
||||
|
||||
function renderModes(tool) {
|
||||
const properties = tool.inputSchema?.properties ?? {};
|
||||
const actionValues = properties.action?.enum;
|
||||
if (Array.isArray(actionValues) && actionValues.length > 0) {
|
||||
return actionValues.map(code).join(", ");
|
||||
}
|
||||
|
||||
const modeGroups = Object.entries(properties)
|
||||
.filter(([, property]) => Array.isArray(property?.enum) && property.enum.length > 0)
|
||||
.map(([name, property]) => `${code(name)}: ${property.enum.map(code).join(", ")}`);
|
||||
return modeGroups.length > 0 ? modeGroups.join("; ") : "Single operation";
|
||||
}
|
||||
|
||||
function renderToolRows(tools, availability) {
|
||||
return tools.map((tool) => (
|
||||
`| ${code(tool.name)} | ${availability} | ${renderModes(tool)} | ${escapeCell(tool.description)} |`
|
||||
)).join("\n");
|
||||
}
|
||||
|
||||
export async function generateSupportedActionsMarkdown() {
|
||||
const defaultCore = await collectRegisteredTools(DEFAULT_CAPABILITIES, false);
|
||||
const fullCore = await collectRegisteredTools(FULL_CAPABILITIES, false);
|
||||
const connectedDefault = await collectRegisteredTools(DEFAULT_CAPABILITIES, true);
|
||||
const defaultNames = new Set(defaultCore.map((tool) => tool.name));
|
||||
const fullNames = new Set(fullCore.map((tool) => tool.name));
|
||||
const restrictedCore = fullCore.filter((tool) => !defaultNames.has(tool.name));
|
||||
const uxpTools = connectedDefault.filter((tool) => !defaultNames.has(tool.name));
|
||||
|
||||
if (uxpTools.some((tool) => fullNames.has(tool.name))) {
|
||||
throw new Error("The UXP additions overlap the registered core tool names.");
|
||||
}
|
||||
|
||||
return `# Supported actions catalog
|
||||
|
||||
<!-- Generated by \`npm run docs:supported-actions\`. Do not edit the tables manually. -->
|
||||
|
||||
This is the complete source-derived public action catalog for the current repository.
|
||||
The generator reads the same MCP registration surface used by clients, so tool names,
|
||||
descriptions, action enums, authority visibility, and counts stay aligned with the code.
|
||||
Release metadata and distributed-artifact claims remain versioned separately; this
|
||||
source catalog may include unreleased actions.
|
||||
|
||||
| Surface | Count | Availability |
|
||||
| --- | ---: | --- |
|
||||
| Registered core actions | ${fullCore.length} | CEP/local server catalog; host and authority checks still apply |
|
||||
| Default-profile core actions | ${defaultCore.length} | Advertised with \`${DEFAULT_CAPABILITIES}\` |
|
||||
| Restricted core actions | ${restrictedCore.length} | Require explicit \`unsafe-script\` authority |
|
||||
| Authenticated UXP additions | ${uxpTools.length} | Advertised only while a compatible authenticated UXP panel is connected |
|
||||
| Default profile with UXP | ${connectedDefault.length} | ${defaultCore.length} core plus ${uxpTools.length} UXP tools |
|
||||
|
||||
## How to read support
|
||||
|
||||
- \`tools/list\` is authoritative for what the current MCP session may call.
|
||||
- \`get_capabilities\` reports the full registered catalog, authority decisions, backend
|
||||
eligibility, and any live-host verification still required.
|
||||
- A listed tool is not proof that a particular Premiere installation supports every host
|
||||
API. The authenticated UXP capability handshake and per-call preflight remain authoritative.
|
||||
- CEP remains the compatibility backend. A failed UXP mutation is never automatically
|
||||
replayed through CEP or the undocumented QE DOM.
|
||||
- Automated tests establish schemas, routing, bounds, transactions, and readback contracts;
|
||||
they do not replace validation in a real Premiere host.
|
||||
|
||||
## Core actions
|
||||
|
||||
Each core tool is one callable MCP action. “Actions or modes” records a top-level
|
||||
\`action\` enum when present, otherwise other top-level enum selectors, or “Single
|
||||
operation” when the tool has no enum-based mode.
|
||||
|
||||
| MCP tool | Availability | Actions or modes | Description |
|
||||
| --- | --- | --- | --- |
|
||||
${renderToolRows(defaultCore, "Default profile")}
|
||||
${renderToolRows(restrictedCore, `Requires ${code("unsafe-script")}`)}
|
||||
|
||||
## Authenticated UXP actions
|
||||
|
||||
These tools are additive. They appear only while the local loopback UXP bridge is
|
||||
authenticated and the connected host advertises the required command capabilities.
|
||||
|
||||
| MCP tool | Availability | Actions or modes | Description |
|
||||
| --- | --- | --- | --- |
|
||||
${renderToolRows(uxpTools, "Connected UXP")}
|
||||
|
||||
## Maintenance
|
||||
|
||||
Run \`npm run docs:supported-actions\` after changing tool registration or action enums.
|
||||
\`npm run check\` fails when this generated page no longer matches the registered surface.
|
||||
`;
|
||||
}
|
||||
|
||||
async function main() {
|
||||
const checkOnly = process.argv.slice(2).includes("--check");
|
||||
const unknown = process.argv.slice(2).filter((argument) => argument !== "--check");
|
||||
if (unknown.length > 0) throw new Error(`Unknown argument: ${unknown[0]}`);
|
||||
const markdown = await generateSupportedActionsMarkdown();
|
||||
if (checkOnly) {
|
||||
const current = await readFile(OUTPUT_PATH, "utf8").catch(() => "");
|
||||
if (current.replaceAll("\r\n", "\n") !== markdown) {
|
||||
throw new Error("docs/supported-actions.md is stale. Run npm run docs:supported-actions.");
|
||||
}
|
||||
process.stdout.write("Supported actions catalog is current.\n");
|
||||
return;
|
||||
}
|
||||
await writeFile(OUTPUT_PATH, markdown, "utf8");
|
||||
process.stdout.write(`Wrote ${OUTPUT_PATH}\n`);
|
||||
}
|
||||
|
||||
if (process.argv[1] && import.meta.url === pathToFileURL(resolve(process.argv[1])).href) {
|
||||
main().catch((error) => {
|
||||
process.stderr.write(`${error instanceof Error ? error.message : String(error)}\n`);
|
||||
process.exitCode = 1;
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user