From 5a140178a1acb093586c8071525711d465242cd6 Mon Sep 17 00:00:00 2001 From: Carl Niklas Rydberg Date: Sat, 24 Jan 2026 22:16:40 +0100 Subject: [PATCH] Add minimal Workspace UI consuming /v1/space/workspace --- README.md | 10 ++ src/amduatd.c | 312 ++++++++++++++++++++++++++++++++++++++++++++ src/amduatd_space.c | 19 +-- 3 files changed, 323 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index f65eb44..f580955 100644 --- a/README.md +++ b/README.md @@ -339,6 +339,13 @@ curl --unix-socket amduatd.sock \ -H 'X-Amduat-Space: demo' ``` +## Workspace UI + +`/workspace` serves a minimal, human-facing page that consumes +`/v1/space/workspace` and `/v1/space/mounts/sync/until`. It is a convenience +view for inspection and manual sync control, not a stable API. For +programmatic use, call the `/v1/*` endpoints directly. + ## Space mounts sync (track mounts) `/v1/space/mounts/sync/until` runs the federation pull/until loop for every @@ -554,6 +561,9 @@ When the daemon uses the `fs` store backend, index-only checks are reported as - response: `{program_ref}` - `POST /v1/context_frames` +UI (human-facing, not an API contract): +- `GET /workspace` → minimal workspace snapshot + sync controls (uses `/v1/space/workspace`) + Receipt example (with v1.1 fields): ```json diff --git a/src/amduatd.c b/src/amduatd.c index 1415fac..453c4f6 100644 --- a/src/amduatd.c +++ b/src/amduatd.c @@ -133,6 +133,304 @@ static const uint64_t AMDUATD_FED_TICK_MS = 1000u; static const size_t AMDUATD_FED_INGEST_MAX_BYTES = 8u * 1024u * 1024u; static const size_t AMDUATD_REF_TEXT_MAX = 256u; static const size_t AMDUATD_SPACE_MANIFEST_MAX_BYTES = 64u * 1024u; +static const char k_amduatd_workspace_html[] = + "\n" + "\n" + "\n" + " \n" + " \n" + " amduatd workspace\n" + " \n" + "\n" + "\n" + "
\n" + "

Workspace snapshot

\n" + "

Local, read-only view of the effective space.

\n" + "
\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
\n" + "\n" + " \n" + "\n" + "
\n" + "
\n" + "

Effective space

\n" + "
-
\n" + "

Store backend

\n" + "
-
\n" + "

Federation

\n" + "
-
\n" + "

Manifest ref

\n" + "
-
\n" + "
\n" + "
\n" + "

Store capabilities

\n" + "
-
\n" + "

Sync result

\n" + "
-
\n" + " \n" + "
\n" + "
\n" + "\n" + "
\n" + "

Mounts

\n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + " \n" + "
NamePeerRemote spaceModeCursorStatus
\n" + "
\n" + "\n" + "
\n" + "

Raw workspace JSON

\n" + "
\n"
+    "    
\n" + "
\n" + "\n" + " \n" + "\n" + "\n"; static const char k_amduatd_contract_v1_json[] = "{" "\"contract\":\"AMDUATD/API/1\"," @@ -1848,6 +2146,16 @@ mounts_sync_cleanup: return ok; } +static bool amduatd_handle_get_workspace_ui(int fd) { + return amduatd_http_send_status(fd, + 200, + "OK", + "text/html; charset=utf-8", + (const uint8_t *)k_amduatd_workspace_html, + strlen(k_amduatd_workspace_html), + false); +} + static bool amduatd_handle_get_space_workspace( int fd, amduat_asl_store_t *store, @@ -9101,6 +9409,10 @@ static bool amduatd_handle_conn(int fd, ok = amduatd_handle_meta(fd, cfg, api_contract_ref, false); goto conn_cleanup; } + if (strcmp(req.method, "GET") == 0 && strcmp(no_query, "/workspace") == 0) { + ok = amduatd_handle_get_workspace_ui(fd); + goto conn_cleanup; + } if (strcmp(req.method, "HEAD") == 0 && strcmp(no_query, "/v1/meta") == 0) { ok = amduatd_handle_meta(fd, cfg, api_contract_ref, true); goto conn_cleanup; diff --git a/src/amduatd_space.c b/src/amduatd_space.c index 37c1839..0aab475 100644 --- a/src/amduatd_space.c +++ b/src/amduatd_space.c @@ -8,24 +8,7 @@ #include static bool amduatd_space_name_valid(const char *name) { - size_t i; - size_t len; - if (name == NULL) { - return false; - } - len = strlen(name); - if (len == 0 || len > 64) { - return false; - } - for (i = 0; i < len; ++i) { - unsigned char c = (unsigned char)name[i]; - if ((c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || c == '_' || - c == '-' || c == '.' || c == '/') { - continue; - } - return false; - } - return true; + return amduat_asl_pointer_name_is_valid(name); } static bool amduatd_space_strdup_cstr(const char *s, char **out) {