diff --git a/.claude/skills/atlas/SKILL.md b/.claude/skills/atlas/SKILL.md index 218516228..8a68ae21c 100644 --- a/.claude/skills/atlas/SKILL.md +++ b/.claude/skills/atlas/SKILL.md @@ -99,6 +99,28 @@ Reads `habitable_planet_count`, `inhabited_planet_count`, `gas_giant`, Creates: planets (inhabited first), gas giants, asteroid belts, oort cloud per system, horizon station per oort cloud. Skips systems that already have bodies. +### Update a system-level field +```bash +tooling/atlas-update-field "GJ 687" settlement_wave wave_3 +tooling/atlas-update-field "GJ 53A" star_type G +``` +Updates a whitelisted field in systems.db. Auto-detects the correct table +(`star_systems`, `system_gates`, or `system_history`). Inserts a row in +child tables if one doesn't exist yet. + +Whitelisted fields: `star_type`, `spectral_class`, `proper_name`, +`geographic_sector`, `habitable_planet_count`, `inhabited_planet_count`, +`gate_topology`, `aperture_count`, `hop_distance_from_gateway`, +`settlement_wave`, `founding_culture_primary`, `founding_culture_secondary`. + +### Commit and sync a single system +```bash +tooling/atlas-commit-and-sync "GJ 105A" east_reach +``` +Full pipeline: verify proposal → wipe existing data (if any) → commit to DB +→ sync wiki → git add + git commit. Second argument is the corridor tag for +the commit message (defaults to `east_reach`). + ## Body ID Naming Convention ``` diff --git a/tooling/atlas-commit-and-sync b/tooling/atlas-commit-and-sync new file mode 100755 index 000000000..fff2d1c77 --- /dev/null +++ b/tooling/atlas-commit-and-sync @@ -0,0 +1,60 @@ +#!/usr/bin/env bash +# Commit a single system proposal to DB, sync wiki, and create a git commit. +# Handles wipe-if-exists automatically. +# +# Usage: atlas-commit-and-sync "GJ 105A" [corridor_tag] +# corridor_tag defaults to "east_reach" +set -euo pipefail +SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" +ATLAS="$SCRIPT_DIR/atlas" + +if [[ $# -lt 1 ]]; then + echo "Usage: atlas-commit-and-sync SYSTEM_ID [corridor_tag]" >&2 + exit 1 +fi + +SYS_ID="$1" +CORRIDOR="${2:-east_reach}" +SLUG="${SYS_ID// /}" +FILE="docs/atlas/proposals/${SLUG}.json" +WIKI_SLUG="${SYS_ID// /-}" +WIKI="wiki/star-systems/${WIKI_SLUG}/index.md" + +if [[ ! -f "$FILE" ]]; then + echo "ERROR: proposal not found: $FILE" >&2 + exit 1 +fi + +# 1. Verify +echo "--- Verifying $FILE" +"$SCRIPT_DIR/atlas-verify" "$FILE" + +# 2. Get system info for commit message +PROPER=$(python3 -c "import json; d=json.load(open('$FILE')); print(d.get('proper_name') or d['system_id'])") + +# 3. Wipe existing data if present +BODY_COUNT=$("$ATLAS" show-system "$SYS_ID" 2>/dev/null \ + | python3 -c "import json,sys; d=json.load(sys.stdin); print(len(d.get('bodies',[])))" 2>/dev/null \ + || echo "0") +if [[ "$BODY_COUNT" -gt 0 ]]; then + echo "--- Wiping existing data for $SYS_ID" + "$ATLAS" wipe-system "$SYS_ID" +fi + +# 4. Commit to DB +echo "--- Committing $SYS_ID to systems.db" +"$ATLAS" commit-system "$FILE" + +# 5. Sync wiki +echo "--- Syncing wiki" +"$ATLAS" sync-wiki "$SYS_ID" + +# 6. Git add + commit +echo "--- Git commit" +git add "$FILE" +[[ -f "$WIKI" ]] && git add "$WIKI" +git commit -m "data(atlas): author ${SYS_ID} (${PROPER}) — ${CORRIDOR} + +Co-Authored-By: Claude Opus 4.6 (1M context) " + +echo "--- Done: $SYS_ID ($PROPER)" diff --git a/tooling/atlas-update-field b/tooling/atlas-update-field new file mode 100755 index 000000000..1aeca5c80 --- /dev/null +++ b/tooling/atlas-update-field @@ -0,0 +1,59 @@ +#!/usr/bin/env bash +# Update a field on a star system record in systems.db. +# Automatically detects which table the field belongs to. +# +# Usage: atlas-update-field "GJ 687" settlement_wave wave_3 +# atlas-update-field "GJ 53A" star_type G +set -euo pipefail +DB="$(cd "$(dirname "$0")/../server/data" && pwd)/systems.db" + +if [[ $# -ne 3 ]]; then + echo "Usage: atlas-update-field SYSTEM_ID FIELD VALUE" >&2 + exit 1 +fi + +SYS="$1" FIELD="$2" VALUE="$3" + +python3 -c " +import sqlite3, sys + +FIELD_TABLE = { + # star_systems + 'star_type': 'star_systems', + 'spectral_class': 'star_systems', + 'proper_name': 'star_systems', + 'geographic_sector': 'star_systems', + 'habitable_planet_count': 'star_systems', + 'inhabited_planet_count': 'star_systems', + # system_gates + 'gate_topology': 'system_gates', + 'aperture_count': 'system_gates', + 'hop_distance_from_gateway': 'system_gates', + # system_history + 'settlement_wave': 'system_history', + 'founding_culture_primary': 'system_history', + 'founding_culture_secondary': 'system_history', +} + +field = sys.argv[1] +value = sys.argv[2] +system_id = sys.argv[3] + +if field not in FIELD_TABLE: + print(f'ERROR: field \"{field}\" not in whitelist', file=sys.stderr) + print(f'Allowed: {sorted(FIELD_TABLE.keys())}', file=sys.stderr) + sys.exit(1) + +table = FIELD_TABLE[field] +conn = sqlite3.connect(sys.argv[4]) +cur = conn.cursor() + +# Ensure row exists in target table (history/gates may not have a row yet) +if table != 'star_systems': + cur.execute(f'INSERT OR IGNORE INTO {table} (system_id) VALUES (?)', (system_id,)) + +cur.execute(f'UPDATE {table} SET {field} = ? WHERE system_id = ?', (value, system_id)) +print(f'updated {cur.rowcount} row(s): {system_id}.{field} = {value} ({table})') +conn.commit() +conn.close() +" "$FIELD" "$VALUE" "$SYS" "$DB"