app
Grok Bot
Public Made by Adomby adom
Grok Bridge lets Adom talk to Grok Bot. Adom's AI environment is for electrical engineers: any provider, any desktop power tool, one place.
main
John Lauer
v1.3.3 (insiders): Grok Bot's computer state: computerReachable on readiness, chat and webhook verbs, fast no_transcrip…
85caf75
5d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
#!/usr/bin/env bash
# ship.sh — the publish pipeline for grok-bridge. Every ship goes to the INSIDERS tier.
#
# tools/ship.sh <version> "<changelog sentence>" # -> INSIDERS (the default)
# tools/promote.sh <version> "<the human's words>" --by "<name>" # -> PUBLIC, attested
#
# Release tiers (wiki issue #2, ab 2.0.99 insidersManifestUrl; same pattern as adom/pup-bridge):
# - The zip becomes a release on adom/grok-bridge. The INSIDERS manifest is written to the
# shared private page adom/insiders as grok-bridge/version.json (bridge-manifest shape) with a
# release-log entry in grok-bridge/README.md. Source text files are pushed to the public page,
# and the skills pkg is published at the same version so the page's top version row always
# carries a tarball (release rows and pkg rows share one namespace, adom/wiki#170).
# - The PUBLIC manifest (adom-bridge-grok-manifest.json, updateManifestUrl) is NEVER touched
# here. It moves only through tools/promote.sh, on a human's exact words.
# - Desktops on ab >= 2.0.99 whose login can read adom/insiders follow the insiders manifest;
# everyone else follows the public manifest.
#
# Env: FORCE_PUSH=1 keeps going when a push reports nothing changed.
set -euo pipefail
VER="${1:?usage: tools/ship.sh <version> \"<changelog>\"}"
LOG="${2:?changelog sentence required (>= 10 chars, >= 2 words)}"
REPO="$(cd "$(dirname "$0")/.." && pwd)"
PAGE="adom/grok-bridge"
INSIDERS_PAGE="adom/insiders"
INSIDERS_DIR="dist/insiders-repo"
INSIDERS_REL="grok-bridge/version.json"
ZIP="adom-bridge-grok-v${VER}.zip"
ARCH="dist/${VER}"
RUNTIME=(BRIDGE_VERSION bridge.json caller_identity.py grok_detect.py server.py handlers/*.py)
cd "$REPO"
echo "== 0. static gates =="
python3 -m py_compile server.py grok_detect.py caller_identity.py handlers/*.py dashboard/grok_dashboard.py
python3 - <<'PY'
import glob, re, sys, yaml
bad = []
for p in ['SKILL.md'] + sorted(glob.glob('skills/*/SKILL.md') + glob.glob('dev-skills/*/SKILL.md')):
m = re.match(r'^---\n(.*?)\n---\n', open(p).read(), re.S)
try:
d = yaml.safe_load(m.group(1)) if m else None
if not isinstance(d, dict) or not isinstance(d.get('name'), str) or not isinstance(d.get('description'), str):
bad.append(p)
except Exception:
bad.append(p)
print(' python compiles; SKILL.md frontmatter invalid:', bad or 'none')
sys.exit(1 if bad else 0)
PY
echo "== 1. version lockstep =="
printf '%s' "$VER" > BRIDGE_VERSION
python3 - "$VER" "$LOG" <<'PY'
import json, sys
v, log = sys.argv[1:3]
d = json.load(open('bridge.json'))
d['version'] = v
assert d.get('insidersManifestUrl', '').endswith('/pages/insiders/files/grok-bridge/version.json'), \
'bridge.json insidersManifestUrl must point at adom/insiders grok-bridge/version.json'
json.dump(d, open('bridge.json', 'w'), indent=2); open('bridge.json', 'a').write('\n')
p = json.load(open('package.json'))
p['version'] = v; p['changelog'] = log
json.dump(p, open('package.json', 'w'), indent=2); open('package.json', 'a').write('\n')
print(f" BRIDGE_VERSION + bridge.json + package.json -> {v}")
PY
echo "== 2. runtime zip (files at zip root) =="
mkdir -p "$ARCH"
rm -f "$ARCH/$ZIP"
python3 - "$ARCH/$ZIP" "${RUNTIME[@]}" <<'PY'
import hashlib, os, sys, zipfile
out, files = sys.argv[1], sys.argv[2:]
with zipfile.ZipFile(out, 'w', zipfile.ZIP_DEFLATED) as z:
for f in files:
z.write(f, f)
print(f" {out} files={len(files)} sha256={hashlib.sha256(open(out,'rb').read()).hexdigest()} size={os.path.getsize(out)}")
PY
echo "== 3a. skills pkg first (same version, so the top version row has a tarball) =="
PUBOUT=$(adom-wiki pkg publish --org adom 2>&1) || { echo "PKG PUBLISH FAILED"; echo "$PUBOUT" | tail -15; exit 1; }
echo "$PUBOUT" | tail -2
echo "== 3b. release on $PAGE =="
adom-wiki release create "$PAGE" "$VER" --changelog "$LOG" >/dev/null 2>&1 || true # exists already = fine
adom-wiki release upload "$PAGE" "$VER" "$ARCH/$ZIP" >/dev/null
URL="https://wiki.adom.inc/download/adom/grok-bridge/${VER}/${ZIP}"
LSHA=$(sha256sum "$ARCH/$ZIP" | cut -d' ' -f1)
RSHA=$(curl -sL "$URL" | sha256sum | cut -d' ' -f1)
[ "$LSHA" = "$RSHA" ] || { echo "SERVED ASSET MISMATCH: $URL sha $RSHA, local $LSHA"; exit 1; }
echo " $URL serves the exact bytes (sha256 $LSHA)"
echo "== 4. insiders manifest + release log -> $INSIDERS_PAGE:grok-bridge/ =="
mkdir -p "$INSIDERS_DIR/grok-bridge"
adom-wiki repo show "$INSIDERS_PAGE" grok-bridge/README.md > "$INSIDERS_DIR/grok-bridge/README.md" 2>/dev/null \
|| rm -f "$INSIDERS_DIR/grok-bridge/README.md"
python3 - "$VER" "$URL" "$ARCH/$ZIP" "$INSIDERS_DIR" "$ARCH" "$LOG" <<'PY'
import datetime, hashlib, json, os, re, sys
ver, url, zp, ins_dir, arch, log = sys.argv[1:7]
base = json.load(open('adom-bridge-grok-manifest.json'))
for k in ('promotion_attestation', 'promoted_by', 'promoted_at', 'rollback_attestation',
'rolled_back_by', 'rolled_back_at', 'insiders_released_at'):
base.pop(k, None)
bj = json.load(open('bridge.json'))
now = datetime.datetime.now(datetime.timezone.utc).isoformat(timespec='seconds').replace('+00:00', 'Z')
base.update({'version': ver, 'url': url, 'sha256': hashlib.sha256(open(zp, 'rb').read()).hexdigest(),
'size': os.path.getsize(zp), 'verbPrefixes': bj.get('verbPrefixes'),
'statusVerb': bj.get('statusVerb'), 'tier': 'insiders', 'released_at': now})
for p in (os.path.join(ins_dir, 'grok-bridge/version.json'), os.path.join(arch, 'insiders-manifest.json')):
json.dump(base, open(p, 'w'), indent=2); open(p, 'a').write('\n')
rp = os.path.join(ins_dir, 'grok-bridge/README.md')
s = open(rp).read() if os.path.exists(rp) and os.path.getsize(rp) else \
"# grok-bridge on the insiders tier\n\nRuntime builds of adom/grok-bridge that insiders get first. " \
"The public manifest moves only through tools/promote.sh, on a human's words.\n\n## Release log\n\n"
if f"- **{ver}**" not in s:
entry = f"- **{ver}** insiders, {datetime.date.today().isoformat()}. {log} Not promoted.\n"
s = s.replace("## Release log\n\n", "## Release log\n\n" + entry, 1)
open(rp, 'w').write(s)
print(f" insiders manifest {ver} staged; release log entry written; archived {arch}/insiders-manifest.json")
PY
( cd "$INSIDERS_DIR" && adom-wiki repo push "$INSIDERS_PAGE" --files "$INSIDERS_REL" grok-bridge/README.md \
-m "grok-bridge ${VER} (insiders): ${LOG}" >/dev/null ) || [ "${FORCE_PUSH:-0}" = "1" ] || { echo "INSIDERS PUSH FAILED"; exit 1; }
echo "== 5. source + skills to $PAGE (public manifest untouched) =="
adom-wiki repo push "$PAGE" --files "${RUNTIME[@]}" package.json SKILL.md CLAUDE.md README.md \
skills/*/SKILL.md dev-skills/*/SKILL.md tools/ship.sh tools/promote.sh \
dashboard/grok_dashboard.py dashboard/ui/index.html dashboard/ui/newbie-panel.js \
-m "v${VER} (insiders): ${LOG}" >/dev/null || [ "${FORCE_PUSH:-0}" = "1" ] || { echo "PAGE PUSH FAILED"; exit 1; }
echo "== 6. verify =="
LIVE_INS=$(adom-wiki repo show "$INSIDERS_PAGE" "$INSIDERS_REL" 2>/dev/null | python3 -c "import json,sys;print(json.load(sys.stdin).get('version'))" 2>/dev/null || echo '?')
ANON_INS=$(curl -s -o /dev/null -w '%{http_code}' "https://wiki.adom.inc/api/v1/pages/insiders/files/grok-bridge/version.json")
PUB=$(curl -s "https://wiki.adom.inc/api/v1/pages/grok-bridge/files/adom-bridge-grok-manifest.json" | python3 -c "import json,sys;print(json.load(sys.stdin).get('version'))")
echo " insiders manifest (with login): $LIVE_INS anonymous: HTTP $ANON_INS (want 404) public manifest: $PUB"
echo "SHIPPED $VER to INSIDERS. Public stays at $PUB until: tools/promote.sh $VER \"<the human's exact words>\" --by \"<name>\""