mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-06 19:58:43 +02:00
feat: phase 3 frontend — model badges, argument-hint composer, ancestor path display
Surface prompt model and argumentHint metadata across the UI: - InlinePromptPill: send model in promptInvocation, show model badge in dropdown, show argumentHint preview, support armed-prompt state for prompts with argumentHint (prompt stays pinned, hint becomes composer placeholder, user types additional context before sending) - ChatPane: armed-prompt state management, argumentHint-driven placeholder, send button enabled when prompt is armed, clear armed state on session change - PromptInvocationChrome: model badge in transcript, parent-repo badge and shortened source path display for ancestor-relative paths - ProjectSettingsPanel: model and argumentHint on prompt cards, parent-repo badge on instructions and prompts with ancestor paths, .claude/rules mentioned in instructions description and empty state Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -9,6 +9,13 @@ import type { ProjectAgentProfile, ProjectInstructionApplicationMode, ProjectIns
|
||||
|
||||
/* ── Types ────────────────────────────────────────────────── */
|
||||
|
||||
/** Shortens ancestor-relative source paths like `..\..\..\.github\prompts\x.md` to `↑ .github/prompts/x.md` */
|
||||
function formatSettingsSourcePath(sourcePath: string): string {
|
||||
const normalized = sourcePath.replace(/\\/g, '/');
|
||||
const segments = normalized.split('/').filter((s) => s !== '..');
|
||||
return `↑ ${segments.join('/')}`;
|
||||
}
|
||||
|
||||
type ProjectSettingsSection = 'overview' | 'instructions' | 'agents' | 'prompts' | 'mcp-servers' | 'danger-zone';
|
||||
|
||||
interface NavItem {
|
||||
@@ -335,7 +342,7 @@ function InstructionsContent({
|
||||
return (
|
||||
<div>
|
||||
<SectionHeader
|
||||
description="Repository instructions discovered from copilot-instructions.md, AGENTS.md, CLAUDE.md, and .github/instructions/**/*.instructions.md."
|
||||
description="Repository instructions discovered from copilot-instructions.md, AGENTS.md, CLAUDE.md, .github/instructions/**/*.instructions.md, and .claude/rules/**/*.md."
|
||||
title="Instructions"
|
||||
>
|
||||
<RescanButton onClick={onRescan} />
|
||||
@@ -343,7 +350,7 @@ function InstructionsContent({
|
||||
|
||||
{instructions.length === 0 ? (
|
||||
<EmptyState>
|
||||
No instruction files found. Add <code className="text-[var(--color-text-secondary)]">.github/copilot-instructions.md</code>, <code className="text-[var(--color-text-secondary)]">AGENTS.md</code>, <code className="text-[var(--color-text-secondary)]">CLAUDE.md</code>, or <code className="text-[var(--color-text-secondary)]">*.instructions.md</code> files under <code className="text-[var(--color-text-secondary)]">.github/instructions/</code>.
|
||||
No instruction files found. Add <code className="text-[var(--color-text-secondary)]">.github/copilot-instructions.md</code>, <code className="text-[var(--color-text-secondary)]">AGENTS.md</code>, <code className="text-[var(--color-text-secondary)]">CLAUDE.md</code>, <code className="text-[var(--color-text-secondary)]">*.instructions.md</code> files under <code className="text-[var(--color-text-secondary)]">.github/instructions/</code>, or <code className="text-[var(--color-text-secondary)]">*.md</code> files under <code className="text-[var(--color-text-secondary)]">.claude/rules/</code>.
|
||||
</EmptyState>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
@@ -359,7 +366,8 @@ function InstructionsContent({
|
||||
function InstructionCard({ instruction }: { instruction: ProjectInstructionFile }) {
|
||||
const [expanded, setExpanded] = useState(false);
|
||||
const isLong = instruction.content.length > 300;
|
||||
const displayName = instruction.name ?? instruction.sourcePath;
|
||||
const isAncestor = instruction.sourcePath.startsWith('..');
|
||||
const displayName = instruction.name ?? (isAncestor ? formatSettingsSourcePath(instruction.sourcePath) : instruction.sourcePath);
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-[var(--color-border)] bg-[var(--color-glass)]">
|
||||
@@ -370,8 +378,13 @@ function InstructionCard({ instruction }: { instruction: ProjectInstructionFile
|
||||
>
|
||||
<FileCode2 className="size-4 shrink-0 text-[var(--color-text-accent)]" />
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<span className="truncate text-[13px] font-medium text-[var(--color-text-primary)]">{displayName}</span>
|
||||
<span className="truncate text-[13px] font-medium text-[var(--color-text-primary)]" title={instruction.sourcePath}>{displayName}</span>
|
||||
<InstructionModeBadge mode={instruction.applicationMode} />
|
||||
{isAncestor && (
|
||||
<span className="shrink-0 rounded bg-[var(--color-surface-3)] px-1.5 py-0.5 text-[9px] font-medium text-[var(--color-text-muted)]">
|
||||
parent repo
|
||||
</span>
|
||||
)}
|
||||
{instruction.applyTo && (
|
||||
<span
|
||||
className="truncate rounded bg-[var(--color-surface-3)] px-1.5 py-0.5 text-[10px] font-medium text-[var(--color-text-muted)]"
|
||||
@@ -571,6 +584,8 @@ function PromptsContent({
|
||||
}
|
||||
|
||||
function PromptCard({ prompt }: { prompt: ProjectPromptFile }) {
|
||||
const isAncestor = prompt.sourcePath.startsWith('..');
|
||||
|
||||
return (
|
||||
<div className="rounded-xl border border-[var(--color-border)] bg-[var(--color-glass)] px-5 py-4">
|
||||
<div className="flex items-start gap-3">
|
||||
@@ -578,6 +593,11 @@ function PromptCard({ prompt }: { prompt: ProjectPromptFile }) {
|
||||
<div className="min-w-0 flex-1">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-[13px] font-medium text-[var(--color-text-primary)]">{prompt.name}</span>
|
||||
{prompt.model && (
|
||||
<span className="rounded-full bg-[var(--color-accent-purple)]/15 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-[var(--color-accent-purple)]">
|
||||
{prompt.model}
|
||||
</span>
|
||||
)}
|
||||
{prompt.agent && (
|
||||
<span className="rounded-full bg-[var(--color-accent-sky)]/15 px-2 py-0.5 text-[10px] font-semibold uppercase tracking-wider text-[var(--color-accent-sky)]">
|
||||
{prompt.agent}
|
||||
@@ -588,10 +608,20 @@ function PromptCard({ prompt }: { prompt: ProjectPromptFile }) {
|
||||
{prompt.variables.length} variable{prompt.variables.length === 1 ? '' : 's'}
|
||||
</span>
|
||||
)}
|
||||
{isAncestor && (
|
||||
<span className="rounded-full bg-[var(--color-surface-3)] px-2 py-0.5 text-[9px] font-medium text-[var(--color-text-muted)]">
|
||||
parent repo
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
{prompt.description && (
|
||||
<p className="mt-1 text-[12px] leading-relaxed text-[var(--color-text-muted)]">{prompt.description}</p>
|
||||
)}
|
||||
{prompt.argumentHint && (
|
||||
<p className="mt-1 text-[11px] italic text-[var(--color-text-muted)]">
|
||||
Hint: {prompt.argumentHint}
|
||||
</p>
|
||||
)}
|
||||
{prompt.tools && prompt.tools.length > 0 && (
|
||||
<div className="mt-2 flex flex-wrap gap-1.5">
|
||||
{prompt.tools.map((tool) => (
|
||||
@@ -617,7 +647,9 @@ function PromptCard({ prompt }: { prompt: ProjectPromptFile }) {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<p className="mt-1.5 text-[11px] text-[var(--color-text-muted)]">{prompt.sourcePath}</p>
|
||||
<p className="mt-1.5 text-[11px] text-[var(--color-text-muted)]" title={prompt.sourcePath}>
|
||||
{isAncestor ? formatSettingsSourcePath(prompt.sourcePath) : prompt.sourcePath}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user