merge: integrate v7-rbac-visibility on top of skills feature
Brings together the two unmerged feature lines onto one integration branch: - skills/review/proposals/revisions (via fix/mcpd-instance-health-and-retry, which contains the full skills-1..7 chain + mcpd env/retry/readiness fix) - v7 visibility scope + ownership for Llms and Agents Auto-merge resolved schema.prisma, mcpd main.ts, mcplocal config, CLI create, and completions with no conflicts. Both Prisma migrations coexist. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -264,6 +264,7 @@ export function createCreateCommand(deps: CreateCommandDeps): Command {
|
||||
.option('--api-key-ref <ref>', 'API key reference in SECRET/KEY form (e.g. anthropic-key/token)')
|
||||
.option('--extra <entry>', 'Extra config key=value (repeat)', collect, [])
|
||||
.option('--pool-name <pool>', 'Stack with other Llms sharing this pool name; agents pinned to any member dispatch across the pool')
|
||||
.option('--visibility <scope>', 'Visibility scope: public (everyone) or private (only owner + name-grants)', 'public')
|
||||
.option('--force', 'Update if already exists')
|
||||
.option('--skip-auth-check', 'Skip the upstream auth probe (for offline registration before infra exists)')
|
||||
.action(async (name: string, opts) => {
|
||||
@@ -276,6 +277,12 @@ export function createCreateCommand(deps: CreateCommandDeps): Command {
|
||||
if (opts.url) body.url = opts.url;
|
||||
if (opts.description !== undefined) body.description = opts.description;
|
||||
if (opts.poolName !== undefined) body.poolName = opts.poolName;
|
||||
if (opts.visibility !== undefined) {
|
||||
if (opts.visibility !== 'public' && opts.visibility !== 'private') {
|
||||
throw new Error(`Invalid --visibility '${opts.visibility as string}'. Expected 'public' or 'private'`);
|
||||
}
|
||||
body.visibility = opts.visibility;
|
||||
}
|
||||
if (opts.apiKeyRef) {
|
||||
const slashIdx = (opts.apiKeyRef as string).indexOf('/');
|
||||
if (slashIdx < 1) throw new Error(`Invalid --api-key-ref '${opts.apiKeyRef as string}'. Expected SECRET_NAME/KEY_NAME`);
|
||||
@@ -333,6 +340,7 @@ export function createCreateCommand(deps: CreateCommandDeps): Command {
|
||||
.option('--default-stop <text>', 'Default stop sequence (repeat for multiple)', collect, [])
|
||||
.option('--default-extra <kv>', 'Default provider-specific knob k=v (repeat)', collect, [])
|
||||
.option('--default-params-file <path>', 'Read defaultParams from a JSON file')
|
||||
.option('--visibility <scope>', 'Visibility scope: public (everyone) or private (only owner + name-grants)', 'public')
|
||||
.option('--force', 'Update if already exists')
|
||||
.action(async (name: string, opts) => {
|
||||
const body: Record<string, unknown> = {
|
||||
@@ -341,6 +349,12 @@ export function createCreateCommand(deps: CreateCommandDeps): Command {
|
||||
};
|
||||
if (opts.project) body.project = { name: opts.project };
|
||||
if (opts.description !== undefined) body.description = opts.description;
|
||||
if (opts.visibility !== undefined) {
|
||||
if (opts.visibility !== 'public' && opts.visibility !== 'private') {
|
||||
throw new Error(`Invalid --visibility '${opts.visibility as string}'. Expected 'public' or 'private'`);
|
||||
}
|
||||
body.visibility = opts.visibility;
|
||||
}
|
||||
|
||||
let systemPrompt = opts.systemPrompt as string | undefined;
|
||||
if (systemPrompt === undefined && opts.systemPromptFile !== undefined) {
|
||||
|
||||
@@ -138,6 +138,10 @@ interface LlmRow {
|
||||
status?: 'active' | 'inactive' | 'hibernating';
|
||||
// v4: explicit pool key. NULL = solo Llm (effective pool = its own name).
|
||||
poolName?: string | null;
|
||||
// v7: visibility scope. Legacy public rows omit it; mcpd defaults missing
|
||||
// values to 'public' on serialization.
|
||||
visibility?: 'public' | 'private';
|
||||
ownerId?: string | null;
|
||||
}
|
||||
|
||||
// v4: POOL column placed right after NAME so an operator can't miss
|
||||
@@ -148,6 +152,7 @@ const llmColumns: Column<LlmRow>[] = [
|
||||
{ header: 'POOL', key: (r) => (r.poolName !== null && r.poolName !== undefined && r.poolName !== '') ? r.poolName : '-', width: 18 },
|
||||
{ header: 'KIND', key: (r) => r.kind ?? 'public', width: 8 },
|
||||
{ header: 'STATUS', key: (r) => r.status ?? 'active', width: 12 },
|
||||
{ header: 'VISIBILITY', key: (r) => r.visibility ?? 'public', width: 11 },
|
||||
{ header: 'TYPE', key: 'type', width: 12 },
|
||||
{ header: 'MODEL', key: 'model', width: 28 },
|
||||
{ header: 'TIER', key: 'tier', width: 8 },
|
||||
@@ -214,12 +219,15 @@ interface AgentRow {
|
||||
// AgentService as the publishing mcplocal heartbeats and disconnects.
|
||||
kind?: 'public' | 'virtual';
|
||||
status?: 'active' | 'inactive';
|
||||
// v7: visibility — same semantics as Llm. Public legacy agents omit it.
|
||||
visibility?: 'public' | 'private';
|
||||
}
|
||||
|
||||
const agentColumns: Column<AgentRow>[] = [
|
||||
{ header: 'NAME', key: 'name' },
|
||||
{ header: 'KIND', key: (r) => r.kind ?? 'public', width: 8 },
|
||||
{ header: 'STATUS', key: (r) => r.status ?? 'active', width: 10 },
|
||||
{ header: 'VISIBILITY', key: (r) => r.visibility ?? 'public', width: 11 },
|
||||
{ header: 'LLM', key: (r) => r.llm.name, width: 24 },
|
||||
{ header: 'PROJECT', key: (r) => r.project?.name ?? '-', width: 20 },
|
||||
{ header: 'DESCRIPTION', key: (r) => truncate(r.description, 50) || '-', width: 50 },
|
||||
|
||||
Reference in New Issue
Block a user