claude-dev-env 2.10.0 → 2.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CLAUDE.md +1 -1
- package/_shared/advisor/CLAUDE.md +3 -2
- package/_shared/advisor/advisor-protocol.md +74 -108
- package/_shared/advisor/reference/advisor-block.md +37 -0
- package/_shared/advisor/reference/cli-chain.md +45 -0
- package/_shared/advisor/reference/consult-format.md +41 -0
- package/_shared/advisor/reference/lifecycle.md +21 -0
- package/_shared/advisor/reference/sol-rung.md +34 -0
- package/_shared/advisor/reference/spawn-walk-log.md +31 -0
- package/_shared/advisor/reference/third-party-bind.md +30 -0
- package/_shared/advisor/reference/warm-up.md +34 -0
- package/_shared/advisor/scripts/codex_sol_advisor.py +514 -0
- package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +21 -0
- package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +19 -17
- package/_shared/advisor/scripts/config/advisor_scripts_constants/sol_advisor_constants.py +33 -0
- package/_shared/advisor/scripts/model_tier_run_validator.py +32 -9
- package/_shared/advisor/scripts/tests/test_codex_sol_advisor.py +636 -0
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +79 -0
- package/_shared/advisor/scripts/tests/test_tier_model_ids.py +39 -17
- package/_shared/advisor/scripts/tier_model_ids.py +24 -0
- package/commands/CLAUDE.md +1 -0
- package/commands/sr-loop.md +48 -0
- package/docs/references/CLAUDE.md +2 -1
- package/docs/references/advisor-tool.md +26 -8
- package/docs/references/team-advisor-skill.md +3 -3
- package/docs/references/weak-executor-advisor.md +91 -0
- package/hooks/blocking/test_fable_spawn_gate.py +18 -11
- package/package.json +1 -1
- package/skills/_shared/advisor/CLAUDE.md +1 -1
- package/skills/_shared/advisor/scripts/README.md +2 -0
- package/skills/grokify/SKILL.md +1 -1
- package/skills/grokify/templates/handoff-template.md +2 -2
- package/skills/orchestrator/SKILL.md +5 -4
- package/skills/team-advisor/SKILL.md +7 -4
- package/skills/team-advisor/reference/advisor-docs-review.md +207 -0
- package/skills/usage-pause/SKILL.md +1 -1
- package/skills/usage-pause/scripts/resolve_usage_window.py +32 -4
- package/skills/usage-pause/scripts/test_resolve_usage_window.py +26 -0
- package/skills/usage-pause/scripts/usage_pause_constants/resolve_usage_window_constants.py +3 -1
|
@@ -16,25 +16,28 @@ One warm advisor at the strongest tier this session can reach. This session is t
|
|
|
16
16
|
| Doc | Holds |
|
|
17
17
|
|---|---|
|
|
18
18
|
| [`docs/references/advisor-tool.md`](../../docs/references/advisor-tool.md) | **Consult cadence and weight** — when to call, hard rule before first write, how to treat advice. Read this for every consult. |
|
|
19
|
-
| [`~/.claude/_shared/advisor/advisor-protocol.md`](../../_shared/advisor/advisor-protocol.md) | **Bind and lifecycle** — host detect, model floor, warm-up
|
|
19
|
+
| [`~/.claude/_shared/advisor/advisor-protocol.md`](../../_shared/advisor/advisor-protocol.md) | **Bind and lifecycle** — host detect, model floor, warm-up, CLI fallback; its read map routes each moment to a `reference/` detail file. |
|
|
20
20
|
| [`agents/session-advisor.md`](../../agents/session-advisor.md) | **Reply contract** — ENDORSE / CORRECTION / PLAN / STOP; SendMessage only. |
|
|
21
|
+
| [`reference/advisor-docs-review.md`](reference/advisor-docs-review.md) | Anthropic advisor-tool source facts: measured effects, Sonnet steering, cost levers, failure modes. Background — read it when tuning the bind, not on every consult. |
|
|
21
22
|
|
|
22
23
|
## Bind
|
|
23
24
|
|
|
24
25
|
1. Detect the host profile first (protocol **Host profiles**), then walk the model floor.
|
|
25
|
-
2. Floor: this session's own tier on Claude; Opus floor with Fable first on a third-party host.
|
|
26
|
+
2. Floor: the stronger of Opus and this session's own tier on Claude; Opus floor with Fable first on a third-party host.
|
|
26
27
|
3. Name: `team-advisor-agent` on Claude (Agent spawn of `session-advisor`); one CLI `session_id` on a third-party host via the protocol Claude-chain.
|
|
27
28
|
4. A Fable-tier spawn or re-spawn carries the exact token `FABLE-SPAWN-AUTHORIZED` in its prompt (protocol warm-up; `fable_spawn_gate` requires it).
|
|
28
29
|
5. Skip the multi-consumer "who you are" opener — sole consumer.
|
|
29
30
|
6. When the bind or reply path fails, fail closed and report to the user. On a third-party host, only the bound Claude advisor issues ENDORSE / CORRECTION / PLAN / STOP.
|
|
30
31
|
|
|
31
|
-
Full walk, charter, consult
|
|
32
|
+
Full walk, charter, consult packet, Sol routing, and drift re-bind live in the protocol read map and its authoritative `reference/` leaves.
|
|
32
33
|
|
|
33
34
|
## Consult
|
|
34
35
|
|
|
35
36
|
Follow **When to call**, **Hard rule**, and **How to treat advice** in `advisor-tool.md`.
|
|
36
37
|
|
|
37
|
-
|
|
38
|
+
Build every first brief with [`_shared/advisor/reference/consult-format.md`](../../_shared/advisor/reference/consult-format.md). Later briefs carry only the delta and changed evidence.
|
|
39
|
+
|
|
40
|
+
Aim for two consults on a normal task: one after orientation and one after writes and validation. Reserve a third for advisory recovery or reconciliation guidance, and add a consult when a material fork produces new evidence. This is an advisory target owned by the task, not a cap or gate.
|
|
38
41
|
|
|
39
42
|
## Constraints
|
|
40
43
|
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
# Advisor-Tool Documentation Review
|
|
2
|
+
|
|
3
|
+
Distilled facts from the Anthropic advisor-tool documentation, for the
|
|
4
|
+
Sonnet-executor advisor path and the hand-rolled `/team-advisor` bind. Every
|
|
5
|
+
source claim below cites its page; section H is repository practice and says
|
|
6
|
+
so.
|
|
7
|
+
|
|
8
|
+
Consult timing, the hard rule before a first write, and how to weigh the
|
|
9
|
+
advice live in [`docs/references/advisor-tool.md`](../../../docs/references/advisor-tool.md).
|
|
10
|
+
The consult cadence lives in [`SKILL.md`](../SKILL.md). This file carries the
|
|
11
|
+
source facts those two omit: measured effects, Sonnet steering, cost levers,
|
|
12
|
+
failure modes, and what transfers to a hand-rolled bind.
|
|
13
|
+
|
|
14
|
+
## Sources
|
|
15
|
+
|
|
16
|
+
| # | Page |
|
|
17
|
+
|---|---|
|
|
18
|
+
| 1 | [Advisor tool — platform docs](https://platform.claude.com/docs/en/agents-and-tools/tool-use/advisor-tool) |
|
|
19
|
+
| 2 | [Escalate hard decisions with the advisor tool — Claude Code](https://code.claude.com/docs/en/advisor) |
|
|
20
|
+
| 3 | [The advisor strategy — blog](https://claude.com/blog/the-advisor-strategy) |
|
|
21
|
+
| 4 | [Best practices for computer and browser use — blog](https://claude.com/blog/best-practices-for-computer-and-browser-use-with-claude) |
|
|
22
|
+
| 5 | [Claude models explained — blog](https://claude.com/blog/claude-models-explained-choosing-the-best-model-for-your-use-case) |
|
|
23
|
+
| 6 | [Messages API — beta](https://platform.claude.com/docs/en/api/beta/messages) |
|
|
24
|
+
| 7 | [Claude Code changelog](https://code.claude.com/docs/en/changelog) |
|
|
25
|
+
|
|
26
|
+
## A. Consult timing the canonical rules omit
|
|
27
|
+
|
|
28
|
+
Planner funnel, page 1:
|
|
29
|
+
|
|
30
|
+
```text
|
|
31
|
+
If your agent exposes other planner-like tools (for example, a todo list
|
|
32
|
+
tool), prompt the model to call the advisor before those tools so the
|
|
33
|
+
advisor's plan funnels into them.
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Consult moments for long agent runs, page 4: "choosing which tab to open,
|
|
37
|
+
recovering from an unexpected modal, deciding whether to abandon a strategy".
|
|
38
|
+
|
|
39
|
+
Frequency control stays prompt-only, page 2:
|
|
40
|
+
|
|
41
|
+
```text
|
|
42
|
+
There is no setting to cap or force advisor calls; if you want Claude to
|
|
43
|
+
consult more or less often during a task, say so in your instructions.
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## B. Measured effect of the hard rule
|
|
47
|
+
|
|
48
|
+
The rule itself — an advisor call before the first write, edit, or
|
|
49
|
+
state-changing shell call — lives under **Hard rule** in
|
|
50
|
+
[`advisor-tool.md`](../../../docs/references/advisor-tool.md). Page 1 states
|
|
51
|
+
it inside the Haiku and Opus system-prompt blocks and reports its effect:
|
|
52
|
+
the Haiku coding block raises pass rates by roughly 7.5 points on an
|
|
53
|
+
internal coding benchmark. On Opus the same checkpoint raises
|
|
54
|
+
under-calling tasks 7–10 points and holds roughly flat on a mixed workload
|
|
55
|
+
where plan-free tasks over-call.
|
|
56
|
+
|
|
57
|
+
## C. Sonnet-executor facts
|
|
58
|
+
|
|
59
|
+
Page 1 marks the startup nudge as dead weight on Sonnet:
|
|
60
|
+
|
|
61
|
+
```text
|
|
62
|
+
On Sonnet executors, the plain-text nudge had no measurable effect in
|
|
63
|
+
Anthropic's testing.
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Steering for a Sonnet executor belongs in the system prompt, prepended
|
|
67
|
+
"before any other sentences that mention the advisor" (page 1).
|
|
68
|
+
|
|
69
|
+
Page 4 names a long-session gap: the executor does not always remember the
|
|
70
|
+
advisor exists on long-horizon tasks; the tested pattern is a one-line
|
|
71
|
+
reminder after roughly 20 advisor-free turns.
|
|
72
|
+
|
|
73
|
+
Named pairing, page 1:
|
|
74
|
+
|
|
75
|
+
```text
|
|
76
|
+
You currently use Sonnet on complex tasks: Add a higher-tier advisor. Opus
|
|
77
|
+
keeps total cost similar or lower; Claude Fable 5 maximizes the quality lift.
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Effort pairing, page 1:
|
|
81
|
+
|
|
82
|
+
```text
|
|
83
|
+
For coding tasks, pairing a Sonnet executor at medium effort with an Opus
|
|
84
|
+
advisor achieves intelligence comparable to Sonnet at default effort, at
|
|
85
|
+
lower cost. For maximum intelligence, keep the executor at default effort.
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
Page 3 footnotes the benchmark condition: the Sonnet-plus-advisor SWE-bench
|
|
89
|
+
Multilingual run uses the suggested system prompt "with thinking turned
|
|
90
|
+
off" — a consult substitutes for extended thinking in that run.
|
|
91
|
+
|
|
92
|
+
## D. Benchmarks
|
|
93
|
+
|
|
94
|
+
Page 3 and page 5 report these results:
|
|
95
|
+
|
|
96
|
+
- Sonnet 4.6 with an Opus 4.6 advisor: +2.7 points on SWE-bench Multilingual
|
|
97
|
+
over Sonnet solo, cost per agentic task down 11.9%.
|
|
98
|
+
- Haiku 4.5 with an Opus advisor on BrowseComp: 41.2% versus 19.7% solo;
|
|
99
|
+
trails Sonnet solo by 29% in score at 85% lower cost per task.
|
|
100
|
+
- Sonnet 5 with a Fable 5 advisor (page 5): within 10% of Fable 5's own score
|
|
101
|
+
at 63% of the price of running Fable 5 for the whole task, on SWE-bench
|
|
102
|
+
Pro.
|
|
103
|
+
|
|
104
|
+
Advisor reply shape, page 3:
|
|
105
|
+
|
|
106
|
+
```text
|
|
107
|
+
Opus accesses the shared context and returns a plan, a correction, or a stop
|
|
108
|
+
signal, and the executor resumes. The advisor never calls tools or produces
|
|
109
|
+
user-facing output.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## E. Cost levers
|
|
113
|
+
|
|
114
|
+
Output size is the advisor's largest cost driver; the top-level `max_tokens`
|
|
115
|
+
parameter does not bound it (pages 1, 4, 6). A tool-definition
|
|
116
|
+
`max_tokens: 2048` cuts mean advisor output roughly 7x with near-zero
|
|
117
|
+
truncation; `1024` cuts roughly 10x and truncates about 10% of calls. The
|
|
118
|
+
server passes the advisor its remaining budget, so the advisor self-shapes
|
|
119
|
+
its reply length.
|
|
120
|
+
|
|
121
|
+
The brevity line belongs in the user message and addresses the advisor
|
|
122
|
+
directly; the wording lives under **Brevity cue** in
|
|
123
|
+
[`advisor-tool.md`](../../../docs/references/advisor-tool.md).
|
|
124
|
+
|
|
125
|
+
Direct address works because the advisor reads the executor's prompt as
|
|
126
|
+
quoted context: "instructions that address the advisor directly are followed
|
|
127
|
+
much more reliably than third-person descriptions." A brief that asks for
|
|
128
|
+
roughly 80 percent of the true ceiling raises consult frequency while
|
|
129
|
+
lowering total cost.
|
|
130
|
+
|
|
131
|
+
Typical advisor output runs 400–700 text tokens, or 1,400–1,800 with
|
|
132
|
+
thinking included.
|
|
133
|
+
|
|
134
|
+
Advisor-side caching breaks even at roughly three consults per conversation;
|
|
135
|
+
set it once and leave it. A `clear_thinking` setting with `keep` other than
|
|
136
|
+
`"all"` shifts the advisor's quoted transcript and causes advisor-side cache
|
|
137
|
+
misses.
|
|
138
|
+
|
|
139
|
+
`max_uses` caps consults per request; Anthropic's launch example sets
|
|
140
|
+
`max_uses: 3`. Conversation-level caps count client-side; dropping the tool
|
|
141
|
+
requires stripping every `advisor_tool_result` block from history, or the API
|
|
142
|
+
returns 400.
|
|
143
|
+
|
|
144
|
+
## F. Failure modes and API mechanics
|
|
145
|
+
|
|
146
|
+
Error codes the advisor call surfaces (pages 1, 6): `max_uses_exceeded`,
|
|
147
|
+
`too_many_requests`, `overloaded`, `prompt_too_long`,
|
|
148
|
+
`execution_time_exceeded`, `unavailable`, `model_not_found`.
|
|
149
|
+
|
|
150
|
+
```text
|
|
151
|
+
The executor sees the error and continues without further advice. The
|
|
152
|
+
request itself does not fail.
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
The advisor runs without tools and without context management; thinking
|
|
156
|
+
blocks are dropped, and only advice text returns. On the server side,
|
|
157
|
+
nothing the executor puts in `input` reaches the advisor — the server
|
|
158
|
+
forwards the full transcript itself.
|
|
159
|
+
|
|
160
|
+
Fable, Opus 5, and Mythos advisors return `advisor_redacted_result`
|
|
161
|
+
(encrypted, round-trips verbatim). Opus 4.8 and below return plaintext
|
|
162
|
+
`advisor_result`. A native Fable-class advisor's encrypted block carries no
|
|
163
|
+
guidance the client can read; when logging or auditing the guidance matters,
|
|
164
|
+
pick a plaintext-returning advisor — the hand-rolled CLI and warm-agent
|
|
165
|
+
paths always yield a readable transcript.
|
|
166
|
+
|
|
167
|
+
Pairing invariant: "The advisor must be at least as capable as the
|
|
168
|
+
executor." Claude Code enforces the same check per subagent — subagents
|
|
169
|
+
inherit the configured advisor and apply the same pairing check against
|
|
170
|
+
their own model.
|
|
171
|
+
|
|
172
|
+
The native advisor is a server tool with no name a permission rule or hook
|
|
173
|
+
matcher can reference, so it bypasses hooks. The bind this skill uses lives
|
|
174
|
+
in [`SKILL.md`](../SKILL.md) **Bind**.
|
|
175
|
+
|
|
176
|
+
Consults run slow enough to look like stalls: changelog 2.1.214 (page 7)
|
|
177
|
+
fixes a spurious "check your network" warning that appeared while the
|
|
178
|
+
advisor was thinking.
|
|
179
|
+
|
|
180
|
+
Usage accounting: each consult is an `advisor_message` entry in
|
|
181
|
+
`usage.iterations[]` with its own model and token counts, billed at advisor
|
|
182
|
+
rates.
|
|
183
|
+
|
|
184
|
+
## G. What transfers to the hand-rolled advisor path
|
|
185
|
+
|
|
186
|
+
The claude-dev-env advisor is a warm agent or CLI session. Three inversions
|
|
187
|
+
apply against the native server tool:
|
|
188
|
+
|
|
189
|
+
1. **Context forwarding is manual.** The native tool auto-forwards the full
|
|
190
|
+
transcript. Everything a hand-rolled advisor sees arrives in the consult.
|
|
191
|
+
Build the first packet with
|
|
192
|
+
[`_shared/advisor/reference/consult-format.md`](../../../_shared/advisor/reference/consult-format.md);
|
|
193
|
+
later consults carry only the delta.
|
|
194
|
+
2. **Caching becomes prefix stability.** The charter and role text stay
|
|
195
|
+
byte-stable at the top of the consult stream; volatile detail goes last.
|
|
196
|
+
3. **Hooks apply.** Consult payloads travel through ordinary tools, so each
|
|
197
|
+
payload stays hook-safe and the bind log is mechanically validated.
|
|
198
|
+
|
|
199
|
+
## H. Measuring the advisor's lift
|
|
200
|
+
|
|
201
|
+
Repository practice, sourced to no page: benchmark three routes on one
|
|
202
|
+
representative workload — the executor alone, the executor plus advisor, and
|
|
203
|
+
the strongest model throughout. Route future work by measured cost per
|
|
204
|
+
successful task.
|
|
205
|
+
|
|
206
|
+
Track, per route: completion rate, regression rate, tool calls, tokens by
|
|
207
|
+
tier, and latency.
|
|
@@ -44,7 +44,7 @@ On exit 2 the script prints `{"error": ...}`. Ask the user for a manual reset ti
|
|
|
44
44
|
In short: the resolver picks a bearer token, probes the OAuth usage endpoint the interactive `/usage` panel uses, and returns the session and weekly buckets with utilization and reset times. Token sources depend on the host:
|
|
45
45
|
|
|
46
46
|
- **Desktop host** (the `CLAUDE_CODE_ENTRYPOINT` variable is `claude-desktop`): the resolver does not read the CLI credential file, which belongs to a different authentication session than the one the desktop app counts usage against. It uses the session ingress token when one is set, and otherwise takes the manual-override path.
|
|
47
|
-
- **Every other host**: the resolver reads the Claude Code CLI's stored OAuth access token first (honored only while unexpired), then the session ingress bearer token file named by `CLAUDE_SESSION_INGRESS_TOKEN_FILE` (cloud sessions) when the credential token is unavailable.
|
|
47
|
+
- **Every other host**: the resolver reads the Claude Code CLI's stored OAuth access token first (honored only while unexpired), then the session ingress bearer token file named by `CLAUDE_SESSION_INGRESS_TOKEN_FILE` (cloud sessions) when the credential token is unavailable. The credential file lives under the directory `CLAUDE_CONFIG_DIR` names when that variable is set — a profile-isolated session's own account — else the home-directory default; the home file on a multi-profile machine can belong to a different account, whose meter is the wrong one to read.
|
|
48
48
|
|
|
49
49
|
Fallbacks, in order: both token sources unavailable (expired/unreadable credential and no ingress file), a failed request, or a response with no readable session-window reset time all end in exit 2 — the manual-override ask above. The manual path works with no probe at all, so the skill functions even when both token sources are unavailable.
|
|
50
50
|
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
|
|
10
10
|
With no ``--override``, the script resolves a bearer token. On the desktop
|
|
11
11
|
host it uses only the session ingress token. On every other host it reads the
|
|
12
|
-
Claude Code OAuth access token from the CLI credential file
|
|
13
|
-
|
|
12
|
+
Claude Code OAuth access token from the CLI credential file — under the
|
|
13
|
+
directory ``CLAUDE_CONFIG_DIR`` names when set, else the home-directory
|
|
14
|
+
default — then the session ingress token file when that credential is
|
|
15
|
+
unavailable. It asks the OAuth
|
|
14
16
|
usage endpoint for the ``five_hour`` and ``seven_day`` windows. Exit code 2
|
|
15
17
|
means the probe cannot resolve; the caller then asks the user for a manual
|
|
16
18
|
reset time.
|
|
@@ -38,10 +40,12 @@ from usage_pause_constants.resolve_usage_window_constants import (
|
|
|
38
40
|
BARE_MINUTES_PATTERN,
|
|
39
41
|
CLOCK_HOUR_MAXIMUM,
|
|
40
42
|
CLOCK_PATTERN,
|
|
43
|
+
CONFIG_DIR_ENV_VAR,
|
|
41
44
|
CONTENT_TYPE_HEADER_NAME,
|
|
42
45
|
CONTENT_TYPE_JSON,
|
|
43
46
|
CREDENTIALS_ACCESS_TOKEN_KEY,
|
|
44
47
|
CREDENTIALS_EXPIRES_AT_KEY,
|
|
48
|
+
CREDENTIALS_FILE_NAME,
|
|
45
49
|
CREDENTIALS_OAUTH_SECTION_KEY,
|
|
46
50
|
DESKTOP_ENTRYPOINT_VALUE,
|
|
47
51
|
DURATION_PATTERN,
|
|
@@ -203,6 +207,27 @@ def plan_wakeup_stages(seconds_until_reset: int) -> list[int]:
|
|
|
203
207
|
return stages
|
|
204
208
|
|
|
205
209
|
|
|
210
|
+
def default_credentials_path() -> Path:
|
|
211
|
+
"""Locate the CLI credential file for the account this session runs as.
|
|
212
|
+
|
|
213
|
+
::
|
|
214
|
+
|
|
215
|
+
CLAUDE_CONFIG_DIR=C:/profiles/mel -> C:/profiles/mel/.credentials.json
|
|
216
|
+
(variable unset or empty) -> ~/.claude/.credentials.json
|
|
217
|
+
|
|
218
|
+
A profile-isolated session keeps its credential under the config-dir
|
|
219
|
+
directory. On such a machine the home file belongs to a different
|
|
220
|
+
account. Reading the home file reports that other account's meter.
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
The credential file for the session's own account.
|
|
224
|
+
"""
|
|
225
|
+
config_directory = os.environ.get(CONFIG_DIR_ENV_VAR)
|
|
226
|
+
if config_directory:
|
|
227
|
+
return Path(config_directory) / CREDENTIALS_FILE_NAME
|
|
228
|
+
return Path.home().joinpath(*ALL_CREDENTIALS_RELATIVE_PATH_PARTS)
|
|
229
|
+
|
|
230
|
+
|
|
206
231
|
def read_oauth_access_token(credentials_path: Path, now: datetime) -> str | None:
|
|
207
232
|
"""Read the CLI's OAuth access token when it is still valid.
|
|
208
233
|
|
|
@@ -523,7 +548,10 @@ def _parse_arguments() -> argparse.Namespace:
|
|
|
523
548
|
parser.add_argument(
|
|
524
549
|
"--credentials-path",
|
|
525
550
|
default=None,
|
|
526
|
-
help=
|
|
551
|
+
help=(
|
|
552
|
+
"Path to the CLI credential file; defaults to the CLAUDE_CONFIG_DIR "
|
|
553
|
+
"location when that variable is set, else the home-directory location."
|
|
554
|
+
),
|
|
527
555
|
)
|
|
528
556
|
return parser.parse_args()
|
|
529
557
|
|
|
@@ -558,7 +586,7 @@ def main() -> int:
|
|
|
558
586
|
credentials_path = (
|
|
559
587
|
Path(arguments.credentials_path)
|
|
560
588
|
if arguments.credentials_path
|
|
561
|
-
else
|
|
589
|
+
else default_credentials_path()
|
|
562
590
|
)
|
|
563
591
|
access_token = resolve_access_token(credentials_path, now)
|
|
564
592
|
if access_token is None:
|
|
@@ -19,6 +19,7 @@ if str(SCRIPTS_DIRECTORY) not in sys.path:
|
|
|
19
19
|
sys.path.insert(0, str(SCRIPTS_DIRECTORY))
|
|
20
20
|
|
|
21
21
|
from usage_pause_constants.resolve_usage_window_constants import ( # noqa: E402
|
|
22
|
+
CONFIG_DIR_ENV_VAR,
|
|
22
23
|
DESKTOP_ENTRYPOINT_VALUE,
|
|
23
24
|
ENTRYPOINT_ENV_VAR,
|
|
24
25
|
SESSION_INGRESS_TOKEN_FILE_ENV_VAR as INGRESS_TOKEN_FILE_ENV_VAR,
|
|
@@ -195,6 +196,31 @@ class TestReadOauthAccessToken:
|
|
|
195
196
|
assert any("unreadable" in each_message for each_message in caplog.messages)
|
|
196
197
|
|
|
197
198
|
|
|
199
|
+
class TestDefaultCredentialsPath:
|
|
200
|
+
def should_use_the_config_dir_credential_file_when_the_variable_is_set(
|
|
201
|
+
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
202
|
+
) -> None:
|
|
203
|
+
resolver = load_resolver_module()
|
|
204
|
+
monkeypatch.setenv(CONFIG_DIR_ENV_VAR, str(tmp_path))
|
|
205
|
+
assert resolver.default_credentials_path() == tmp_path / ".credentials.json"
|
|
206
|
+
|
|
207
|
+
def should_fall_back_to_the_home_credential_file_when_the_variable_is_unset(
|
|
208
|
+
self, monkeypatch: pytest.MonkeyPatch
|
|
209
|
+
) -> None:
|
|
210
|
+
resolver = load_resolver_module()
|
|
211
|
+
monkeypatch.delenv(CONFIG_DIR_ENV_VAR, raising=False)
|
|
212
|
+
expected = Path.home() / ".claude" / ".credentials.json"
|
|
213
|
+
assert resolver.default_credentials_path() == expected
|
|
214
|
+
|
|
215
|
+
def should_fall_back_to_the_home_credential_file_when_the_variable_is_empty(
|
|
216
|
+
self, monkeypatch: pytest.MonkeyPatch
|
|
217
|
+
) -> None:
|
|
218
|
+
resolver = load_resolver_module()
|
|
219
|
+
monkeypatch.setenv(CONFIG_DIR_ENV_VAR, "")
|
|
220
|
+
expected = Path.home() / ".claude" / ".credentials.json"
|
|
221
|
+
assert resolver.default_credentials_path() == expected
|
|
222
|
+
|
|
223
|
+
|
|
198
224
|
class TestReadSessionIngressToken:
|
|
199
225
|
def should_return_stripped_token_from_the_named_file(
|
|
200
226
|
self, tmp_path: Path, monkeypatch: pytest.MonkeyPatch
|
|
@@ -19,6 +19,8 @@ CONTENT_TYPE_JSON = "application/json"
|
|
|
19
19
|
PROBE_TIMEOUT_SECONDS = 10
|
|
20
20
|
|
|
21
21
|
ALL_CREDENTIALS_RELATIVE_PATH_PARTS = (".claude", ".credentials.json")
|
|
22
|
+
CONFIG_DIR_ENV_VAR = "CLAUDE_CONFIG_DIR"
|
|
23
|
+
CREDENTIALS_FILE_NAME = ".credentials.json"
|
|
22
24
|
CREDENTIALS_OAUTH_SECTION_KEY = "claudeAiOauth"
|
|
23
25
|
CREDENTIALS_ACCESS_TOKEN_KEY = "accessToken"
|
|
24
26
|
CREDENTIALS_EXPIRES_AT_KEY = "expiresAt"
|
|
@@ -67,4 +69,4 @@ SOURCE_OVERRIDE = "override"
|
|
|
67
69
|
EXIT_CODE_RESOLVED = 0
|
|
68
70
|
EXIT_CODE_PROBE_UNAVAILABLE = 2
|
|
69
71
|
|
|
70
|
-
LOGGING_FORMAT = "%(levelname)s %(name)s: %(message)s"
|
|
72
|
+
LOGGING_FORMAT = "%(levelname)s %(name)s: %(message)s"
|