11import { select } from "@inquirer/prompts" ;
22import { Glob } from "bun" ;
3- import { basename } from "path" ;
3+ import { basename , join } from "path" ;
44import { realpathSync } from "fs" ;
5+ import { homedir } from "os" ;
56
67export interface CliArgs {
78 filePath : string ;
@@ -87,6 +88,13 @@ Command resolution:
8788 1. --command flag (e.g., ma task.md --command claude)
8889 2. Filename pattern (e.g., task.claude.md → claude)
8990
91+ Agent file discovery (in priority order):
92+ 1. Explicit path: ma ./path/to/agent.md
93+ 2. Current directory: ./
94+ 3. Project agents: ./.ma/
95+ 4. User agents: ~/.ma/
96+ 5. $PATH directories
97+
9098All frontmatter keys are passed as CLI flags to the command.
9199Global defaults can be set in ~/.markdown-agent/config.yaml
92100
@@ -116,9 +124,10 @@ ma-specific flags (consumed, not passed to command):
116124 --trust Skip trust prompt for remote URLs (TOFU bypass)
117125
118126Without a file:
119- ma --setup Configure shell to run .md files directly
120- ma --logs Show log directory
121- ma --help Show this help
127+ ma Interactive agent picker (from ./.ma/, ~/.ma/, etc.)
128+ ma --setup Configure shell to run .md files directly
129+ ma --logs Show log directory
130+ ma --help Show this help
122131` ) ;
123132}
124133
@@ -135,9 +144,20 @@ function normalizePath(filePath: string): string {
135144 }
136145}
137146
147+ /** Project-level agent directory */
148+ const PROJECT_AGENTS_DIR = ".ma" ;
149+
150+ /** User-level agent directory */
151+ const USER_AGENTS_DIR = join ( homedir ( ) , ".ma" ) ;
152+
138153/**
139- * Find agent markdown files from current directory and $PATH
140- * Returns files sorted by source (cwd first, then PATH directories)
154+ * Find agent markdown files with priority order:
155+ * 1. Current directory (cwd)
156+ * 2. Project-level: ./.ma/
157+ * 3. User-level: ~/.ma/
158+ * 4. $PATH directories
159+ *
160+ * Returns files sorted by source priority (earlier sources take precedence)
141161 */
142162export async function findAgentFiles ( ) : Promise < AgentFile [ ] > {
143163 const files : AgentFile [ ] = [ ] ;
@@ -158,7 +178,34 @@ export async function findAgentFiles(): Promise<AgentFile[]> {
158178 // Skip if cwd is not accessible
159179 }
160180
161- // 2. $PATH directories
181+ // 2. Project-level: ./.ma/
182+ const projectAgentsPath = join ( process . cwd ( ) , PROJECT_AGENTS_DIR ) ;
183+ try {
184+ for await ( const file of glob . scan ( { cwd : projectAgentsPath , absolute : true } ) ) {
185+ const normalizedPath = normalizePath ( file ) ;
186+ if ( ! seenPaths . has ( normalizedPath ) ) {
187+ seenPaths . add ( normalizedPath ) ;
188+ files . push ( { name : basename ( file ) , path : normalizedPath , source : ".ma" } ) ;
189+ }
190+ }
191+ } catch {
192+ // Skip if .ma/ doesn't exist
193+ }
194+
195+ // 3. User-level: ~/.ma/
196+ try {
197+ for await ( const file of glob . scan ( { cwd : USER_AGENTS_DIR , absolute : true } ) ) {
198+ const normalizedPath = normalizePath ( file ) ;
199+ if ( ! seenPaths . has ( normalizedPath ) ) {
200+ seenPaths . add ( normalizedPath ) ;
201+ files . push ( { name : basename ( file ) , path : normalizedPath , source : "~/.ma" } ) ;
202+ }
203+ }
204+ } catch {
205+ // Skip if ~/.ma/ doesn't exist
206+ }
207+
208+ // 4. $PATH directories
162209 const pathDirs = ( process . env . PATH || "" ) . split ( ":" ) ;
163210 for ( const dir of pathDirs ) {
164211 if ( ! dir ) continue ;
@@ -178,6 +225,20 @@ export async function findAgentFiles(): Promise<AgentFile[]> {
178225 return files ;
179226}
180227
228+ /**
229+ * Get the project agents directory path
230+ */
231+ export function getProjectAgentsDir ( ) : string {
232+ return join ( process . cwd ( ) , PROJECT_AGENTS_DIR ) ;
233+ }
234+
235+ /**
236+ * Get the user agents directory path
237+ */
238+ export function getUserAgentsDir ( ) : string {
239+ return USER_AGENTS_DIR ;
240+ }
241+
181242/**
182243 * Show interactive file picker and return selected file path
183244 */
0 commit comments