delete incorrectly uploaded skill

This commit is contained in:
2026-04-30 18:21:23 +00:00
parent 1fb2940ba8
commit 9020af7407

View File

@@ -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 <name> <url>", "/ai set token <provider> <token>")
CMD_DESC("Interact with AI models via OpenAI-compatible APIs.")
CMD_ARGS({ "", "Display current AI settings" },
{ "set provider <name> <url>", "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 [<arg>]")
CMD_DESC("My new command description.")
CMD_ARGS({ "<arg>", "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