1- # Collect a Claude auth token (`claude setup-token`) for the repo's env-file. Run by the session
2- # service in a host tmux session (no container); ShellRunner sources the repo's env-file first, so an
3- # already-configured credential shows up as an env var, and exports PANOPTICON_ENV_FILE (its path)
4- # and PANOPTICON_GIT_URL (the repo's remote, used to detect a GitHub forge below).
1+ # Guide the operator through a repo's host-side setup: mint a Claude auth token (`claude
2+ # setup-token`) and — for a GitHub repo — record a `GH_TOKEN`, writing each into the repo's env-file.
3+ # Run by the session service in a host tmux session (no container); ShellRunner sources the repo's
4+ # env-file first (so an already-configured credential shows up as an env var) and exports
5+ # PANOPTICON_ENV_FILE (its path), PANOPTICON_GIT_URL (the repo's remote, used to detect a GitHub
6+ # forge below), and PANOPTICON_REPO_NAME (the repo's label, for the summary).
57#
6- # Whatever route the operator takes, the script converges on a summary + a prompt to press Enter,
7- # which completes the task and returns them to the dashboard.
8+ # Whatever route the operator takes, the script converges on a bulleted summary + a prompt to press
9+ # Enter, which completes the task and returns them to the dashboard.
810
911env_file=" ${PANOPTICON_ENV_FILE:- the repo' s env-file}"
12+ repo_name="${PANOPTICON_REPO_NAME:-this repo}"
13+ repo_url="${PANOPTICON_GIT_URL:-}"
14+ repo_label=$(repo_source_label "$repo_url")
1015
1116# How to get back to the dashboard: detach from this tmux session. Detect the prefix + detach key
1217# from the running server (the operator may have rebound them), falling back to the tmux defaults.
1318prefix=$(tmux show-options -gv prefix 2>/dev/null)
1419[ -n "$prefix" ] || prefix="C-b"
1520detach=$(tmux list-keys -T prefix 2>/dev/null | awk ' $NF == " detach-client" { print $(NF - 1); exit } ')
1621[ -n " $detach " ] || detach=" d"
17- dashboard_hint=" To return to the dashboard without finishing, detach: press $prefix then $detach (the task stays running )."
22+ dashboard_hint=" To return to the dashboard without finishing, detach: press $prefix then $detach (you can resume this task any time from the dashboard )."
1823
1924# Show how to get back to the dashboard up front, before anything else.
2025echo " $dashboard_hint "
2126echo
2227
23- summary=" "
28+ # Work out what's already configured and what setting this repo up entails. The Claude credential is
29+ # always needed (the agent runs ` claude` regardless); a GH_TOKEN is only needed for a GitHub remote
30+ # (a local checkout has nothing to push). " Configured" means the env-file already carries it.
31+ claude_configured=0
32+ if [ -n " ${CLAUDE_CODE_OAUTH_TOKEN:- } " ] || [ -n " ${ANTHROPIC_API_KEY:- } " ]; then
33+ claude_configured=1
34+ fi
35+ gh_needed=0
36+ gh_configured=0
37+ if is_github_url " $repo_url " ; then
38+ gh_needed=1
39+ env_file_has_var GH_TOKEN " ${PANOPTICON_ENV_FILE:- } " && gh_configured=1
40+ fi
2441
25- # Append clause $1 to the running $summary , space-separating it from anything already there. Each
26- # step records its own outcome this way, so the order the steps run in doesn't clobber the summary.
42+ # What we know about the repo, and what its setup entails — two bulleted lists up front.
43+ echo " This repo:"
44+ echo " • Name: $repo_name "
45+ echo " • Source: $repo_label "
46+ echo
47+ echo " To set up:"
48+ if [ " $claude_configured " -eq 1 ]; then
49+ echo " • Claude credential — already configured"
50+ else
51+ echo " • Claude credential — needed"
52+ fi
53+ if [ " $gh_needed " -eq 1 ]; then
54+ if [ " $gh_configured " -eq 1 ]; then
55+ echo " • GH_TOKEN — already configured"
56+ else
57+ echo " • GH_TOKEN — needed (GitHub repo)"
58+ fi
59+ else
60+ echo " • GH_TOKEN — not needed (not a GitHub repo)"
61+ fi
62+ echo
63+
64+ # The closing summary is a bullet per step; each step appends its outcome here.
65+ summary=" "
2766add_summary() {
28- if [ -n " $summary " ]; then
29- summary=" $summary $1 "
67+ if [ -z " $summary " ]; then
68+ summary=" • $1 "
3069 else
31- summary=" $1 "
70+ summary=" $summary
71+ • $1 "
3272 fi
3373}
3474
35- # Mint a token and record the outcome in $summary . On success, capture the minted token and write it
36- # straight into the repo's env-file (commenting out any previous one — see store_oauth_token ); fall
75+ # Mint a Claude token and record the outcome. On success, capture the minted token and write it
76+ # straight into the repo's env-file (commenting out any previous one — see store_env_token ); fall
3777# back to on-screen copy instructions when it can't be captured or there's no env-file to write to.
38- # extract_oauth_token / store_oauth_token come from setup_repo_lib.sh (prepended by shell_script()).
78+ # extract_oauth_token / store_env_token come from setup_repo_lib.sh (prepended by shell_script()).
3979collect_token() {
4080 echo
4181 echo " Running ' claude setup-token' — follow the prompts to mint a token."
@@ -60,66 +100,108 @@ collect_token() {
60100 fi
61101
62102 if [ " $_ct_ok " -eq 0 ]; then
63- add_summary " ' claude setup-token' failed or was cancelled — no token was collected."
103+ add_summary " Claude credential: ' claude setup-token' failed or was cancelled — nothing collected."
64104 elif [ -n " $_ct_token " ] && [ -n " ${PANOPTICON_ENV_FILE:- } " ] \
65- && store_oauth_token " $_ct_token " " $PANOPTICON_ENV_FILE " ; then
105+ && store_env_token CLAUDE_CODE_OAUTH_TOKEN " $_ct_token " " $PANOPTICON_ENV_FILE " ; then
66106 echo
67107 echo " Wrote the new token to $env_file as CLAUDE_CODE_OAUTH_TOKEN (any previous one was commented out)."
68- add_summary " Minted a new token and wrote it to $env_file (any previous token was commented out)."
108+ add_summary " Claude credential: minted a new token and wrote it to $env_file (any previous one was commented out)."
69109 else
70110 # Minted, but we couldn't capture/extract it or there's no env-file configured — guide the copy.
71111 echo
72112 echo " Token minted. Copy the token shown above into $env_file as:"
73113 echo " CLAUDE_CODE_OAUTH_TOKEN=< token> "
74- add_summary " Minted a new token — copy it into $env_file as CLAUDE_CODE_OAUTH_TOKEN."
114+ add_summary " Claude credential: minted a new token — copy it into $env_file as CLAUDE_CODE_OAUTH_TOKEN."
115+ fi
116+ }
117+
118+ # Write a GH token into the env-file, or record why we couldn't — shared by both the reuse-from-env
119+ # and ` gh auth login` paths (mirrors the Claude token's store step). $1 ok flag, $2 token, $3 the
120+ # source label for the summary. Goes through store_env_token, so an existing GH_TOKEN is commented
121+ # out and replaced just like the Claude token.
122+ store_gh_token() {
123+ if [ " $1 " -eq 0 ]; then
124+ add_summary " GH_TOKEN: $3 failed or was cancelled — nothing collected."
125+ elif [ -n " $2 " ] && [ -n " ${PANOPTICON_ENV_FILE:- } " ] \
126+ && store_env_token GH_TOKEN " $2 " " $PANOPTICON_ENV_FILE " ; then
127+ echo
128+ echo " Wrote GH_TOKEN to $env_file (any previous one was commented out)."
129+ add_summary " GH_TOKEN: wrote it to $env_file from $3 (any previous one was commented out)."
130+ else
131+ echo
132+ echo " Couldn' t write GH_TOKEN. Add it to $env_file yourself:"
133+ echo " GH_TOKEN=<a GitHub token>"
134+ add_summary "GH_TOKEN: couldn' t write it — add GH_TOKEN to $env_file yourself."
75135 fi
76136}
77137
78- # Offer to record a GitHub token in the repo's env-file, but only when it's both wanted and missing:
79- # the repo is hosted on GitHub (PANOPTICON_GIT_URL), a GH_TOKEN is present in the environment (e.g.
80- # the operator's own shell — the shell runner inherits the host env), and the env-file doesn't
81- # already carry an active GH_TOKEN line. Records the outcome in $summary . is_github_url /
82- # env_file_has_var / append_env_var come from setup_repo_lib.sh (prepended by shell_script()).
83- maybe_offer_github_token() {
84- is_github_url " ${PANOPTICON_GIT_URL:- } " || return 0
85- [ -n " ${GH_TOKEN:- } " ] || return 0
86- [ -n " ${PANOPTICON_ENV_FILE:- } " ] || return 0
87- ! env_file_has_var GH_TOKEN " $PANOPTICON_ENV_FILE " || return 0
138+ # Authenticate to GitHub with ` gh auth login` , then capture the token with ` gh auth token` and store
139+ # it — the fallback when there's no GH_TOKEN in the environment to reuse. Guarded on ` gh` being
140+ # installed; otherwise guides the operator to add one by hand.
141+ collect_gh_token() {
142+ if ! command -v gh >/dev/null 2>&1; then
143+ echo
144+ echo " The ' gh' CLI isn' t installed on this host, so I can' t run ' gh auth login' ."
145+ echo " Add a token to $env_file yourself instead:"
146+ echo " GH_TOKEN=< a GitHub token, e.g. from ' gh auth token' > "
147+ add_summary " GH_TOKEN: ' gh' not installed — add GH_TOKEN to $env_file yourself."
148+ return
149+ fi
88150 echo
89- echo " This repo is hosted on GitHub and a GH_TOKEN is set in your environment, but $env_file "
90- echo " has no GH_TOKEN. Adding it lets task containers use ' gh' and push over HTTPS."
151+ echo " Running ' gh auth login' — follow the prompts to authenticate to GitHub."
91152 echo
92- printf 'Add GH_TOKEN to %s? [y/N] ' " $env_file "
93- read gh_answer
94- case " $gh_answer " in
95- [Yy]*)
96- if append_env_var GH_TOKEN " $GH_TOKEN " " $PANOPTICON_ENV_FILE " ; then
97- echo " Wrote GH_TOKEN to $env_file ."
98- add_summary " Added GH_TOKEN to $env_file ."
99- else
100- echo " Could not write GH_TOKEN to $env_file ."
101- add_summary " Could not add GH_TOKEN to $env_file ."
102- fi
103- ;;
104- *) add_summary " Left GH_TOKEN out of $env_file ." ;;
105- esac
153+ _gt_ok=1
154+ gh auth login || _gt_ok=0
155+ _gt_token=" "
156+ [ " $_gt_ok " -eq 1 ] && _gt_token=$( gh auth token 2> /dev/null)
157+ store_gh_token " $_gt_ok " " $_gt_token " " ' gh auth login' "
106158}
107159
108- if [ -n " ${CLAUDE_CODE_OAUTH_TOKEN:- } " ] || [ -n " ${ANTHROPIC_API_KEY:- } " ]; then
160+ # Get a GH_TOKEN into the env-file for a GitHub repo: reuse one already in the environment if the
161+ # operator has it (the shell runner inherits the host env — the fast path), else authenticate with
162+ # ` gh auth login` .
163+ setup_gh_token() {
164+ if [ -n " ${GH_TOKEN:- } " ]; then
165+ echo " A GH_TOKEN is set in your environment. Adding it to $env_file lets task containers use"
166+ echo " ' gh' and push over HTTPS."
167+ echo
168+ printf 'Add the GH_TOKEN from your environment to %s? [Y/n] ' " $env_file "
169+ read gh_answer
170+ case " $gh_answer " in
171+ [Nn]*) add_summary " GH_TOKEN: skipped — add GH_TOKEN to $env_file yourself." ;;
172+ *) store_gh_token 1 " $GH_TOKEN " " your environment" ;;
173+ esac
174+ else
175+ echo " No GH_TOKEN in your environment — a GitHub repo needs one to push and open PRs."
176+ echo
177+ echo " Prefer to use your own? Press $prefix then $detach to go to the dashboard, drop this task using ' x' and add"
178+ echo " GH_TOKEN=< a GitHub token> "
179+ echo " to $env_file yourself."
180+ echo
181+ printf 'Authenticate to GitHub with gh now? [Y/n] '
182+ read gh_answer
183+ case " $gh_answer " in
184+ [Nn]*) add_summary " GH_TOKEN: skipped — add GH_TOKEN to $env_file yourself." ;;
185+ *) collect_gh_token ;;
186+ esac
187+ fi
188+ }
189+
190+ # --- Claude credential -------------------------------------------------------------------------
191+ if [ " $claude_configured " -eq 1 ]; then
109192 echo " A Claude credential is already configured in $env_file ."
110- echo " To keep using it, drop this task instead (press ' x' in the dashboard)."
111193 echo
112194 printf 'Collect a new token anyway? [y/N] '
113195 read answer
114196 case " $answer " in
115197 [Yy]*) collect_token ;;
116- *) add_summary " Kept the existing credential in $env_file — nothing collected." ;;
198+ *) add_summary " Claude credential: kept the existing one in $env_file — nothing collected." ;;
117199 esac
118200else
119201 echo " No Claude credential found in $env_file ."
120202 echo " About to collect one with ' claude setup-token' ."
121203 echo
122- echo " Prefer to use your own? Drop this task (press ' x ' in the dashboard) and add one of"
204+ echo " Prefer to use your own? Press $prefix then $detach to go to the dashboard, drop this task using ' x ' and add one of"
123205 echo " these to $env_file yourself:"
124206 echo " CLAUDE_CODE_OAUTH_TOKEN=< token from ' claude setup-token' > "
125207 echo " ANTHROPIC_API_KEY=< your Anthropic API key> "
@@ -129,14 +211,33 @@ else
129211 collect_token
130212fi
131213
132- # With the Claude credential settled, offer to record a GitHub token too (no-op unless it applies).
133- maybe_offer_github_token
214+ # --- GH_TOKEN (GitHub repos only) --------------------------------------------------------------
215+ if [ " $gh_needed " -eq 1 ]; then
216+ echo
217+ if [ " $gh_configured " -eq 1 ]; then
218+ echo " A GH_TOKEN is already configured in $env_file ."
219+ echo
220+ printf 'Replace it? [y/N] '
221+ read answer
222+ case " $answer " in
223+ [Yy]*) setup_gh_token ;;
224+ *) add_summary " GH_TOKEN: kept the existing one in $env_file — nothing collected." ;;
225+ esac
226+ else
227+ setup_gh_token
228+ fi
229+ fi
134230
135- # Every route converges here: summarize what happened, then complete the task on Enter (which ends
136- # the session and returns the operator to the dashboard; detaching instead — see the hint above —
137- # leaves it running).
231+ # Every route converges here: summarize what happened (a bullet per step) , then complete the task on
232+ # Enter (which ends the session and returns the operator to the dashboard; detaching instead — see
233+ # the hint above — leaves it running).
138234echo
139- echo " Summary: $summary "
235+ echo " Summary:"
236+ if [ -n " $summary " ]; then
237+ echo " $summary "
238+ else
239+ echo " • Nothing to do — everything was already configured."
240+ fi
140241echo
141242printf 'Press Enter to complete this task and return to the dashboard. '
142243read _
0 commit comments