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
+137
View File
@@ -0,0 +1,137 @@
#include "table_stats.h"
#include "line_index.h"
#include <string.h>
int table_is_separator_row(const char *line, size_t len)
{
int pipes = 0;
int dashes = 0;
for (size_t i = 0; i < len; i++) {
char c = line[i];
if (c == '|') pipes++;
else if (c == '-' || c == ':' || c == ' ') dashes++;
else if (c != '\r') return 0;
}
return pipes >= 1 && dashes > 0;
}
/* GFM: leading/trailing '|' are delimiters, not empty cells. */
int table_count_cols(const char *line, size_t len, int *has_pipe)
{
if (has_pipe)
*has_pipe = 0;
while (len > 0 && line[len - 1] == '\r')
len--;
size_t start = 0;
size_t end = len;
while (start < end && (line[start] == ' ' || line[start] == '\t'))
start++;
if (start < end && line[start] == '|') {
start++;
if (has_pipe)
*has_pipe = 1;
}
while (end > start && (line[end - 1] == ' ' || line[end - 1] == '\t'))
end--;
if (end > start && line[end - 1] == '|') {
end--;
if (has_pipe)
*has_pipe = 1;
}
if (start >= end)
return 1;
int cols = 1;
for (size_t i = start; i < end; i++) {
if (line[i] == '|') {
cols++;
if (has_pipe)
*has_pipe = 1;
}
}
return cols > SASHIDOWN_MAX_COLS ? SASHIDOWN_MAX_COLS : cols;
}
static size_t te_line_end(sashidown_ctx_t *ctx, const char *input, size_t len, size_t pos)
{
if (ctx && ctx->line_ix)
return line_end_ix((line_index_t *)ctx->line_ix, input, len, pos);
const char *hit = memchr(input + pos, '\n', len - pos);
return hit ? (size_t)(hit - input) : len;
}
static size_t te_skip_line(sashidown_ctx_t *ctx, const char *input, size_t len, size_t pos)
{
if (ctx && ctx->line_ix)
return skip_line_ix((line_index_t *)ctx->line_ix, input, len, pos);
pos = te_line_end(NULL, input, len, pos);
if (pos < len)
pos++;
return pos;
}
static int line_has_pipe_raw(const char *line, size_t len)
{
return memchr(line, '|', len) != NULL;
}
static int try_parse_table(sashidown_ctx_t *ctx, const char *input, size_t len,
size_t line_start, table_entry_t *e)
{
size_t le = te_line_end(ctx, input, len, line_start);
int has_pipe = 0;
int cols = table_count_cols(input + line_start, le - line_start, &has_pipe);
if (!has_pipe)
return 0;
size_t sep = te_skip_line(ctx, input, len, line_start);
if (sep >= len) {
if (ctx && ctx->line_ix)
line_index_seek((line_index_t *)ctx->line_ix, line_start);
return 0;
}
size_t sep_le = te_line_end(ctx, input, len, sep);
if (!table_is_separator_row(input + sep, sep_le - sep)) {
if (ctx && ctx->line_ix)
line_index_seek((line_index_t *)ctx->line_ix, line_start);
return 0;
}
size_t pos = te_skip_line(ctx, input, len, sep);
e->start = line_start;
e->body_start = pos;
e->cols = cols; /* GFM: header determines column count */
e->body_rows = 0;
e->valid = 1;
while (pos < len) {
le = te_line_end(ctx, input, len, pos);
size_t line_len = le - pos;
if (!line_has_pipe_raw(input + pos, line_len))
break;
if (table_is_separator_row(input + pos, line_len))
break;
e->body_rows++;
pos = te_skip_line(ctx, input, len, pos);
}
e->end = pos;
return 1;
}
int table_try_parse_at(sashidown_ctx_t *ctx, const char *input, size_t len,
size_t pos, table_entry_t *e)
{
e->start = 0;
e->end = 0;
e->body_start = 0;
e->cols = 0;
e->body_rows = 0;
e->valid = 0;
return try_parse_table(ctx, input, len, pos, e);
}