Initial CST-Agent: portable Linux/Termux/Windows coding agent.

Vendored sashidown, OpenAI-compatible env (OPENAI_*), and bootstrap scripts.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
WHC
2026-09-07 22:42:32 +08:00
co-authored by Cursor
commit 1f1fcba7ad
75 changed files with 14940 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
CC ?= gcc
CFLAGS ?= -std=c11 -Wall -Wextra -O2
.PHONY: all clean test
all: calc
calc: calc.c
$(CC) $(CFLAGS) -o $@ $<
test: calc
./tests/smoke.sh
clean:
rm -f calc
+19
View File
@@ -0,0 +1,19 @@
# mini_calc
Tiny integer calculator CLI for CST-Agent e2e demos.
## Ops
`add` `sub` `mul` `div` — all four work (see `make test`).
```bash
./calc add 2 3 # → 5
./calc div 8 2 # → 4
```
## Build
```bash
make
make test
```
+11
View File
@@ -0,0 +1,11 @@
# 任务:修好 mini_calc
你在一个很小的 C 项目里。请完成下列事项后结束(不要无关重构):
1. 阅读 `README.md`、`calc.c`、`tests/smoke.sh`。
2. 修复 `add` 的 off-by-one bug(应为 `a+b`,不是 `a+b+1`)。
3. 实现真正的整数除法 `div_ints`(`a/b`,调用方已保证 `b!=0`)。
4. 运行 `make test`,确保全部用例通过。
5. 用简短中文说明你改了什么。
可用工具:`read_file`、`run_shell`、`write_file` / `apply_patch`。工作区根目录就是本项目。
+58
View File
@@ -0,0 +1,58 @@
/* mini_calc — intentionally broken fixture for CST-Agent e2e / paper case study.
*
* Bugs (for the agent to fix):
* 1) add(): off-by-one — returns a+b+1
* 2) div(): missing — only stub returns 0
* README claims all four ops work (false until fixed).
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int add(int a, int b) {
/* BUG: off-by-one */
return a + b + 1;
}
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int div_ints(int a, int b) {
/* BUG: not implemented */
(void)a;
(void)b;
return 0;
}
static void usage(const char *argv0) {
fprintf(stderr, "Usage: %s <add|sub|mul|div> <a> <b>\n", argv0);
}
int main(int argc, char **argv) {
if (argc != 4) {
usage(argv[0]);
return 2;
}
int a = atoi(argv[2]);
int b = atoi(argv[3]);
int r = 0;
if (strcmp(argv[1], "add") == 0)
r = add(a, b);
else if (strcmp(argv[1], "sub") == 0)
r = sub(a, b);
else if (strcmp(argv[1], "mul") == 0)
r = mul(a, b);
else if (strcmp(argv[1], "div") == 0) {
if (b == 0) {
fprintf(stderr, "div by zero\n");
return 3;
}
r = div_ints(a, b);
} else {
usage(argv[0]);
return 2;
}
printf("%d\n", r);
return 0;
}
+30
View File
@@ -0,0 +1,30 @@
#!/usr/bin/env bash
# Smoke tests for mini_calc. Exit 0 only when add/sub/mul/div are correct.
set -euo pipefail
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
CALC="$ROOT/calc"
fail=0
expect() {
local op=$1 a=$2 b=$3 want=$4
local got
got="$("$CALC" "$op" "$a" "$b")"
if [[ "$got" != "$want" ]]; then
echo "FAIL: $op $a $b → got '$got' want '$want'"
fail=1
else
echo "ok: $op $a $b → $got"
fi
}
expect add 2 3 5
expect sub 9 4 5
expect mul 3 4 12
expect div 8 2 4
if [[ "$fail" -ne 0 ]]; then
echo "smoke: FAILED"
exit 1
fi
echo "smoke: PASSED"
exit 0
+10
View File
@@ -0,0 +1,10 @@
CXX = g++
CXXFLAGS = -O2 -std=c++17 -Wall -Wextra
snake: snake.cpp
$(CXX) $(CXXFLAGS) -o snake snake.cpp
clean:
rm -f snake
.PHONY: clean
+51
View File
@@ -0,0 +1,51 @@
# Snake Game
A classic terminal-based Snake game written in C++17.
## Features
- Smooth snake movement using POSIX terminal I/O
- WASD or Arrow keys for movement
- Food spawning and snake growth
- Wall and self-collision detection
- Score tracking
- Pause functionality (P key)
- Clean terminal rendering
## Build
```bash
make
```
This compiles `snake.cpp` with optimization level O2 and C++17 standard.
## Run
```bash
./snake
```
## Controls
| Key | Action |
|-----|--------|
| W / ↑ | Move Up |
| S / ↓ | Move Down |
| A / ← | Move Left |
| D / → | Move Right |
| P | Pause/Resume |
| Q | Quit |
## Game Rules
- Eat the `*` food to grow and score points (+10 per food)
- Avoid hitting the walls `#`
- Avoid colliding with your own body `o`
- The snake moves continuously
## Requirements
- GCC/G++ with C++17 support
- POSIX-compliant system (Linux, macOS)
- Terminal with ANSI escape support
+10
View File
@@ -0,0 +1,10 @@
Write a complete C++ terminal Snake game in this workspace.
Requirements:
1. Single file `snake.cpp` (C++17 ok). Use POSIX terminal I/O: raw mode or ncurses; WASD or arrow keys; quit with `q`.
2. Features: moving snake, food, grow on eat, wall or self collision ends game, score printed, board roughly 20x20 or similar.
3. `Makefile` with target `snake` that runs `g++ -O2 -o snake snake.cpp` (link `-lncurses` only if you use ncurses).
4. After writing, run `make` to verify it compiles. Do not need an interactive play session.
5. Brief README.md with how to build and run.
Use write_file / run_shell tools. Prefer implementing yourself rather than downloading.
+224
View File
@@ -0,0 +1,224 @@
#include <iostream>
#include <vector>
#include <deque>
#include <cstdlib>
#include <ctime>
#include <cstring>
#include <chrono>
#include <thread>
#include <conio.h>
// Game constants
constexpr int BOARD_WIDTH = 20;
constexpr int BOARD_HEIGHT = 15;
constexpr char WALL = '#';
constexpr char SNAKE_BODY = 'o';
constexpr char SNAKE_HEAD = 'O';
constexpr char FOOD = '*';
constexpr char EMPTY = ' ';
// Directions
enum class Direction { UP, DOWN, LEFT, RIGHT };
struct Position {
int x, y;
bool operator==(const Position& other) const {
return x == other.x && y == other.y;
}
};
struct GameState {
std::deque<Position> snake;
Position food;
Direction dir;
Direction next_dir;
int score;
bool game_over;
bool paused;
};
char board[BOARD_HEIGHT][BOARD_WIDTH + 1];
void place_food(GameState& state);
void init_board() {
for (int y = 0; y < BOARD_HEIGHT; y++) {
for (int x = 0; x < BOARD_WIDTH; x++) {
if (y == 0 || y == BOARD_HEIGHT - 1 || x == 0 || x == BOARD_WIDTH - 1) {
board[y][x] = WALL;
} else {
board[y][x] = EMPTY;
}
}
board[y][BOARD_WIDTH] = '\0';
}
}
void init_game(GameState& state) {
Position head = {BOARD_WIDTH / 2, BOARD_HEIGHT / 2};
state.snake = {head, {head.x - 1, head.y}, {head.x - 2, head.y}};
state.dir = Direction::RIGHT;
state.next_dir = Direction::RIGHT;
state.score = 0;
state.game_over = false;
state.paused = false;
place_food(state);
}
void place_food(GameState& state) {
Position pos;
bool on_snake;
do {
on_snake = false;
pos.x = 1 + std::rand() % (BOARD_WIDTH - 2);
pos.y = 1 + std::rand() % (BOARD_HEIGHT - 2);
for (const auto& segment : state.snake) {
if (segment == pos) {
on_snake = true;
break;
}
}
} while (on_snake);
state.food = pos;
}
void render(const GameState& state) {
system("cls"); // Windows clear screen
init_board();
board[state.food.y][state.food.x] = FOOD;
for (size_t i = 0; i < state.snake.size(); i++) {
const auto& segment = state.snake[i];
board[segment.y][segment.x] = (i == 0) ? SNAKE_HEAD : SNAKE_BODY;
}
std::cout << "=== SNAKE GAME ===\n";
std::cout << "Score: " << state.score << "\n";
std::cout << "Controls: WASD/Arrows to move, Q to quit, P to pause\n";
std::cout << "==================\n";
for (int y = 0; y < BOARD_HEIGHT; y++) {
std::cout << board[y] << "\n";
}
if (state.game_over) {
std::cout << "\n=== GAME OVER! ===\n";
std::cout << "Final Score: " << state.score << "\n";
std::cout << "Press R to restart or Q to quit.\n";
} else if (state.paused) {
std::cout << "\n=== PAUSED ===\n";
std::cout << "Press P to continue.\n";
}
}
bool kbhit() {
return _kbhit() != 0;
}
char get_char() {
return _getch();
}
void update_direction(GameState& state, Direction new_dir) {
Direction opposite = Direction::UP;
switch (state.dir) {
case Direction::UP: opposite = Direction::DOWN; break;
case Direction::DOWN: opposite = Direction::UP; break;
case Direction::LEFT: opposite = Direction::RIGHT; break;
case Direction::RIGHT: opposite = Direction::LEFT; break;
}
if (new_dir != opposite) {
state.next_dir = new_dir;
}
}
bool move_snake(GameState& state) {
state.dir = state.next_dir;
Position head = state.snake.front();
switch (state.dir) {
case Direction::UP: head.y--; break;
case Direction::DOWN: head.y++; break;
case Direction::LEFT: head.x--; break;
case Direction::RIGHT: head.x++; break;
}
// Check wall collision
if (head.x <= 0 || head.x >= BOARD_WIDTH - 1 ||
head.y <= 0 || head.y >= BOARD_HEIGHT - 1) {
return false;
}
// Check self collision (skip tail as it will move)
for (size_t i = 0; i < state.snake.size() - 1; i++) {
if (state.snake[i] == head) {
return false;
}
}
state.snake.push_front(head);
// Check food
if (head == state.food) {
state.score += 10;
place_food(state);
} else {
state.snake.pop_back();
}
return true;
}
void handle_input(GameState& state) {
if (kbhit()) {
char c = get_char();
if (state.game_over) {
if (c == 'r' || c == 'R') {
init_game(state);
}
return;
}
if (state.paused) {
if (c == 'p' || c == 'P') {
state.paused = false;
}
return;
}
switch (c) {
case 'w': case 'W': case 72: update_direction(state, Direction::UP); break;
case 's': case 'S': case 80: update_direction(state, Direction::DOWN); break;
case 'a': case 'A': case 75: update_direction(state, Direction::LEFT); break;
case 'd': case 'D': case 77: update_direction(state, Direction::RIGHT); break;
case 'q': case 'Q': state.game_over = true; state.score = -1; break;
case 'p': case 'P': state.paused = true; break;
}
}
}
int main() {
std::srand(static_cast<unsigned>(std::time(nullptr)));
GameState state;
init_game(state);
while (true) {
render(state);
if (!state.game_over && !state.paused) {
if (!move_snake(state)) {
state.game_over = true;
}
}
handle_input();
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}