fix(coding): remediate ML-07 plugin authority
This commit is contained in:
@@ -26,7 +26,16 @@ const EMPTY_FILES: string[] = [];
|
||||
type DrawerMode = 'models' | 'knowledge' | 'skills' | null;
|
||||
type ProjectIdentityKind = ProjectIdentityChoice['kind'];
|
||||
type SkillStructureEntry = { path: string; type: 'file' | 'directory' };
|
||||
type SkillInfo = { id: string; name: string; description: string; location: string; content: string; entries: SkillStructureEntry[] };
|
||||
type SkillInfo = {
|
||||
id: string;
|
||||
name: string;
|
||||
description: string;
|
||||
available: boolean;
|
||||
effective: boolean;
|
||||
location: string;
|
||||
content: string;
|
||||
entries: SkillStructureEntry[];
|
||||
};
|
||||
|
||||
function createCustomAgent(index: number, modelKey: string): CodingProjectAgent {
|
||||
const now = new Date().toISOString();
|
||||
@@ -154,6 +163,8 @@ export function ProjectConfiguration() {
|
||||
.then((result) => setSkills(result.skills.map((skill) => ({
|
||||
id: skill.id,
|
||||
...getSkillDisplayInfo(skill.id),
|
||||
available: skill.available,
|
||||
effective: skill.effective,
|
||||
location: skill.location ?? '',
|
||||
content: skill.content ?? '',
|
||||
entries: skill.entries ?? [{ path: 'SKILL.md', type: 'file' }],
|
||||
|
||||
@@ -11,10 +11,8 @@ import { cn } from '@/lib/utils';
|
||||
import { codingPluginsStore, useCodingPluginsStore } from '@/stores/coding-plugins';
|
||||
import { useCodingWorkspaceStore } from '@/stores/coding-workspace';
|
||||
import type { DataServiceInstanceState } from '../../../shared/data-service';
|
||||
import { BUNDLED_CODING_PLUGIN_DEFINITIONS, type CodingPluginDefinition } from '../../../shared/coding-plugins';
|
||||
|
||||
const PLUGIN_SETTINGS_SURFACES = { 'data-service': DataServicePluginSettings } as const;
|
||||
const definitions = new Map<string, CodingPluginDefinition>(BUNDLED_CODING_PLUGIN_DEFINITIONS.map((definition) => [definition.id, definition]));
|
||||
|
||||
const STATE_TEXT: Record<CodingPluginItem['state'], string> = {
|
||||
unavailable: '暂不可用', disabled: '未启用', identity_required: '需要项目 ID',
|
||||
@@ -60,8 +58,6 @@ export function ProjectPluginsView(props: ViewProps) {
|
||||
const [selectedId, setSelectedId] = useState(props.projection.items[0]?.id ?? null);
|
||||
const [disableCandidate, setDisableCandidate] = useState<CodingPluginItem | null>(null);
|
||||
const selected = props.projection.items.find(({ id }) => id === selectedId) ?? props.projection.items[0] ?? null;
|
||||
const definition = selected ? definitions.get(selected.id) : undefined;
|
||||
const billing = selected?.capabilities.flatMap(({ operations }) => operations.map(({ billing }) => billing))[0] ?? null;
|
||||
const SettingsSurface = selected?.settingsSurface && selected.settingsSurface in PLUGIN_SETTINGS_SURFACES
|
||||
? PLUGIN_SETTINGS_SURFACES[selected.settingsSurface as keyof typeof PLUGIN_SETTINGS_SURFACES]
|
||||
: null;
|
||||
@@ -92,19 +88,18 @@ export function ProjectPluginsView(props: ViewProps) {
|
||||
<section className="mt-6 grid gap-3 sm:grid-cols-2 lg:grid-cols-4" aria-label="插件概览">
|
||||
<div className="rounded-xl bg-surface-subtle p-3"><p className="text-xs text-muted-foreground">发布者</p><p className="mt-1 font-semibold">MakeLore</p></div>
|
||||
<div className="rounded-xl bg-surface-subtle p-3"><p className="text-xs text-muted-foreground">包版本</p><p className="mt-1 font-semibold">{selected.version}</p></div>
|
||||
<div className="rounded-xl bg-surface-subtle p-3"><p className="text-xs text-muted-foreground">合同版本</p><p className="mt-1 font-semibold">v{definition?.contractVersion ?? '—'}</p></div>
|
||||
<div className="rounded-xl bg-surface-subtle p-3"><p className="text-xs text-muted-foreground">后端</p><p className="mt-1 font-semibold">{definition?.requiresBackend ? '需要' : '不需要'}</p></div>
|
||||
<div className="rounded-xl bg-surface-subtle p-3"><p className="text-xs text-muted-foreground">合同版本</p><p className="mt-1 font-semibold">v{selected.contractVersion}</p></div>
|
||||
<div className="rounded-xl bg-surface-subtle p-3"><p className="text-xs text-muted-foreground">后端</p><p className="mt-1 font-semibold">{selected.requiresBackend ? '需要' : '不需要'}</p></div>
|
||||
</section>
|
||||
{selected.state === 'identity_required' ? <Button type="button" variant="outline" className="mt-5" onClick={() => navigate('/project-config')}>创建或绑定项目 ID</Button> : null}
|
||||
{selected.state === 'authentication_required' ? <Button type="button" variant="outline" className="mt-5" onClick={() => navigate('/login', { state: { from: '/project-plugins' } })}>前往登录</Button> : null}
|
||||
<section className="mt-7" aria-labelledby="plugin-capabilities-heading"><h3 id="plugin-capabilities-heading" className="text-balance text-lg font-semibold">能力与权限</h3>
|
||||
<div className="mt-3 flex flex-wrap gap-2">{selected.capabilities.map((capability) => <Badge key={capability.id} variant="secondary">{capability.id}</Badge>)}</div>
|
||||
<div className="mt-3 space-y-3">{definition?.tools.map((tool) => <div key={tool.name} className="rounded-xl bg-surface-subtle p-4"><div className="flex flex-wrap items-center gap-2"><code className="font-mono text-sm font-semibold">{tool.name}</code><Badge variant="outline">{MUTATION_TEXT[tool.mutation]}</Badge></div><p className="mt-2 text-pretty text-sm text-muted-foreground">{tool.description}</p><p className="mt-2 flex items-center gap-2 text-xs"><ShieldCheck className="h-4 w-4 text-brand" />{tool.permissions.map((permission) => PERMISSION_TEXT[permission] ?? permission).join('、')}</p></div>)}</div>
|
||||
<div className="mt-3 space-y-4">{selected.capabilities.map((capability) => <div key={capability.id} className="rounded-xl border border-border/70 p-4"><h4 className="font-mono text-sm font-semibold">{capability.id}</h4><div className="mt-3 space-y-3">{capability.operations.map((operation) => <div key={operation.id} className="rounded-lg bg-surface-subtle p-3"><div className="flex flex-wrap items-center gap-2"><code className="font-mono text-sm font-semibold">{operation.id}</code>{operation.tool ? <><Badge variant="outline">{MUTATION_TEXT[operation.tool.mutation]}</Badge><code className="text-xs text-muted-foreground">{operation.tool.name}</code></> : <Badge variant="outline">SDK</Badge>}</div>{operation.tool ? <><p className="mt-2 text-pretty text-sm text-muted-foreground">{operation.tool.description}</p><p className="mt-2 flex items-center gap-2 text-xs"><ShieldCheck className="h-4 w-4 text-brand" />{operation.tool.permissions.map((permission) => PERMISSION_TEXT[permission] ?? permission).join('、')}</p></> : <p className="mt-2 text-pretty text-sm text-muted-foreground">由生成的 Data Service SDK 使用,不作为 Pi 工具暴露。</p>}<p className="mt-2 text-pretty text-xs font-medium">{billingText(operation.billing)}</p></div>)}</div></div>)}</div>
|
||||
</section>
|
||||
<section className="mt-7" aria-labelledby="plugin-agents-heading"><div className="flex flex-wrap items-center justify-between gap-3"><h3 id="plugin-agents-heading" className="text-balance text-lg font-semibold">伙伴分配</h3><Button type="button" variant="outline" onClick={() => navigate('/project-config')}>管理伙伴技能</Button></div>
|
||||
<div className="mt-3 flex flex-wrap gap-2">{selected.skills.flatMap(({ assignedAgentIds }) => assignedAgentIds).length ? selected.skills.flatMap(({ assignedAgentIds }) => assignedAgentIds).map((id) => <Badge key={id} variant="secondary">{props.agentNames[id] ?? '未知伙伴'}</Badge>) : <p className="text-pretty text-sm text-muted-foreground">尚未分配给任何伙伴。</p>}</div>
|
||||
</section>
|
||||
<section className="mt-7" aria-labelledby="plugin-billing-heading"><h3 id="plugin-billing-heading" className="text-balance text-lg font-semibold">用量与计费</h3>{billing ? <><p className="mt-2 text-pretty text-sm">{billingText(billing)}</p>{billing.mode === 'platform_metered' ? <p className="mt-1 text-pretty text-xs text-muted-foreground">钱包流水由权益所有者查看,当前页面不扩大财务权限。</p> : null}</> : <p className="mt-2 text-pretty text-sm">计费策略暂不可用,相关调用已停用。</p>}</section>
|
||||
<section className="mt-7" aria-labelledby="plugin-billing-heading"><h3 id="plugin-billing-heading" className="text-balance text-lg font-semibold">用量与计费</h3><p className="mt-2 text-pretty text-sm">各操作的计费模式已在上方能力列表中逐项显示;平台计量操作的流水仍由权益所有者查看。</p></section>
|
||||
{SettingsSurface && selected.enabled ? <section className="mt-7" aria-labelledby="plugin-settings-heading"><h3 id="plugin-settings-heading" className="mb-3 text-balance text-lg font-semibold">配置</h3><SettingsSurface state={selected.state} projectName={props.projectName} data={props.dataService} pending={props.pending} onConfigure={props.onConfigure} onReset={props.onReset} onRemoveCollection={props.onRemoveCollection} onRemoveProject={props.onRemoveProject} /></section> : null}
|
||||
</article>
|
||||
) : <p className="text-sm text-muted-foreground">当前没有可用插件。</p>}
|
||||
|
||||
Reference in New Issue
Block a user