diff --git a/packages/cli/src/tests/agent-instructions.test.ts b/packages/cli/src/tests/agent-instructions.test.ts new file mode 100644 index 00000000..08e21614 --- /dev/null +++ b/packages/cli/src/tests/agent-instructions.test.ts @@ -0,0 +1,24 @@ +import { test } from "node:test"; +import assert from "node:assert/strict"; +import { buildAgentInstructionsReport } from "../ui/core/agent-instructions"; + +test("buildAgentInstructionsReport highlights the loaded file (#262)", () => { + const report = buildAgentInstructionsReport([ + { displayPath: "./.deepcode/AGENTS.md", absolutePath: "/p/.deepcode/AGENTS.md", exists: true, loaded: true }, + { displayPath: "./AGENTS.md", absolutePath: "/p/AGENTS.md", exists: true, loaded: false }, + { displayPath: "~/.deepcode/AGENTS.md", absolutePath: "/home/u/.deepcode/AGENTS.md", exists: false, loaded: false }, + ]); + assert.match(report, /Agent instructions loaded from \.\/\.deepcode\/AGENTS\.md/); + assert.match(report, /\.\/\.deepcode\/AGENTS\.md — loaded/); + assert.match(report, /\.\/AGENTS\.md — present/); + assert.match(report, /~\/\.deepcode\/AGENTS\.md — not found/); +}); + +test("buildAgentInstructionsReport handles the no-instructions case (#262)", () => { + const report = buildAgentInstructionsReport([ + { displayPath: "./.deepcode/AGENTS.md", absolutePath: "/p/.deepcode/AGENTS.md", exists: false, loaded: false }, + { displayPath: "./AGENTS.md", absolutePath: "/p/AGENTS.md", exists: false, loaded: false }, + { displayPath: "~/.deepcode/AGENTS.md", absolutePath: "/home/u/.deepcode/AGENTS.md", exists: false, loaded: false }, + ]); + assert.match(report, /No AGENTS\.md instruction file found/); +}); diff --git a/packages/cli/src/tests/slash-commands.test.ts b/packages/cli/src/tests/slash-commands.test.ts index 311c01ed..b71efc13 100644 --- a/packages/cli/src/tests/slash-commands.test.ts +++ b/packages/cli/src/tests/slash-commands.test.ts @@ -31,6 +31,7 @@ test("buildSlashCommands prefixes skills before built-ins", () => { "undo", "mcp", "raw", + "agents", "exit", ]); }); diff --git a/packages/cli/src/ui/core/agent-instructions.ts b/packages/cli/src/ui/core/agent-instructions.ts new file mode 100644 index 00000000..23bae183 --- /dev/null +++ b/packages/cli/src/ui/core/agent-instructions.ts @@ -0,0 +1,19 @@ +export type AgentInstructionSource = { + displayPath: string; + absolutePath: string; + exists: boolean; + loaded: boolean; +}; + +/** Render a human-readable report of which AGENTS.md files exist and which one is loaded. (#262) */ +export function buildAgentInstructionsReport(sources: AgentInstructionSource[]): string { + const lines = sources.map((source) => { + const status = source.exists ? (source.loaded ? "loaded" : "present") : "not found"; + return `${source.displayPath} — ${status}`; + }); + const loaded = sources.find((source) => source.loaded); + const header = loaded + ? `Agent instructions loaded from ${loaded.displayPath}` + : "No AGENTS.md instruction file found (default system prompt only)"; + return `${header}\n${lines.join("\n")}`; +} diff --git a/packages/cli/src/ui/core/slash-commands.ts b/packages/cli/src/ui/core/slash-commands.ts index 77292b40..aac599dc 100644 --- a/packages/cli/src/ui/core/slash-commands.ts +++ b/packages/cli/src/ui/core/slash-commands.ts @@ -13,6 +13,7 @@ export type SlashCommandKind = | "undo" | "mcp" | "raw" + | "agents" | "exit"; export type SlashCommandItem = { @@ -92,6 +93,12 @@ export const BUILTIN_SLASH_COMMANDS: SlashCommandItem[] = [ args: ["lite", "normal", "raw-scrollback"], description: "Toggle display mode for viewing or collapsing reasoning content", }, + { + kind: "agents", + name: "agents", + label: "/agents", + description: "Show which AGENTS.md instruction files are loaded", + }, { kind: "exit", name: "exit", diff --git a/packages/cli/src/ui/views/App.tsx b/packages/cli/src/ui/views/App.tsx index 034c62ac..2233ac0a 100644 --- a/packages/cli/src/ui/views/App.tsx +++ b/packages/cli/src/ui/views/App.tsx @@ -9,6 +9,7 @@ import { MessageView, RawModeExitPrompt } from "../components"; import { SessionList } from "./SessionList"; import { type UndoRestoreMode, UndoSelector } from "./UndoSelector"; import { buildLoadingText } from "../core/loading-text"; +import { buildAgentInstructionsReport } from "../core/agent-instructions"; import { findExpandedThinkingId } from "../core/thinking-state"; import { WelcomeScreen } from "./WelcomeScreen"; import { AskUserQuestionPrompt } from "./AskUserQuestionPrompt"; @@ -392,6 +393,11 @@ function App({ projectRoot, initialPrompt, resumeSessionId, forkSessionId, onRes navigateToSubView("mcp-status"); return; } + if (submission.command === "agents") { + const report = buildAgentInstructionsReport(sessionManager.getAgentInstructionSources()); + setMessages((prev) => [...prev, buildSyntheticUserMessage(report, 0)]); + return; + } const prompt: UserPromptContent = { text: submission.text, diff --git a/packages/cli/src/ui/views/PromptInput.tsx b/packages/cli/src/ui/views/PromptInput.tsx index 9e6240a4..30cbe00d 100644 --- a/packages/cli/src/ui/views/PromptInput.tsx +++ b/packages/cli/src/ui/views/PromptInput.tsx @@ -73,7 +73,7 @@ export type PromptSubmission = { permissions?: UserToolPermission[]; alwaysAllows?: PermissionScope[]; planMode?: boolean; - command?: "new" | "resume" | "fork" | "continue" | "undo" | "mcp" | "exit"; + command?: "new" | "resume" | "fork" | "continue" | "undo" | "mcp" | "agents" | "exit"; }; export type PromptDraft = { @@ -734,6 +734,11 @@ export const PromptInput = React.memo(function PromptInput({ resetPromptInput(); return; } + if (item.kind === "agents") { + onSubmit({ text: "/agents", imageUrls: [], command: "agents" }); + resetPromptInput(); + return; + } if (item.kind === "exit") { onSubmit({ text: "/exit", imageUrls: [], command: "exit" }); setBuffer(EMPTY_BUFFER); diff --git a/packages/core/src/session.ts b/packages/core/src/session.ts index b9252eaa..4bfde4e0 100644 --- a/packages/core/src/session.ts +++ b/packages/core/src/session.ts @@ -2403,6 +2403,33 @@ ${agentInstructions} return this.readNonEmptyFile(path.join(os.homedir(), ".deepcode", "AGENTS.md")); } + /** Report which AGENTS.md instruction files exist and which one is loaded. (#262) */ + getAgentInstructionSources(): Array<{ displayPath: string; absolutePath: string; exists: boolean; loaded: boolean }> { + const candidates = [ + { + absolutePath: path.join(this.projectRoot, ".deepcode", "AGENTS.md"), + displayPath: "./.deepcode/AGENTS.md", + }, + { + absolutePath: path.join(this.projectRoot, "AGENTS.md"), + displayPath: "./AGENTS.md", + }, + { + absolutePath: path.join(os.homedir(), ".deepcode", "AGENTS.md"), + displayPath: "~/.deepcode/AGENTS.md", + }, + ]; + const project = this.loadProjectAgentInstructions(); + const userContent = this.readNonEmptyFile(path.join(os.homedir(), ".deepcode", "AGENTS.md")); + const effectiveDisplayPath = project?.displayPath ?? (userContent ? candidates[2]!.displayPath : null); + return candidates.map((candidate) => ({ + displayPath: candidate.displayPath, + absolutePath: candidate.absolutePath, + exists: fs.existsSync(candidate.absolutePath), + loaded: candidate.displayPath === effectiveDisplayPath, + })); + } + private buildSystemMessage( sessionId: string, content: string,