forked from WHC/Hermit
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:
+140
@@ -0,0 +1,140 @@
|
||||
#define _DEFAULT_SOURCE
|
||||
|
||||
#include "cst_agent.h"
|
||||
#include "os_compat.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
/* Config dir via os_compat: ~/.config/cst-agent or %APPDATA%\cst-agent */
|
||||
|
||||
static int credentials_path(char *out, size_t n) {
|
||||
char dir[OS_PATH_MAX];
|
||||
if (os_config_dir(dir, sizeof(dir)) != 0)
|
||||
return -1;
|
||||
return os_path_join(out, n, dir, "credentials");
|
||||
}
|
||||
|
||||
int cst_creds_load_api_key(char *out, size_t out_sz) {
|
||||
if (!out || out_sz < 2)
|
||||
return -1;
|
||||
out[0] = 0;
|
||||
char path[OS_PATH_MAX];
|
||||
if (credentials_path(path, sizeof(path)) != 0)
|
||||
return -1;
|
||||
FILE *fp = fopen(path, "r");
|
||||
if (!fp)
|
||||
return -1;
|
||||
char line[1024];
|
||||
while (fgets(line, sizeof(line), fp)) {
|
||||
if (strncmp(line, "api_key=", 8) != 0)
|
||||
continue;
|
||||
char *v = line + 8;
|
||||
size_t len = strlen(v);
|
||||
while (len > 0 && (v[len - 1] == '\n' || v[len - 1] == '\r'))
|
||||
v[--len] = 0;
|
||||
if (len == 0 || len + 1 > out_sz) {
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
memcpy(out, v, len + 1);
|
||||
fclose(fp);
|
||||
return 0;
|
||||
}
|
||||
fclose(fp);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int cst_creds_save_api_key(const char *key) {
|
||||
if (!key || !key[0])
|
||||
return -1;
|
||||
char dir[OS_PATH_MAX], path[OS_PATH_MAX];
|
||||
if (os_config_dir(dir, sizeof(dir)) != 0)
|
||||
return -1;
|
||||
if (os_mkdir(dir, 0700) != 0)
|
||||
return -1;
|
||||
if (credentials_path(path, sizeof(path)) != 0)
|
||||
return -1;
|
||||
FILE *fp = fopen(path, "w");
|
||||
if (!fp)
|
||||
return -1;
|
||||
fprintf(fp, "api_key=%s\n", key);
|
||||
fprintf(fp, "api_base=https://api.minimax.cn/v1\n");
|
||||
fprintf(fp, "model=MiniMax-M2.7\n");
|
||||
fclose(fp);
|
||||
(void)os_chmod_private(path);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Zenity on Unix; stdin prompt elsewhere / when zenity missing. */
|
||||
int cst_creds_prompt_api_key(char *out, size_t out_sz) {
|
||||
if (!out || out_sz < 2)
|
||||
return -1;
|
||||
out[0] = 0;
|
||||
|
||||
#ifndef _WIN32
|
||||
FILE *fp = popen(
|
||||
"zenity --password --title='CST-Agent / MiniMax' "
|
||||
"--text='请输入 MiniMax API Key(将保存到配置目录 credentials)' "
|
||||
"2>/dev/null",
|
||||
"r");
|
||||
if (fp) {
|
||||
if (fgets(out, (int)out_sz, fp)) {
|
||||
int st = pclose(fp);
|
||||
size_t len = strlen(out);
|
||||
while (len > 0 && (out[len - 1] == '\n' || out[len - 1] == '\r'))
|
||||
out[--len] = 0;
|
||||
if (st == 0 && len > 0)
|
||||
return 0;
|
||||
} else {
|
||||
pclose(fp);
|
||||
}
|
||||
out[0] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Fallback: console prompt (headless / Windows / no zenity). */
|
||||
fprintf(stderr, "CST-Agent: enter MiniMax API Key (saved to config dir): ");
|
||||
fflush(stderr);
|
||||
if (!fgets(out, (int)out_sz, stdin)) {
|
||||
out[0] = 0;
|
||||
return -1;
|
||||
}
|
||||
size_t len = strlen(out);
|
||||
while (len > 0 && (out[len - 1] == '\n' || out[len - 1] == '\r'))
|
||||
out[--len] = 0;
|
||||
if (len == 0) {
|
||||
out[0] = 0;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cst_creds_ensure_api_key(char *out, size_t out_sz) {
|
||||
const char *env = getenv("CST_API_KEY");
|
||||
if (!env || !env[0])
|
||||
env = getenv("MINIMAX_API_KEY");
|
||||
if (!env || !env[0])
|
||||
env = getenv("OPENAI_API_KEY");
|
||||
if (env && env[0]) {
|
||||
snprintf(out, out_sz, "%s", env);
|
||||
return 0;
|
||||
}
|
||||
if (cst_creds_load_api_key(out, out_sz) == 0 && out[0])
|
||||
return 0;
|
||||
if (cst_creds_prompt_api_key(out, out_sz) != 0)
|
||||
return -1;
|
||||
if (cst_creds_save_api_key(out) != 0)
|
||||
fprintf(stderr, "warning: failed to save credentials file\n");
|
||||
else
|
||||
fprintf(stderr, "saved API key to config directory\n");
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user