feat: parliament daemon, login gate, peer context sync (0.9.13)
Login claims the chair, writes a session ticket, and starts a background service for discovery plus revision-based context sync. Password Realm opens require --login (or CST_REALM_PASSWORD); --service/--service-stop manage the resident agent. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+114
-1
@@ -165,7 +165,7 @@ int cst_parliament_claim_chair(const char *instance_id,
|
||||
return cst_parliament_save(&m);
|
||||
}
|
||||
|
||||
int cst_parliament_context_put(const char *text) {
|
||||
static int context_write_file(const char *text) {
|
||||
char path[OS_PATH_MAX], tmp[OS_PATH_MAX + 8];
|
||||
if (context_path(path, sizeof(path)) != 0)
|
||||
return -1;
|
||||
@@ -185,6 +185,12 @@ int cst_parliament_context_put(const char *text) {
|
||||
remove(tmp);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cst_parliament_context_put(const char *text) {
|
||||
if (context_write_file(text) != 0)
|
||||
return -1;
|
||||
cst_parliament_meta_t m;
|
||||
if (cst_parliament_load(&m) == 0) {
|
||||
m.revision++;
|
||||
@@ -290,8 +296,115 @@ char *cst_parliament_login(const char *password, const char *instance_id,
|
||||
cst_buf_puts(&hand, ctx ? ctx : "");
|
||||
free(ctx);
|
||||
free(dev);
|
||||
if (cst_parliament_session_write(instance_id) != 0) {
|
||||
if (err && err_sz)
|
||||
snprintf(err, err_sz, "session ticket write failed");
|
||||
crypto_wipe(keys.seed, sizeof(keys.seed));
|
||||
crypto_wipe(keys.sk, sizeof(keys.sk));
|
||||
crypto_wipe(sk, sizeof(sk));
|
||||
cst_buf_free(&hand);
|
||||
return NULL;
|
||||
}
|
||||
crypto_wipe(keys.seed, sizeof(keys.seed));
|
||||
crypto_wipe(keys.sk, sizeof(keys.sk));
|
||||
crypto_wipe(sk, sizeof(sk));
|
||||
return cst_buf_steal(&hand);
|
||||
}
|
||||
|
||||
static int session_path(char *out, size_t n) {
|
||||
char dir[OS_PATH_MAX];
|
||||
if (cst_realm_dir(dir, sizeof(dir)) != 0)
|
||||
return -1;
|
||||
return os_path_join(out, n, dir, "chair.session");
|
||||
}
|
||||
|
||||
int cst_parliament_session_write(const char *instance_id) {
|
||||
if (!instance_id || !instance_id[0])
|
||||
return -1;
|
||||
char path[OS_PATH_MAX], tmp[OS_PATH_MAX + 8];
|
||||
if (session_path(path, sizeof(path)) != 0)
|
||||
return -1;
|
||||
if (snprintf(tmp, sizeof(tmp), "%s.tmp", path) >= (int)sizeof(tmp))
|
||||
return -1;
|
||||
FILE *f = fopen(tmp, "wb");
|
||||
if (!f)
|
||||
return -1;
|
||||
int ok = fprintf(f, "instance=%s\nissued=%ld\n", instance_id,
|
||||
(long)time(NULL)) > 0;
|
||||
if (fclose(f) != 0)
|
||||
ok = 0;
|
||||
if (!ok) {
|
||||
remove(tmp);
|
||||
return -1;
|
||||
}
|
||||
if (os_rename_replace(tmp, path) != 0) {
|
||||
remove(tmp);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int cst_parliament_session_ok(char *instance_id_out, size_t n) {
|
||||
char path[OS_PATH_MAX];
|
||||
if (session_path(path, sizeof(path)) != 0)
|
||||
return 0;
|
||||
FILE *f = fopen(path, "rb");
|
||||
if (!f)
|
||||
return 0;
|
||||
char line[256], iid[64] = {0};
|
||||
long issued = 0;
|
||||
while (fgets(line, sizeof(line), f)) {
|
||||
if (!strncmp(line, "instance=", 9)) {
|
||||
const char *p = line + 9;
|
||||
size_t i = 0;
|
||||
while (p[i] && p[i] != '\n' && p[i] != '\r' && i + 1 < sizeof(iid)) {
|
||||
iid[i] = p[i];
|
||||
i++;
|
||||
}
|
||||
iid[i] = 0;
|
||||
} else if (!strncmp(line, "issued=", 7))
|
||||
issued = atol(line + 7);
|
||||
}
|
||||
fclose(f);
|
||||
if (!iid[0] || issued <= 0)
|
||||
return 0;
|
||||
/* Ticket valid for 24h of wall clock. */
|
||||
long now = (long)time(NULL);
|
||||
if (now < issued || now - issued > 86400)
|
||||
return 0;
|
||||
cst_parliament_meta_t m;
|
||||
if (cst_parliament_load(&m) != 0)
|
||||
return 0;
|
||||
if (!m.chair_instance[0] || strcmp(m.chair_instance, iid) != 0)
|
||||
return 0;
|
||||
if (instance_id_out && n)
|
||||
snprintf(instance_id_out, n, "%s", iid);
|
||||
return 1;
|
||||
}
|
||||
|
||||
void cst_parliament_session_clear(void) {
|
||||
char path[OS_PATH_MAX];
|
||||
if (session_path(path, sizeof(path)) == 0)
|
||||
remove(path);
|
||||
}
|
||||
|
||||
int cst_parliament_apply_sync(unsigned long revision, const char *parliament_id,
|
||||
const char *project_id, const char *chair,
|
||||
const char *context) {
|
||||
cst_parliament_meta_t m;
|
||||
if (cst_parliament_load(&m) != 0)
|
||||
return -1;
|
||||
if (revision <= m.revision)
|
||||
return 0;
|
||||
if (parliament_id && parliament_id[0])
|
||||
snprintf(m.parliament_id, sizeof(m.parliament_id), "%s", parliament_id);
|
||||
if (project_id)
|
||||
snprintf(m.project_id, sizeof(m.project_id), "%s", project_id);
|
||||
if (chair)
|
||||
snprintf(m.chair_instance, sizeof(m.chair_instance), "%s", chair);
|
||||
m.revision = revision;
|
||||
snprintf(m.status, sizeof(m.status), "%s", "open");
|
||||
if (context_write_file(context ? context : "") != 0)
|
||||
return -1;
|
||||
return cst_parliament_save(&m);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user