← Commit history

1.3.6: claude-rc seeds Claude's first-run flags itself and gains 'ensure' (remote control on by default on ah)

John Lauer ·ae71de0626 ·27d ago ·parent d6a59e0
4 files changed +89−4
SKILL.md+9
@@ -16,6 +16,15 @@ The registry-native, cross-agent auto-update hook. It keeps your `adom/core` app and skills current from the wiki registry (wiki.adom.inc) without git or any private repository. ++## On Adom Hydrogen, it is on by default++`claude-rc ensure` is what hydrogen-bootstrap runs on every converge: on an ah container it+turns remote control on without asking, so a fresh install reaches the Claude mobile app on+its own. It respects an explicit `claude-rc decline` or `disable`, and it stays quiet until+Claude Code is signed in (a brand-new box), retrying on the next sweep. Hydrogen Cloud keeps+the offer-based flow through the prompt hook.+ ## What it does  On every Claude Code and Codex prompt (`UserPromptSubmit`), a throttled check runs
claude-rc+77−1
@@ -8,6 +8,8 @@ #                       and on hc (no cron) doubles as the watchdog. #   claude-rc check     the watchdog: launch if absent, with cooldown after failures. #   claude-rc enable    record consent, register cron on ah, launch now.+#   claude-rc ensure    what hydrogen-bootstrap calls on every converge: on ah, turn it on+#                       by default (respects decline/disable, quiet when not ready yet). #   claude-rc decline   record "no thanks"; the hook never offers again. #   claude-rc disable   stop the server, drop cron, stop watching (re-enable any time). #   claude-rc status    where things stand (state, pid, name, env, last log lines).@@ -78,9 +80,55 @@ stop_server() { # Prerequisites `claude rc` needs: the CLI, a logged-in account, and the workspace # trust dialog accepted for PROJECT_DIR. A UserPromptSubmit hook fires from inside a # session so these normally already hold; the check matters for Codex callers.+# Claude Code's own first-run state lives in ~/.claude.json: hasCompletedOnboarding, a+# theme, and per-folder hasTrustDialogAccepted. Claude REWRITES that file when it signs in,+# dropping whatever seeded it, and then `claude rc` sits on the trust prompt forever. So we+# do not merely CHECK those keys, we write the missing ones ourselves (never overwriting a+# value the user already set). arav-rog 2026-09-23: a fresh install lost the flags at+# sign-in, prereqs read "missing", and remote control never came up for a whole day.+seed_claude_flags() {+  command -v python3 >/dev/null 2>&1 || return 0+  python3 - "$HOME/.claude.json" "$PROJECT_DIR" <<'PY' 2>/dev/null || true+import json, os, sys+path, proj = sys.argv[1], sys.argv[2]+try:+    d = json.load(open(path))+except Exception:+    d = {}+changed = False+for k, v in (("hasCompletedOnboarding", True), ("theme", "dark")):+    if k not in d:+        d[k] = v; changed = True+pr = d.setdefault("projects", {}).setdefault(proj, {})+if not pr.get("hasTrustDialogAccepted"):+    pr["hasTrustDialogAccepted"] = True; changed = True+if changed:+    tmp = path + ".claude-rc.tmp"+    json.dump(d, open(tmp, "w"), indent=2)+    os.replace(tmp, path)+PY+}++# Is an account signed in? `claude rc` needs one; without it the server starts and dies.+signed_in() {+  [ -s "$HOME/.claude/.credentials.json" ] && return 0+  [ -n "${ANTHROPIC_API_KEY:-}" ] && return 0+  command -v python3 >/dev/null 2>&1 || return 1+  python3 - "$HOME/.claude/settings.json" <<'PY' 2>/dev/null+import json, sys+try:+    d = json.load(open(sys.argv[1]))+except Exception:+    sys.exit(1)+sys.exit(0 if (d.get("env") or {}).get("ANTHROPIC_API_KEY") else 1)+PY+}+ prereqs_ok() {   command -v claude >/dev/null 2>&1 || return 1   [ -d "$PROJECT_DIR" ] || return 1+  signed_in || return 1+  seed_claude_flags   command -v python3 >/dev/null 2>&1 || return 0   python3 - "$HOME/.claude.json" "$PROJECT_DIR" <<'PY' 2>/dev/null import json, sys@@ -236,6 +284,33 @@ cmd_enable() {     fi   fi }+# ---- ensure: remote control is ON by default on an Adom Hydrogen container ----------+# John 2026-09-23, after two boxes ran all day without it: have the bootstrap enable this on+# an ah container by default, so a fresh install has remote control from day one without+# anyone answering a prompt. Called by every bootstrap converge: quiet, cheap, idempotent.+# It NEVER overrides a human answer (declined/disabled stay), and hc keeps the offer flow.+cmd_ensure() {+  local verbose="${1:-}"+  is_ah || { [ "$verbose" = "--verbose" ] && echo "claude-rc: not an ah container; the prompt hook still offers it."; return 0; }+  case "$(state)" in+    declined|disabled) [ "$verbose" = "--verbose" ] && echo "claude-rc: $(state) by the user; leaving it alone."; return 0 ;;+    enabled)+      if [ -n "$(running_pid)" ]; then+        [ "$verbose" = "--verbose" ] && echo "claude-rc: already running (pid $(running_pid))."+      else+        check+      fi+      return 0 ;;+  esac+  if ! prereqs_ok; then+    # Not signed in yet is the normal case on a brand-new box: stay `unasked` and try again on+    # the next converge, so remote control starts as soon as the user signs Claude Code in.+    [ "$verbose" = "--verbose" ] && echo "claude-rc: prerequisites not met yet (sign in to Claude Code); will try again next sweep."+    return 0+  fi+  cmd_enable+}+ cmd_decline() { st_set state declined; st_set declined_at "$(now)"; cron_remove; echo "claude-rc: declined. The hook will not offer again; 'claude-rc enable' turns it on later."; } cmd_disable() {   st_set state disabled; cron_remove@@ -284,12 +359,13 @@ main() {   hook)    cmd_hook ;;   check)   check ;;   enable)  cmd_enable ;;+  ensure)  cmd_ensure "${2:-}" ;;   decline) cmd_decline ;;   disable) cmd_disable ;;   status)  cmd_status ;;   logs)    cmd_logs "${2:-40}" ;;   -h|--help|help) sed -n 2,24p "$0" ;;-  *) echo "claude-rc: unknown verb '$1' (hook|check|enable|decline|disable|status|logs)" >&2; exit 2 ;;+  *) echo "claude-rc: unknown verb '$1' (hook|check|ensure|enable|decline|disable|status|logs)" >&2; exit 2 ;; esac } 
package.json+1−1
@@ -1,6 +1,6 @@ {   "slug": "hook",-  "version": "1.3.5",+  "version": "1.3.6",   "type": "app",   "org": "adom",   "bundled": true,
page.json+2−2
@@ -1,6 +1,6 @@ {   "slug": "hook",-  "version": "1.3.5",+  "version": "1.3.6",   "type": "app",   "org": "adom",   "bundled": true,@@ -79,4 +79,4 @@     }   ],   "tag": "latest"-}\ No newline at end of file+}