diff --git a/README.md b/README.md index ab81b85..dadce0e 100644 --- a/README.md +++ b/README.md @@ -54,11 +54,11 @@ Skills compose by adoption-list order (`10123`) and trigger tags carry runtime e Didactyl will support local inference, which is very privacy preserving. Remote inference does however have it's advantages, and in those cases Didactyl supports using Bitcoin Lightning and eCash inference providers. -## Current Status — v0.2.70 +## Current Status — v0.2.71 **Active build — this project is barely working. Experiment at your own risk.** -> Last release update: v0.2.70 — Add AGENTS.md with build instructions, project overview, coding conventions, and key architecture decisions +> Last release update: v0.2.71 — Fix Step 7 skill picker: numbers now toggle X/space, edit moved to separate 'e' command - Connects to configured relays with auto-reconnect and relay state transition logging - Publishes configured startup events per relay as each relay becomes connected diff --git a/src/main.h b/src/main.h index 738d9e2..e166153 100644 --- a/src/main.h +++ b/src/main.h @@ -12,8 +12,8 @@ // Using DIDACTYL_ prefix to avoid conflicts with nostr_core_lib VERSION macros #define DIDACTYL_VERSION_MAJOR 0 #define DIDACTYL_VERSION_MINOR 2 -#define DIDACTYL_VERSION_PATCH 70 -#define DIDACTYL_VERSION "v0.2.70" +#define DIDACTYL_VERSION_PATCH 71 +#define DIDACTYL_VERSION "v0.2.71" // Agent metadata #define DIDACTYL_NAME "Didactyl" diff --git a/src/setup_wizard.c b/src/setup_wizard.c index 298f3bf..e21f0bd 100644 --- a/src/setup_wizard.c +++ b/src/setup_wizard.c @@ -773,14 +773,14 @@ static int prompt_skill_configuration(didactyl_config_t* cfg, const char* agent_ char input[WIZARD_LINE_MAX]; for (;;) { render_wizard_page_header("Step 7 of 8", "New Agent Setup -- Skills"); - fprintf(stderr, " Skills (enter a number to cycle: X=enabled, E=edit, space=disabled):\n"); + fprintf(stderr, " Skills (enter a number to toggle: X=enabled, space=disabled):\n"); for (int i = 0; i < skill_count; i++) { - char state_char = skill_state[i] == 1 ? 'X' : (skill_state[i] == 2 ? 'E' : ' '); + char state_char = skill_state[i] == 1 ? 'X' : ' '; fprintf(stderr, " %d. [%c] %s\n", i + 1, state_char, skill_d_tags[i] ? skill_d_tags[i] : ""); } fprintf(stderr, "\n"); - fprintf(stderr, " Commands: a=add custom skill, d=done, b=back, q=quit\n"); + fprintf(stderr, " Commands: a=add custom skill, e=edit skill, d=done, b=back, q=quit\n"); if (read_line_prompt("> ", input, sizeof(input)) != 0) { for (int i = 0; i < skill_count; i++) { free(skill_d_tags[i]); free(skill_contents[i]); free(skill_tags[i]); } return -1; @@ -801,23 +801,8 @@ static int prompt_skill_configuration(didactyl_config_t* cfg, const char* agent_ if (is_number) { int idx = atoi(trimmed) - 1; if (idx >= 0 && idx < skill_count) { - /* Cycle: 0→1 (enabled), 1→2 (edit), 2→0 (disabled) */ - skill_state[idx]++; - if (skill_state[idx] > 2) skill_state[idx] = 0; - /* If we entered edit mode, open the system editor. */ - if (skill_state[idx] == 2) { - fprintf(stderr, "\n Opening editor for skill '%s'...\n", skill_d_tags[idx] ? skill_d_tags[idx] : ""); - char* edited = NULL; - if (edit_content_with_editor(skill_contents[idx], &edited) == 0 && edited) { - free(skill_contents[idx]); - skill_contents[idx] = edited; - fprintf(stderr, "%sSkill '%s' updated.%s\n", ANSI_YELLOW, skill_d_tags[idx] ? skill_d_tags[idx] : "", ANSI_RESET); - } else { - fprintf(stderr, "%sEdit cancelled or failed; keeping original content.%s\n", ANSI_RED, ANSI_RESET); - } - /* After edit, set back to enabled. */ - skill_state[idx] = 1; - } + /* Toggle: 0→1 (enabled), 1→0 (disabled) */ + skill_state[idx] = skill_state[idx] ? 0 : 1; } else { fprintf(stderr, "%sInvalid skill number (1-%d).%s\n", ANSI_RED, skill_count, ANSI_RESET); } @@ -852,6 +837,32 @@ static int prompt_skill_configuration(didactyl_config_t* cfg, const char* agent_ for (int i = 0; i < skill_count; i++) { free(skill_d_tags[i]); free(skill_contents[i]); free(skill_tags[i]); } return 0; } + if (c == 'e') { + char num_str[WIZARD_LINE_MAX] = {0}; + if (read_line_prompt(" Edit skill number: ", num_str, sizeof(num_str)) != 0) { + for (int i = 0; i < skill_count; i++) { free(skill_d_tags[i]); free(skill_contents[i]); free(skill_tags[i]); } + return -1; + } + if (line_is_quit(num_str)) { + for (int i = 0; i < skill_count; i++) { free(skill_d_tags[i]); free(skill_contents[i]); free(skill_tags[i]); } + return -1; + } + int e_idx = atoi(num_str) - 1; + if (e_idx >= 0 && e_idx < skill_count) { + fprintf(stderr, "\n Opening editor for skill '%s'...\n", skill_d_tags[e_idx] ? skill_d_tags[e_idx] : ""); + char* edited = NULL; + if (edit_content_with_editor(skill_contents[e_idx], &edited) == 0 && edited) { + free(skill_contents[e_idx]); + skill_contents[e_idx] = edited; + fprintf(stderr, "%sSkill '%s' updated.%s\n", ANSI_YELLOW, skill_d_tags[e_idx] ? skill_d_tags[e_idx] : "", ANSI_RESET); + } else { + fprintf(stderr, "%sEdit cancelled or failed; keeping original content.%s\n", ANSI_RED, ANSI_RESET); + } + } else { + fprintf(stderr, "%sInvalid skill number (1-%d).%s\n", ANSI_RED, skill_count, ANSI_RESET); + } + continue; + } if (c == 'a') { if (skill_count >= SKILL_PICKER_MAX) { fprintf(stderr, "%sMaximum skill count reached.%s\n", ANSI_RED, ANSI_RESET);