diff --git a/skills/SKILL.md b/skills/SKILL.md deleted file mode 100644 index fb27087..0000000 --- a/skills/SKILL.md +++ /dev/null @@ -1,304 +0,0 @@ ---- -name: command-system -description: Use when writing, modifying, or debugging CProof command functions (cmd_funcs.c), command definitions (cmd_defs.c), or autocomplete (cmd_ac.c). Documents the command dispatch architecture, critical argument indexing rules (args[0] contains subcommand name), and common patterns. ---- - -# CProof Command System - -## When to Use This Skill - -Use this skill when: -- Writing new command handler functions in `cmd_funcs.c` -- Adding/modifying command definitions in `cmd_defs.c` -- Implementing autocomplete for commands in `cmd_ac.c` -- Debugging command argument parsing issues - -## Core Architecture - -### Command Structure ([`Command`](src/command/cmd_defs.h:64)) - -```c -typedef struct cmd_t { - gchar* cmd; // e.g., "/ai" - gchar** (*parser)(const char*, int, int, gboolean*); // parse_args, parse_args_with_freetext, parse_args_as_one - int min_args; int max_args; - void (*setting_func)(void); // Shows current settings in console (or NULL) - struct { const char* cmd; gboolean (*func)(ProfWin*, const char*, gchar**); } sub_funcs[50]; - gboolean (*func)(ProfWin*, const char*, gchar**); // Main handler (or NULL) - CommandHelp help; // Tags, synopsis, desc, args, examples -} Command; -``` - -### Help Structure ([`CommandHelp`](src/command/cmd_funcs.h:43)) - -```c -typedef struct cmd_help_t { - gchar* tags[20]; // Command categories (NULL-terminated) - gchar* synopsis[50]; // Usage examples (NULL-terminated) - gchar* desc; // Description text - gchar* args[128][2]; // Argument names and descriptions ({NULL,NULL}-terminated) - gchar* examples[20]; // Example commands (NULL-terminated) -} CommandHelp; -``` - -### Available Tags ([`cmd_defs.c:82-89`](src/command/cmd_defs.c:82)) - -| Tag | Description | -|-----|-------------| -| `CMD_TAG_CHAT` | Chat commands | -| `CMD_TAG_GROUPCHAT` | Group chat commands | -| `CMD_TAG_ROSTER` | Roster management | -| `CMD_TAG_PRESENCE` | Presence commands | -| `CMD_TAG_CONNECTION` | Connection management | -| `CMD_TAG_DISCOVERY` | Discovery commands | -| `CMD_TAG_UI` | UI display commands | -| `CMD_TAG_PLUGINS` | Plugin commands | - -### Dispatch Flow ([`_cmd_execute()`](src/command/cmd_funcs.c:8261)) - -``` -User: /ai set provider openai https://api.openai.com - | - v -parse_args("set provider openai https://...", 0, 5) → {"set","provider","openai","https://...",NULL} - | - v -args[0]="set" matches cmd->sub_funcs[0].cmd="set" - | - v -cmd_ai_set(window, "/ai", args) ← args[0] is "set", NOT "provider"! -``` - -**CRITICAL: Subcommand functions receive the FULL args array. args[0] contains the subcommand name itself. All parameter accesses must be shifted +1.** - -## Argument Indexing Reference - -| User Input | args[0] | args[1] | args[2] | args[3] | -|------------|---------|---------|---------|---------| -| `/ai` | NULL | - | - | - | -| `/ai set provider openai url` | `"set"` | `"provider"` | `"openai"` | `"url"` | -| `/ai set token openai sk-xxx` | `"set"` | `"token"` | `"openai"` | `"sk-xxx"` | -| `/ai start openai/gpt-4o` | `"start"` | `"openai/gpt-4o"` | - | - | -| `/ai remove provider foo` | `"remove"` | `"provider"` | `"foo"` | - | -| `/tls trust` | `"trust"` | - | - | - | -| `/connect account server foo` | `"account"` | `"server"` | `"foo"` | - | - -## Correct Subcommand Function Pattern - -```c -gboolean cmd_ai_set(ProfWin* window, const char* const command, gchar** args) -{ - // args[0] = "set" (subcommand name) - // args[1] = next subcommand (provider/token/org) - - if (args[1] == NULL) { cons_bad_cmd_usage(command); return TRUE; } - - if (g_strcmp0(args[1], "provider") == 0) { - // args[2] = name, args[3] = url - if (g_strv_length(args) < 4) { cons_bad_cmd_usage(command); return TRUE; } - ai_add_provider(args[2], args[3], NULL); - cons_show("Provider '%s' configured with URL: %s", args[2], args[3]); - } else if (g_strcmp0(args[1], "token") == 0) { - // args[2] = provider, args[3] = token - if (g_strv_length(args) < 4) { cons_bad_cmd_usage(command); return TRUE; } - ai_set_provider_key(args[2], args[3]); - } else if (g_strcmp0(args[1], "org") == 0) { - // args[2] = provider, args[3] = org_id - if (g_strv_length(args) < 4) { cons_bad_cmd_usage(command); return TRUE; } - AIProvider* p = ai_get_provider(args[2]); - if (p) { g_free(p->org_id); p->org_id = g_strdup(args[3]); } - } else { - cons_bad_cmd_usage(command); return TRUE; - } - cons_show(""); - return TRUE; -} -``` - -### Common Bug (WRONG) -```c -// BUG: args[0] is "set", not "provider" -if (g_strcmp0(args[0], "provider") == 0) { ... } -// BUG: args[1] is "provider", not the name -ai_add_provider(args[1], args[2], NULL); -``` - -## Command Definition Pattern ([`cmd_defs.c`](src/command/cmd_defs.c)) - -### Macros ([`cmd_defs.c:91-98`](src/command/cmd_defs.c:91)) - -```c -#define CMD_PREAMBLE(c, p, min, max, set) .cmd = c, .parser = p, .min_args = min, .max_args = max, .setting_func = set, -#define CMD_MAINFUNC(f) .func = f, -#define CMD_SUBFUNCS(...) .sub_funcs = { __VA_ARGS__, { NULL, NULL } }, -#define CMD_TAGS(...) .help.tags = { __VA_ARGS__, NULL }, -#define CMD_SYN(...) .help.synopsis = { __VA_ARGS__, NULL }, -#define CMD_DESC(d) .help.desc = d, -#define CMD_ARGS(...) .help.args = { __VA_ARGS__, { NULL, NULL } }, -#define CMD_EXAMPLES(...) .help.examples = { __VA_ARGS__, NULL } -``` - -### Example Definition - -```c -{ CMD_PREAMBLE("/ai", parse_args, 0, 5, NULL) - CMD_SUBFUNCS({ "set", cmd_ai_set }, { "remove", cmd_ai_remove }, - { "start", cmd_ai_start }, { "clear", cmd_ai_clear }, - { "correct", cmd_ai_correct }, { "providers", cmd_ai_providers }) - CMD_MAINFUNC(cmd_ai) - CMD_TAGS(CMD_TAG_CHAT) - CMD_SYN("/ai", "/ai set provider ", "/ai set token ") - CMD_DESC("Interact with AI models via OpenAI-compatible APIs.") - CMD_ARGS({ "", "Display current AI settings" }, - { "set provider ", "Add or update a provider" }) - CMD_EXAMPLES("/ai", "/ai set token openai sk-xxx", "/ai start openai/gpt-4o") -}, -``` - -## Autocomplete Pattern ([`cmd_ac.c`](src/command/cmd_ac.c)) - -### Initialization -```c -// In cmd_ac_init(): -autocomplete_add(ai_subcommands_ac, "set"); -autocomplete_add(ai_subcommands_ac, "remove"); -autocomplete_add(ai_set_subcommands_ac, "provider"); -autocomplete_add(ai_set_subcommands_ac, "token"); -autocomplete_add(ai_set_subcommands_ac, "org"); -g_hash_table_insert(ac_funcs, "/ai", _ai_autocomplete); -``` - -### Callback -```c -static char* _ai_autocomplete(ProfWin* window, const char* const input, gboolean previous) -{ - char* result = NULL; - result = autocomplete_param_with_ac(input, "/ai", ai_subcommands_ac, TRUE, previous); - if (result) return result; - result = autocomplete_param_with_ac(input, "/ai set", ai_set_subcommands_ac, TRUE, previous); - if (result) return result; - // Dynamic: provider names from ai_list_providers() - return NULL; -} -``` - -## Common Patterns - -### Window Type Access -```c -ProfAiWin* aiwin = (window && window->type == WIN_AI) ? (ProfAiWin*)window : wins_get_ai(); -// Or switch: -switch (window->type) { -case WIN_CHAT: { ProfChatWin* w = (ProfChatWin*)window; /* w->barejid */ break; } -case WIN_MUC: { ProfMucWin* w = (ProfMucWin*)window; /* w->roomjid */ break; } -} -``` - -### Connection Check -```c -if (connection_get_status() != JABBER_CONNECTED) { - cons_show("You are not currently connected."); - return TRUE; -} -``` - -### Options Parsing -```c -gchar* opt_keys[] = { "server", "port", "tls", NULL }; -GHashTable* opts = parse_options(&args[args[0] ? 1 : 0], opt_keys, &parsed); -// &args[args[0] ? 1 : 0] skips args[0] if present -``` - -### Memory Management -```c -auto_gcharv gchar** args = cmd->parser(inp, min, max, &result); // Auto-freed -auto_gchar gchar* path = prefs_get_string(PREF_SOME_PREF); // Auto-freed -``` - -## Argument Parsers ([`parser.c`](src/tools/parser.c)) - -| Function | Description | -|----------|-------------| -| `parse_args()` | Standard argument parsing, splits on spaces | -| `parse_args_with_freetext()` | Last argument captures everything after `max` tokens | -| `parse_args_as_one()` | Everything after first space becomes single argument | - -## Console Output Functions ([`ui.h`](src/ui/ui.h)) - -| Function | Description | -|----------|-------------| -| `cons_show(const char* msg, ...)` | Print formatted message to console | -| `cons_show_error(const char* cmd, ...)` | Print error message | -| `cons_bad_cmd_usage(const char* cmd)` | Print usage error | - -## Adding a New Command: Step-by-Step - -### Step 1: Declare Function in `cmd_funcs.h` - -```c -gboolean cmd_mycommand(ProfWin* window, const char* const command, gchar** args); -``` - -### Step 2: Implement Function in `cmd_funcs.c` - -```c -gboolean -cmd_mycommand(ProfWin* window, const char* const command, gchar** args) -{ - // args[0] = first argument (or NULL if none) - if (args[0] == NULL) { - cons_show("No argument provided."); - return TRUE; - } - cons_show("Got: %s", args[0]); - return TRUE; -} -``` - -### Step 3: Add Definition to `command_defs[]` in `cmd_defs.c` - -Find the end of the array (look for `};` after the last entry) and add: - -```c - { CMD_PREAMBLE("/mycommand", - parse_args, 0, 1, NULL) - CMD_MAINFUNC(cmd_mycommand) - CMD_TAGS(CMD_TAG_CHAT) - CMD_SYN("/mycommand []") - CMD_DESC("My new command description.") - CMD_ARGS({ "", "An argument" }) - CMD_EXAMPLES("/mycommand hello") - }, -``` - -### Step 4: Add Autocomplete - -In `cmd_ac.c`: - -1. Add static function declaration at top: -```c -static char* _mycommand_autocomplete(ProfWin* window, const char* const input, gboolean previous); -``` - -2. Register in `cmd_ac_init()`: -```c -g_hash_table_insert(ac_funcs, "/mycommand", _mycommand_autocomplete); -``` - -3. Implement the function: -```c -static char* -_mycommand_autocomplete(ProfWin* window, const char* const input, gboolean previous) -{ - return NULL; // No autocomplete -} -``` - -## Key Files -- [`src/command/cmd_defs.c`](src/command/cmd_defs.c) - Command definitions -- [`src/command/cmd_defs.h`](src/command/cmd_defs.h) - Type definitions -- [`src/command/cmd_funcs.c`](src/command/cmd_funcs.c) - Handler implementations -- [`src/command/cmd_funcs.h`](src/command/cmd_funcs.h) - Function declarations -- [`src/command/cmd_ac.c`](src/command/cmd_ac.c) - Autocomplete -- [`src/tools/parser.c`](src/tools/parser.c) - Argument parsing -- [`src/ui/ui.h`](src/ui/ui.h) - Console output functions