mirror of
https://bitbucket.org/siakitem/my-pi.git
synced 2026-10-26 18:55:22 +00:00
feat: vendor permission system source
This commit is contained in:
@@ -0,0 +1,148 @@
|
||||
import { getNonEmptyString, toRecord } from "./value-guards";
|
||||
|
||||
/** Narrow interface for the Pi tool API subset used by handler classes. */
|
||||
export interface ToolRegistry {
|
||||
/** All registered tools (`pi.getAllTools()` — `ToolInfo[]`); kept defensively wide. */
|
||||
getAll(): unknown[];
|
||||
/** Currently active tool names (`pi.getActiveTools()`). */
|
||||
getActive(): string[];
|
||||
setActive(names: string[]): void;
|
||||
}
|
||||
|
||||
export type ToolRegistrationCheckResult =
|
||||
| {
|
||||
status: "missing-tool-name";
|
||||
}
|
||||
| {
|
||||
status: "registered";
|
||||
requestedToolName: string;
|
||||
normalizedToolName: string;
|
||||
}
|
||||
| {
|
||||
status: "unregistered";
|
||||
requestedToolName: string;
|
||||
normalizedToolName: string;
|
||||
availableToolNames: string[];
|
||||
};
|
||||
|
||||
function normalizeToolName(
|
||||
toolName: string,
|
||||
aliases: Record<string, string>,
|
||||
): string {
|
||||
return aliases[toolName] || toolName;
|
||||
}
|
||||
|
||||
function buildReverseAliases(
|
||||
aliases: Record<string, string>,
|
||||
): Map<string, string[]> {
|
||||
const reverse = new Map<string, string[]>();
|
||||
|
||||
for (const [alias, canonical] of Object.entries(aliases)) {
|
||||
const existing = reverse.get(canonical) ?? [];
|
||||
if (!existing.includes(alias)) {
|
||||
existing.push(alias);
|
||||
}
|
||||
reverse.set(canonical, existing);
|
||||
}
|
||||
|
||||
return reverse;
|
||||
}
|
||||
|
||||
function addToolNameVariants(
|
||||
value: string,
|
||||
names: Set<string>,
|
||||
aliases: Record<string, string>,
|
||||
reverseAliases: ReadonlyMap<string, readonly string[]>,
|
||||
): void {
|
||||
names.add(value);
|
||||
|
||||
const normalized = normalizeToolName(value, aliases);
|
||||
names.add(normalized);
|
||||
|
||||
const canonicalFromAlias = aliases[value];
|
||||
if (canonicalFromAlias) {
|
||||
names.add(canonicalFromAlias);
|
||||
}
|
||||
|
||||
const aliasValues = reverseAliases.get(value);
|
||||
if (aliasValues) {
|
||||
for (const alias of aliasValues) {
|
||||
names.add(alias);
|
||||
}
|
||||
}
|
||||
|
||||
const aliasValuesForNormalized = reverseAliases.get(normalized);
|
||||
if (aliasValuesForNormalized) {
|
||||
for (const alias of aliasValuesForNormalized) {
|
||||
names.add(alias);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function getToolNameFromValue(value: unknown): string | null {
|
||||
const direct = getNonEmptyString(value);
|
||||
if (direct) {
|
||||
return direct;
|
||||
}
|
||||
|
||||
const record = toRecord(value);
|
||||
const candidates = [record.toolName, record.name, record.tool];
|
||||
|
||||
for (const candidate of candidates) {
|
||||
const stringValue = getNonEmptyString(candidate);
|
||||
if (stringValue) {
|
||||
return stringValue;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
export function checkRequestedToolRegistration(
|
||||
requestedToolName: string | null,
|
||||
registeredTools: readonly unknown[],
|
||||
aliases: Record<string, string> = {},
|
||||
): ToolRegistrationCheckResult {
|
||||
const requested = getNonEmptyString(requestedToolName);
|
||||
if (!requested) {
|
||||
return {
|
||||
status: "missing-tool-name",
|
||||
};
|
||||
}
|
||||
|
||||
const normalizedToolName = normalizeToolName(requested, aliases);
|
||||
const reverseAliases = buildReverseAliases(aliases);
|
||||
|
||||
const registeredLookup = new Set<string>();
|
||||
const availableToolNames = new Set<string>();
|
||||
|
||||
for (const tool of registeredTools) {
|
||||
const name = getToolNameFromValue(tool);
|
||||
if (!name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
availableToolNames.add(name);
|
||||
addToolNameVariants(name, registeredLookup, aliases, reverseAliases);
|
||||
}
|
||||
|
||||
const isRegistered =
|
||||
registeredLookup.has(requested) || registeredLookup.has(normalizedToolName);
|
||||
|
||||
if (isRegistered) {
|
||||
return {
|
||||
status: "registered",
|
||||
requestedToolName: requested,
|
||||
normalizedToolName,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
status: "unregistered",
|
||||
requestedToolName: requested,
|
||||
normalizedToolName,
|
||||
availableToolNames: [...availableToolNames].sort((a, b) =>
|
||||
a.localeCompare(b),
|
||||
),
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user