Documentation
¶
Overview ¶
Package usercmd loads user-authored slash commands from markdown files dropped in ~/.yottacode/commands/ (user scope) and <cwd>/.yottacode/commands/ (project scope).
Layout mirrors Claude Code's custom-commands feature: filename becomes the command name, subdirectories become a colon-separated namespace (commands/frontend/component.md → /frontend:component), the body is sent to the agent as the user message for that turn (with $ARGUMENTS / $1..$9 substituted and @<path> file refs honored by the same pipeline that handles user-typed @-refs).
Index ¶
Constants ¶
This section is empty.
Variables ¶
var Reserved = map[string]bool{ "help": true, "quit": true, "clear": true, "permissions": true, "system": true, "sessions": true, "model": true, "provider": true, "doctor": true, "redo": true, "recall": true, "summarize": true, "checkpoints": true, "memory": true, "max-iterations": true, "setup": true, "init": true, "plan": true, "loop": true, "subagents": true, "skills": true, "git-commit": true, "git-create-pr": true, "git-review-pr": true, "git-push": true, "git-update-pr": true, }
Reserved is the set of built-in slash command names a custom file is forbidden from shadowing. Kept here (not derived from the TUI package's allSlash) so this package stays standalone-testable; the TUI's init() is the source of truth and a one-line drift test in the TUI package guards against new built-ins being forgotten.
Functions ¶
func Load ¶
Load walks both scope directories (user first, then project) and returns the merged command list plus per-file load errors.
Conflict resolution:
- Same name within the SAME scope: both copies dropped, error emitted. We can't pick a winner safely (the user clearly intended different prompts) and silently keeping one would surprise them.
- Same name across scopes: project wins. The user-scope copy is dropped with an info-level notice so the user understands why /foo doesn't behave like their global file.
- Same name as a built-in: custom dropped with a warning. Built-ins can't be shadowed because the dispatcher walks built-ins first.
Errors are returned alongside the commands rather than as a single error — one broken file should not block a directory of working commands. The TUI iterates errs at startup and emits one styled notice per entry.
func ProjectCommandsDir ¶
ProjectCommandsDir returns <cwd>/.yottacode/commands/ — the per-repo custom-command directory. Commands here are committable so teams can share project-specific commands via git. Empty cwd returns "" so callers can detect "no project scope" without an error path.
func Substitute ¶
Substitute resolves $ARGUMENTS and $1..$9 in body using args. args is the post-name remainder a user typed after the command — for "/foo a b c", args is "a b c".
Tokenization is strings.Fields (whitespace-split, collapsing runs) to match what runSlash already does on the command line. Missing positionals (e.g. $3 when only two args were supplied) resolve to the empty string; the command author is responsible for handling the empty case in their prose if it matters.
func UserCommandsDir ¶
UserCommandsDir returns ~/.yottacode/commands/ — the cross-project custom-command directory. Commands here apply to every yottacode session for this user.
Types ¶
type Command ¶
type Command struct {
Name string
Description string
ArgHint string
Body string
SourceFile string
Scope Scope
}
Command is one loaded custom command. Body is the post-frontmatter markdown, unsubstituted (the TUI calls Substitute() with the user's args at invocation time).
type Level ¶
type Level int
Level grades a LoadError as either a hard error (the file did not produce a usable command) or a warning (the file is fine but shadowed / dropped due to a collision). The TUI renders the two levels with different styles.