teams: zeroclaw container coords + coding_readwrite risk profile
Slice 3a of the per-loop-team arc — prerequisites for the runtime spawn hookup that lands in 3b: 0046 migration - ALTER TABLE teams ADD zeroclaw_container TEXT - ALTER TABLE teams ADD zeroclaw_gateway_url TEXT Both NULL until the runtime's spawn_team fn (3b) provisions the container and persists its coordinates. Mirrors the shape already on research_topics (0038) so the resolver code path can generalize. cm-db - team_container_coords / set_team_container_coords: dynamic sqlx::query() readers/writers for the new columns. Runtime template (gw-04, out-of-band edit on /var/lib/clawmates-runtime-template/config.toml + shared runtime /root/clawmates-runtime/data/.zeroclaw/config.toml) - New [risk_profiles.coding_readwrite]: adds file_write + shell on top of the research_readonly baseline. Still excludes http_request / browser / composio (egress stays behind the MCP door). Slice 3b will add spawn_team (bind-mounts paired-topic repo, uses team-scoped state dir, injects team.risk_profile into the config template) and rewire topology_worker to resolve gateway URL through team_id when the loop has one.
This commit is contained in:
@@ -372,3 +372,56 @@ pub async fn set_team_for_research_topic(
|
|||||||
.await?;
|
.await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 0046: read the team's per-container coordinates. Both fields NULL
|
||||||
|
/// means the team has never spawned; the runtime provisions on first
|
||||||
|
/// iteration.
|
||||||
|
pub async fn team_container_coords(
|
||||||
|
pool: &PgPool,
|
||||||
|
id: Uuid,
|
||||||
|
workspace_id: WorkspaceId,
|
||||||
|
) -> Result<Option<(Option<String>, Option<String>)>, DbError> {
|
||||||
|
use sqlx::Row;
|
||||||
|
let row: Option<sqlx::postgres::PgRow> = sqlx::query(
|
||||||
|
"SELECT zeroclaw_container, zeroclaw_gateway_url FROM teams
|
||||||
|
WHERE id = $1 AND workspace_id = $2",
|
||||||
|
)
|
||||||
|
.bind(id)
|
||||||
|
.bind(workspace_id.as_uuid())
|
||||||
|
.fetch_optional(pool)
|
||||||
|
.await?;
|
||||||
|
Ok(row.map(|r| {
|
||||||
|
(
|
||||||
|
r.try_get::<Option<String>, _>("zeroclaw_container")
|
||||||
|
.ok()
|
||||||
|
.flatten(),
|
||||||
|
r.try_get::<Option<String>, _>("zeroclaw_gateway_url")
|
||||||
|
.ok()
|
||||||
|
.flatten(),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 0046: set (or clear) the team's per-container coordinates once
|
||||||
|
/// spawn_team lands them.
|
||||||
|
pub async fn set_team_container_coords(
|
||||||
|
pool: &PgPool,
|
||||||
|
id: Uuid,
|
||||||
|
workspace_id: WorkspaceId,
|
||||||
|
container: Option<&str>,
|
||||||
|
gateway_url: Option<&str>,
|
||||||
|
) -> Result<(), DbError> {
|
||||||
|
sqlx::query(
|
||||||
|
"UPDATE teams
|
||||||
|
SET zeroclaw_container = $3,
|
||||||
|
zeroclaw_gateway_url = $4
|
||||||
|
WHERE id = $1 AND workspace_id = $2",
|
||||||
|
)
|
||||||
|
.bind(id)
|
||||||
|
.bind(workspace_id.as_uuid())
|
||||||
|
.bind(container)
|
||||||
|
.bind(gateway_url)
|
||||||
|
.execute(pool)
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,12 @@
|
|||||||
|
-- Per-team container coordinates. Sibling to
|
||||||
|
-- research_topics.zeroclaw_container / zeroclaw_gateway_url (added in
|
||||||
|
-- 0038) — same shape, different owner. When a loop with team_id fires
|
||||||
|
-- its first iteration, the runtime spawns a team-scoped container
|
||||||
|
-- (name `team-<team_id>-container`, port 42617 on clawmates_core) and
|
||||||
|
-- persists both fields here so subsequent iterations reattach idempotently.
|
||||||
|
--
|
||||||
|
-- Both NULLABLE. NULL = team has never spawned a container; runtime
|
||||||
|
-- treats that as the on-first-iteration provision path.
|
||||||
|
ALTER TABLE teams
|
||||||
|
ADD COLUMN IF NOT EXISTS zeroclaw_container TEXT,
|
||||||
|
ADD COLUMN IF NOT EXISTS zeroclaw_gateway_url TEXT;
|
||||||
Reference in New Issue
Block a user