forked from WHC/Hermit
Usability pass: tool registry, TUI polish, saved keys and settings
Tools - Table-driven tool registry with permission classes and default/minimal profiles; new tools: edit_file, list_dir, glob, grep, delete_file, move_file, todo_write, web_fetch, ask_user (plus read_file paging). - Built-in Myers diff; write tools return unified diffs. - Persistent permission rules (.agent/permissions.json), per-turn undo snapshots (.agent/undo), AGENTS.md project notes, auto-compact at 80% of the model context, cancellable run_shell with process-group kill. TUI - Table-driven slash commands: /provider /key /effort /status /tools /permissions /yolo /undo /retry /diff /export /copy /rename /delete /init /max-steps /todo, with / and @ completion. - Permission modal with diff and prefix rules, ask_user modal, todo panel, header with model/effort/context, bracketed paste, line editing, wide-char cursor, NO_COLOR and ASCII fallback; Esc never quits. Startup and configuration - API keys are entered in the TUI (hidden) and saved per provider in <config>/credentials (0600); env variables are only a fallback. - Last provider, per-provider model and reasoning effort are remembered in <config>/settings.json; --effort/-e and /effort send reasoning_effort (low|medium|high|max) to models that accept it. - DeepSeek preset uses deepseek-flash / deepseek-v4-pro. - Session flags --new/--continue/--resume/--list-sessions, --yolo, --confirm. Compatibility and tests - ncurses detection, macOS/Homebrew support, make install, XDG config dir, POSIX cleanups; Gitea CI (gcc/clang/asan/musl/macOS). - Unit tests for diff, fs tools, registry, undo/perms and config; e2e fixtures multi_file_refactor and ask_or_todo; vendored cJSON.
This commit is contained in:
@@ -1,16 +1,65 @@
|
||||
CC ?= gcc
|
||||
CFLAGS ?= -std=c11 -Wall -Wextra -O2 -g
|
||||
SD_DIR := vendor/sashidown
|
||||
CPPFLAGS += -Iinclude -I$(SD_DIR)/include -D_XOPEN_SOURCE_EXTENDED
|
||||
LDFLAGS += -L$(SD_DIR)
|
||||
LDLIBS += -lsashidown -lm -lcurl -lncursesw -lpthread
|
||||
CJSON_DIR := vendor/cjson
|
||||
PKG_CONFIG ?= pkg-config
|
||||
PREFIX ?= /usr/local
|
||||
DESTDIR ?=
|
||||
UNAME_S := $(shell uname -s 2>/dev/null)
|
||||
|
||||
SRC = \
|
||||
# macOS: Homebrew ncurses/curl are keg-only, so point pkg-config at them.
|
||||
# (macOS ships GNU make 3.81, whose $(shell) ignores exported variables.)
|
||||
PKG_ENV :=
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
BREW_PREFIX := $(shell brew --prefix 2>/dev/null)
|
||||
ifneq ($(BREW_PREFIX),)
|
||||
PKG_ENV := PKG_CONFIG_PATH="$(BREW_PREFIX)/opt/ncurses/lib/pkgconfig:$(BREW_PREFIX)/opt/curl/lib/pkgconfig:$$PKG_CONFIG_PATH"
|
||||
endif
|
||||
CPPFLAGS += -D_DARWIN_C_SOURCE
|
||||
endif
|
||||
PKGC = $(PKG_ENV) $(PKG_CONFIG)
|
||||
|
||||
# Wide-character curses: ncursesw, else ncurses (macOS/BSD build it wide).
|
||||
CURSES_PC := $(shell for p in ncursesw ncurses; do $(PKGC) --exists $$p 2>/dev/null && { echo $$p; exit 0; }; done)
|
||||
ifneq ($(CURSES_PC),)
|
||||
CURSES_CFLAGS := $(shell $(PKGC) --cflags $(CURSES_PC))
|
||||
CURSES_LIBS := $(shell $(PKGC) --libs $(CURSES_PC))
|
||||
else ifeq ($(UNAME_S),Darwin)
|
||||
CURSES_LIBS := -lncurses
|
||||
else
|
||||
CURSES_LIBS := -lncursesw
|
||||
endif
|
||||
|
||||
CURL_CFLAGS := $(shell $(PKGC) --cflags libcurl 2>/dev/null)
|
||||
CURL_LIBS := $(shell $(PKGC) --libs libcurl 2>/dev/null)
|
||||
ifeq ($(strip $(CURL_LIBS)),)
|
||||
CURL_LIBS := -lcurl
|
||||
endif
|
||||
|
||||
PKG_CFLAGS := $(CURL_CFLAGS) $(CURSES_CFLAGS)
|
||||
PKG_LIBS := $(CURL_LIBS) $(CURSES_LIBS)
|
||||
|
||||
CPPFLAGS += -Iinclude -I$(SD_DIR)/include -I$(CJSON_DIR) -D_XOPEN_SOURCE_EXTENDED $(PKG_CFLAGS)
|
||||
LDFLAGS += -L$(SD_DIR)
|
||||
LDLIBS += -lsashidown -lm $(PKG_LIBS) -lpthread
|
||||
|
||||
CORE_SRC = \
|
||||
$(CJSON_DIR)/cJSON.c \
|
||||
src/util.c \
|
||||
src/ctl_parse.c \
|
||||
src/os_compat.c \
|
||||
src/sandbox.c \
|
||||
src/session.c \
|
||||
src/tools/tools.c \
|
||||
src/tools/patch.c \
|
||||
src/tools/registry.c \
|
||||
src/tools/fs_tools.c \
|
||||
src/tools/agent_tools.c \
|
||||
src/tools/web.c \
|
||||
src/tools/diff.c \
|
||||
src/undo.c \
|
||||
src/permissions.c \
|
||||
src/settings.c \
|
||||
src/llm_openai.c \
|
||||
src/agent_loop.c \
|
||||
src/agent_store.c \
|
||||
@@ -18,16 +67,36 @@ SRC = \
|
||||
src/creds.c \
|
||||
src/mm_tool.c \
|
||||
src/models.c \
|
||||
src/tui.c \
|
||||
src/main.c
|
||||
src/metrics.c
|
||||
|
||||
SRC = $(CORE_SRC) src/tui.c src/main.c
|
||||
OBJ = $(SRC:.c=.o)
|
||||
HDRS = $(wildcard include/*.h) $(wildcard src/tools/*.h) $(CJSON_DIR)/cJSON.h
|
||||
|
||||
.PHONY: all clean check demo sashidown-lib cmake-gcc cmake-clang
|
||||
TESTS = \
|
||||
tests/test_ctl_frontier \
|
||||
tests/test_ctl_heredoc \
|
||||
tests/test_json_baseline \
|
||||
tests/test_replay_starvation \
|
||||
tests/test_replay_real \
|
||||
tests/test_mm_tool \
|
||||
tests/test_llm_body \
|
||||
tests/test_sse_decode \
|
||||
tests/test_apply_patch \
|
||||
tests/test_session_roundtrip \
|
||||
tests/test_shell \
|
||||
tests/test_diff \
|
||||
tests/test_tools_fs \
|
||||
tests/test_registry \
|
||||
tests/test_undo \
|
||||
tests/test_config
|
||||
|
||||
TEST_LIBS = -lm $(CURL_LIBS) -lpthread
|
||||
|
||||
.PHONY: all clean check demo sashidown-lib cmake-gcc cmake-clang asan install uninstall
|
||||
|
||||
all: sashidown-lib cst-agent
|
||||
|
||||
# Optional CMake entrypoints (same sources)
|
||||
cmake-gcc:
|
||||
cmake -B build-gcc -DCMAKE_C_COMPILER=gcc -DCST_BUILD_TUI=ON
|
||||
cmake --build build-gcc
|
||||
@@ -43,35 +112,51 @@ sashidown-lib:
|
||||
cst-agent: $(OBJ) $(SD_DIR)/libsashidown.a
|
||||
$(CC) $(CFLAGS) -o $@ $(OBJ) $(LDFLAGS) $(LDLIBS)
|
||||
|
||||
src/%.o: src/%.c include/ctl.h include/cst_agent.h
|
||||
%.o: %.c $(HDRS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
src/tools/%.o: src/tools/%.c include/ctl.h include/cst_agent.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
src/tui.o: src/tui.c include/cst_agent.h $(SD_DIR)/include/sashidown.h
|
||||
src/tui.o: src/tui.c $(HDRS) $(SD_DIR)/include/sashidown.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -c -o $@ $<
|
||||
|
||||
tests/test_ctl_frontier: tests/test_ctl_frontier.c src/ctl_parse.c include/ctl.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_ctl_frontier.c src/ctl_parse.c
|
||||
|
||||
tests/test_json_baseline: tests/test_json_baseline.c src/json_baseline.c include/cst_agent.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_json_baseline.c src/json_baseline.c
|
||||
tests/test_ctl_heredoc: tests/test_ctl_heredoc.c src/ctl_parse.c include/ctl.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_ctl_heredoc.c src/ctl_parse.c
|
||||
|
||||
tests/test_replay_starvation: tests/test_replay_starvation.c src/ctl_parse.c src/json_baseline.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_replay_starvation.c src/ctl_parse.c src/json_baseline.c
|
||||
tests/test_json_baseline: tests/test_json_baseline.c src/json_baseline.c $(CJSON_DIR)/cJSON.c $(HDRS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_json_baseline.c src/json_baseline.c $(CJSON_DIR)/cJSON.c -lm
|
||||
|
||||
tests/test_replay_starvation: tests/test_replay_starvation.c src/ctl_parse.c src/json_baseline.c $(CJSON_DIR)/cJSON.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_replay_starvation.c src/ctl_parse.c src/json_baseline.c $(CJSON_DIR)/cJSON.c -lm
|
||||
|
||||
tests/test_replay_real: tests/test_replay_real.c src/ctl_parse.c src/json_baseline.c $(CJSON_DIR)/cJSON.c
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_replay_real.c src/ctl_parse.c src/json_baseline.c $(CJSON_DIR)/cJSON.c -lm
|
||||
|
||||
tests/test_mm_tool: tests/test_mm_tool.c src/mm_tool.c include/mm_tool.h
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ tests/test_mm_tool.c src/mm_tool.c
|
||||
|
||||
check: tests/test_ctl_frontier tests/test_json_baseline tests/test_replay_starvation tests/test_mm_tool
|
||||
./tests/test_ctl_frontier
|
||||
./tests/test_json_baseline
|
||||
./tests/test_replay_starvation
|
||||
./tests/test_mm_tool
|
||||
tests/test_%: tests/test_%.c $(CORE_SRC) $(HDRS)
|
||||
$(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $< $(CORE_SRC) $(TEST_LIBS)
|
||||
|
||||
check: $(TESTS)
|
||||
@set -e; for t in $(TESTS); do echo "== $$t"; ./$$t; done
|
||||
|
||||
# AddressSanitizer + UBSan build of the agent and all tests.
|
||||
asan:
|
||||
$(MAKE) clean
|
||||
$(MAKE) sashidown-lib
|
||||
$(MAKE) CFLAGS="-std=c11 -Wall -Wextra -O1 -g -fsanitize=address,undefined -fno-sanitize-recover=undefined -fno-omit-frame-pointer" cst-agent check
|
||||
|
||||
demo: cst-agent
|
||||
./cst-agent --demo-ctl --workspace .
|
||||
|
||||
clean:
|
||||
rm -f $(OBJ) cst-agent tests/test_ctl_frontier tests/test_json_baseline tests/test_replay_starvation tests/test_mm_tool
|
||||
rm -f $(OBJ) cst-agent $(TESTS)
|
||||
|
||||
install: cst-agent
|
||||
install -d "$(DESTDIR)$(PREFIX)/bin"
|
||||
install -m 0755 cst-agent "$(DESTDIR)$(PREFIX)/bin/cst-agent"
|
||||
|
||||
uninstall:
|
||||
rm -f "$(DESTDIR)$(PREFIX)/bin/cst-agent"
|
||||
|
||||
Reference in New Issue
Block a user