Monorepo for Tangled tangled.org
2

Configure Feed

Select the types of activity you want to include in your feed.

1#!/bin/sh 2# dev bootstrap: 3# - create accounts (alice, bob) 4# - write OWNER_DID to /shared/owner-did (for knot/spindle) 5# - create system label definitions under SYSTEM_DID 6set -eu 7 8: "${PDS_URL:?PDS_URL must be set}" 9PASSWORD="password" 10 11USERS="alice bob" 12OWNER_USER="${OWNER_USER:-alice}" 13SYSTEM_USER="${SYSTEM_USER:-alice}" 14SHARED_DIR="${SHARED_DIR:-/shared}" 15 16# --- helpers --- 17 18# resolve_handle HANDLE → DID on stdout 19resolve_handle() { 20 resp=$(curl -sS -w '\n%{http_code}' \ 21 "${PDS_URL}/xrpc/com.atproto.identity.resolveHandle?handle=$1") 22 body=$(printf '%s\n' "$resp" | sed '$d') 23 status=$(printf '%s\n' "$resp" | tail -n1) 24 case "$status" in 25 200) printf '%s\n' "$body" | jq -er '.did' ;; 26 400) : ;; # not found — expected 27 *) printf 'resolveHandle %s: HTTP %s: %s\n' "$1" "$status" "$body" >&2; return 1 ;; 28 esac 29} 30 31# ensure_account USERNAME → DID on stdout. Creates account if missing. 32ensure_account() { 33 username="$1" 34 handle="${username}.${PDS_HOSTNAME}" 35 email="${username}@${PDS_HOSTNAME}" 36 37 did=$(resolve_handle "$handle") 38 if [ -n "$did" ]; then 39 printf '[skip] %s = %s\n' "$handle" "$did" >&2 40 printf '%s\n' "$did" 41 return 0 42 fi 43 44 invite=$(curl -fsS -u "admin:${PDS_ADMIN_PASSWORD}" \ 45 -H "Content-Type: application/json" \ 46 -d '{"useCount":1}' \ 47 "${PDS_URL}/xrpc/com.atproto.server.createInviteCode" | jq -er '.code') 48 49 result=$(curl -fsS \ 50 -H "Content-Type: application/json" \ 51 -d "{\"email\":\"${email}\",\"handle\":\"${handle}\",\"password\":\"${PASSWORD}\",\"inviteCode\":\"${invite}\"}" \ 52 "${PDS_URL}/xrpc/com.atproto.server.createAccount") 53 54 did=$(printf '%s\n' "$result" | jq -er '.did') 55 printf '[create] %s = %s (password: %s)\n' "$handle" "$did" "$PASSWORD" >&2 56 printf '%s\n' "$did" 57} 58 59# login DID/Handle → access JWT on stdout 60login() { 61 curl -fsS -H "Content-Type: application/json" \ 62 -d "{\"identifier\":\"$1\",\"password\":\"${PASSWORD}\"}" \ 63 "${PDS_URL}/xrpc/com.atproto.server.createSession" \ 64 | jq -er '.accessJwt' 65} 66 67# put_record JWT DID COLLECTION RKEY RECORD_JSON 68put_record() { 69 jwt="$1"; did="$2"; collection="$3"; rkey="$4"; record="$5" 70 71 payload=$(jq -nc \ 72 --arg repo "$did" \ 73 --arg collection "$collection" \ 74 --arg rkey "$rkey" \ 75 --argjson record "$record" \ 76 '{repo:$repo, collection:$collection, rkey:$rkey, record:$record}') 77 78 curl -fsS \ 79 -H "Content-Type: application/json" \ 80 -H "Authorization: Bearer ${jwt}" \ 81 -d "$payload" \ 82 "${PDS_URL}/xrpc/com.atproto.repo.putRecord" >/dev/null 83 84 printf '[record] at://%s/%s/%s\n' "$did" "$collection" "$rkey" >&2 85} 86 87# ensure accounts 88OWNER_DID="" 89SYSTEM_DID="" 90for u in $USERS; do 91 did=$(ensure_account "$u") 92 if [ "$u" = "$OWNER_USER" ]; then 93 OWNER_DID="$did" 94 fi 95 if [ "$u" = "$SYSTEM_USER" ]; then 96 SYSTEM_DID="$did" 97 fi 98done 99 100[ -n "$OWNER_DID" ] || { printf 'OWNER_USER %s not in USERS list\n' "$OWNER_USER" >&2; exit 1; } 101[ -n "$SYSTEM_DID" ] || { printf 'SYSTEM_USER %s not in USERS list\n' "$SYSTEM_USER" >&2; exit 1; } 102 103mkdir -p "$SHARED_DIR" 104printf '%s' "$OWNER_DID" > "${SHARED_DIR}/owner-did" 105printf '[owner] %s → %s/owner-did\n' "$OWNER_USER" "$SHARED_DIR" >&2 106printf '%s' "$SYSTEM_DID" > "${SHARED_DIR}/system-did" 107printf '[system] %s → %s/system-did\n' "$SYSTEM_USER" "$SHARED_DIR" >&2 108 109# label definitions (under SYSTEM_DID) 110JWT=$(login "$SYSTEM_DID") 111 112CREATED_AT="2025-09-22T11:14:35+01:00" 113 114put_record "$JWT" "$SYSTEM_DID" "sh.tangled.label.definition" "wontfix" "$(cat <<JSON 115{ 116 "name": "wontfix", 117 "color": "#64748b", 118 "scope": ["sh.tangled.repo.issue"], 119 "multiple": false, 120 "createdAt": "${CREATED_AT}", 121 "valueType": {"type": "null", "format": "any"} 122} 123JSON 124)" 125 126put_record "$JWT" "$SYSTEM_DID" "sh.tangled.label.definition" "good-first-issue" "$(cat <<JSON 127{ 128 "name": "good-first-issue", 129 "color": "#8B5CF6", 130 "scope": ["sh.tangled.repo.issue"], 131 "multiple": false, 132 "createdAt": "${CREATED_AT}", 133 "valueType": {"type": "null", "format": "any"} 134} 135JSON 136)" 137 138put_record "$JWT" "$SYSTEM_DID" "sh.tangled.label.definition" "duplicate" "$(cat <<JSON 139{ 140 "name": "duplicate", 141 "color": "#ef4444", 142 "scope": ["sh.tangled.repo.issue"], 143 "multiple": false, 144 "createdAt": "${CREATED_AT}", 145 "valueType": {"type": "null", "format": "any"} 146} 147JSON 148)" 149 150put_record "$JWT" "$SYSTEM_DID" "sh.tangled.label.definition" "documentation" "$(cat <<JSON 151{ 152 "name": "documentation", 153 "color": "#06b6d4", 154 "scope": ["sh.tangled.repo.issue"], 155 "multiple": false, 156 "createdAt": "${CREATED_AT}", 157 "valueType": {"type": "null", "format": "any"} 158} 159JSON 160)" 161 162put_record "$JWT" "$SYSTEM_DID" "sh.tangled.label.definition" "assignee" "$(cat <<JSON 163{ 164 "name": "assignee", 165 "color": "#10B981", 166 "scope": ["sh.tangled.repo.issue", "sh.tangled.repo.pull"], 167 "multiple": false, 168 "createdAt": "${CREATED_AT}", 169 "valueType": {"type": "string", "format": "did"} 170} 171JSON 172)" 173 174# shared env values for appview 175LABEL_GFI=at://${SYSTEM_DID}/sh.tangled.label.definition/good-first-issue 176LABEL_DEFAULTS=$LABEL_GFI 177LABEL_DEFAULTS=$LABEL_DEFAULTS,at://${SYSTEM_DID}/sh.tangled.label.definition/assignee 178LABEL_DEFAULTS=$LABEL_DEFAULTS,at://${SYSTEM_DID}/sh.tangled.label.definition/documentation 179LABEL_DEFAULTS=$LABEL_DEFAULTS,at://${SYSTEM_DID}/sh.tangled.label.definition/duplicate 180LABEL_DEFAULTS=$LABEL_DEFAULTS,at://${SYSTEM_DID}/sh.tangled.label.definition/wontfix 181 182printf '%s' "$LABEL_GFI" > "${SHARED_DIR}/label-gfi" 183printf '%s' "$LABEL_DEFAULTS" > "${SHARED_DIR}/label-defaults" 184printf '[env] wrote label-defaults, label-gfi\n' >&2 185 186# service definitions (under OWNER_DID) 187JWT=$(login "$OWNER_DID") 188 189put_record "$JWT" "$OWNER_DID" "sh.tangled.knot" $KNOT_HOSTNAME "{\"createdAt\": \"${CREATED_AT}\"}" 190 191printf 'done.\n' >&2