feat(cli): personality flag + create/get/edit/delete personalities (Stage 4)

End-to-end CLI surface for the personality overlay:

  mcpctl create personality grumpy --agent reviewer --description "be terse"
  mcpctl create prompt tone --agent reviewer --content "Be very terse."
  mcpctl get personalities
  mcpctl get personalities --agent reviewer
  mcpctl edit personality <id>
  mcpctl delete personality grumpy --agent reviewer
  mcpctl chat reviewer --personality grumpy

Chat banner gains a "Personality:" line that shows either the active
flag value or the agent's `defaultPersonality` (when no flag given),
so the user knows which overlay is in effect before sending a message.

`--personality` is stripped from `/save` (it's a per-turn override,
not a `defaultParams` field — the agent's defaultPersonality lives on
its own column and is set via PUT /agents).

Backend (small additions to land Stage 4 cleanly):
- `GET /api/v1/personalities[?agent=name]` so `mcpctl get
  personalities` doesn't require an agent filter.
- PersonalityService.listAll() aggregates across agents.

Completions: regenerated fish + bash. `personalities` added as a
canonical resource with `personality` alias; edit-resource list
extended; the per-resource argument completers pick up the new
type automatically.

CLI suite: 430/430. mcpd: 801/801. Typecheck clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Michal
2026-04-26 19:32:48 +01:00
parent faef1e732d
commit 9050918a83
11 changed files with 171 additions and 26 deletions

View File

@@ -44,7 +44,7 @@ const COMPLETION_HINTS: Record<string, CompletionHint> = {
'describe.id': 'resource_names',
'delete.resource': 'resource_types',
'delete.id': 'resource_names',
'edit.resource': { static: ['servers', 'secrets', 'projects', 'groups', 'rbac', 'prompts', 'promptrequests'] },
'edit.resource': { static: ['servers', 'secrets', 'projects', 'groups', 'rbac', 'prompts', 'promptrequests', 'personalities'] },
'edit.name-or-id': 'resource_names',
'patch.resource': 'resource_types',
'patch.name': 'resource_names',
@@ -184,7 +184,7 @@ async function extractTree(): Promise<CmdInfo> {
// ============================================================
const CANONICAL_RESOURCES = [
'servers', 'instances', 'secrets', 'secretbackends', 'llms', 'agents', 'templates', 'projects',
'servers', 'instances', 'secrets', 'secretbackends', 'llms', 'agents', 'personalities', 'templates', 'projects',
'users', 'groups', 'rbac', 'prompts', 'promptrequests',
'serverattachments', 'proxymodels', 'all',
];
@@ -196,6 +196,7 @@ const ALIAS_ENTRIES: [string, string][] = [
['secretbackend', 'secretbackends'], ['sb', 'secretbackends'],
['llm', 'llms'], ['llms', 'llms'],
['agent', 'agents'], ['agents', 'agents'],
['personality', 'personalities'], ['personalities', 'personalities'],
['template', 'templates'], ['tpl', 'templates'],
['project', 'projects'], ['proj', 'projects'],
['user', 'users'],