claude-dev-env 8.43.4 → 8.43.6
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/_shared/advisor/advisor-protocol.md +2 -2
- package/_shared/advisor/reference/cli-chain.md +9 -12
- package/_shared/advisor/reference/lifecycle.md +1 -1
- package/_shared/advisor/reference/third-party-bind.md +3 -3
- package/bin/install.mjs +39 -3
- package/bin/install.shared-settings.test.mjs +46 -0
- package/bin/install.test.mjs +1 -1
- package/docs/second-claude-account.md +11 -13
- package/package.json +1 -1
- package/scripts/_code_review_test_support.py +29 -39
- package/scripts/claude_account_worker.py +46 -297
- package/scripts/claude_account_worker_process.py +18 -154
- package/scripts/claude_account_worker_report.py +8 -4
- package/scripts/claude_chain_usage.py +7 -271
- package/scripts/codec_forwarding_test_support.py +11 -65
- package/scripts/dev_env_scripts_constants/claude_account_worker_constants.py +6 -24
- package/scripts/invoke_code_review.py +34 -56
- package/scripts/policy_lint/config/approved_test_pairs.py +1 -0
- package/scripts/resolve_worker_spawn.py +40 -72
- package/scripts/test_account_broker_guard.py +0 -4
- package/scripts/test_claude_account_worker.py +105 -350
- package/scripts/test_claude_chain_usage.py +50 -510
- package/scripts/test_dispatcher_profile_import.py +5 -9
- package/scripts/test_invoke_code_review.py +7 -6
- package/scripts/test_invoke_code_review_chain.py +26 -0
- package/scripts/test_invoke_code_review_cli.py +8 -8
- package/scripts/test_invoke_code_review_codec.py +3 -11
- package/scripts/test_invoke_code_review_contract.py +5 -1
- package/scripts/test_resolve_worker_spawn.py +118 -265
- package/scripts/test_resolve_worker_spawn_codec.py +9 -21
- package/scripts/tests/test_code_review_constants.py +2 -2
- package/scripts/tests/test_policy_lint_rules_pairing.py +13 -0
- package/scripts/claude_account_choice.py +0 -422
- package/scripts/claude_chain_runner.py +0 -1289
- package/scripts/test_claude_account_choice.py +0 -355
- package/scripts/test_claude_chain_runner.py +0 -1839
|
@@ -7,14 +7,14 @@ Mode decision::
|
|
|
7
7
|
host=Claude, session_model=sonnet -> mode chain (headless opus spawn)
|
|
8
8
|
host=ThirdParty, any model -> mode chain
|
|
9
9
|
|
|
10
|
-
Chain mode runs
|
|
10
|
+
Chain mode runs the account broker with argv from ``build_code_review_arguments``
|
|
11
11
|
(single-turn prompt, model opus, json output, and the permission mode this
|
|
12
12
|
caller is allowed to ask the review binary for).
|
|
13
13
|
|
|
14
14
|
cwd is the PR working tree and stdin is redirected from the empty stream so
|
|
15
15
|
the spawn does not wait for interactive input. Result JSON on stdout only::
|
|
16
16
|
|
|
17
|
-
{"mode", "served_command", "returncode", "dirty_tree"}
|
|
17
|
+
{"mode", "served_command", "returncode", "dirty_tree", "status", "wait_reset_at"}
|
|
18
18
|
|
|
19
19
|
Import ``invoke_code_review`` for the outcome object, or run as a CLI::
|
|
20
20
|
|
|
@@ -29,7 +29,7 @@ import json
|
|
|
29
29
|
import os
|
|
30
30
|
import subprocess
|
|
31
31
|
import sys
|
|
32
|
-
from collections.abc import Callable
|
|
32
|
+
from collections.abc import Callable
|
|
33
33
|
from dataclasses import dataclass
|
|
34
34
|
from pathlib import Path
|
|
35
35
|
|
|
@@ -58,16 +58,13 @@ from tier_model_ids import detect_host_profile # noqa: E402
|
|
|
58
58
|
from advisor_scripts_constants.model_tier_run_validator_constants import ( # noqa: E402
|
|
59
59
|
HOST_PROFILE_CLAUDE,
|
|
60
60
|
)
|
|
61
|
-
|
|
62
|
-
from
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
)
|
|
67
|
-
from dev_env_scripts_constants.claude_chain_constants import ( # noqa: E402
|
|
68
|
-
CHAIN_CONFIG_ERROR_EXIT_CODE,
|
|
69
|
-
collect_forwarded_text_codec,
|
|
61
|
+
from account_broker import run_job
|
|
62
|
+
from dev_env_scripts_constants.account_broker_constants import (
|
|
63
|
+
BrokerConfigurationError,
|
|
64
|
+
JobOutcome,
|
|
65
|
+
Product,
|
|
70
66
|
)
|
|
67
|
+
from dev_env_scripts_constants.claude_chain_constants import CHAIN_CONFIG_ERROR_EXIT_CODE
|
|
71
68
|
from dev_env_scripts_constants.code_review_constants import ( # noqa: E402
|
|
72
69
|
ALL_EFFORT_TOKENS_IN_ASCENDING_ORDER,
|
|
73
70
|
CLI_EFFORT_HELP,
|
|
@@ -116,7 +113,7 @@ class CodeReviewOutcome:
|
|
|
116
113
|
|
|
117
114
|
``mode`` is ``in_session`` when the skill should run the slash command
|
|
118
115
|
itself, or ``chain`` when a headless spawn already ran. ``served_command``
|
|
119
|
-
names the
|
|
116
|
+
names the broker account that served a chain run, or ``None`` otherwise.
|
|
120
117
|
``is_dirty_tree`` is True when ``git status --porcelain`` is non-empty
|
|
121
118
|
after a chain run (fixes applied).
|
|
122
119
|
"""
|
|
@@ -125,9 +122,11 @@ class CodeReviewOutcome:
|
|
|
125
122
|
served_command: str | None
|
|
126
123
|
returncode: int
|
|
127
124
|
is_dirty_tree: bool
|
|
125
|
+
status: str | None = None
|
|
126
|
+
wait_reset_at: str | None = None
|
|
128
127
|
|
|
129
128
|
|
|
130
|
-
review_claude_runner =
|
|
129
|
+
review_claude_runner = run_job
|
|
131
130
|
review_host_profile_detector = detect_host_profile
|
|
132
131
|
review_git_status_runner = subprocess.run
|
|
133
132
|
|
|
@@ -198,7 +197,7 @@ def build_code_review_prompt(effort: str) -> str:
|
|
|
198
197
|
def build_code_review_arguments(
|
|
199
198
|
effort: str = DEFAULT_CODE_REVIEW_EFFORT,
|
|
200
199
|
) -> list[str]:
|
|
201
|
-
"""Return the argv tokens passed to
|
|
200
|
+
"""Return the argv tokens passed to the account broker for a review.
|
|
202
201
|
|
|
203
202
|
::
|
|
204
203
|
|
|
@@ -308,41 +307,16 @@ def _run_claude_with_empty_stdin(
|
|
|
308
307
|
*,
|
|
309
308
|
timeout_seconds: int,
|
|
310
309
|
working_directory: Path,
|
|
311
|
-
) ->
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
timeout_for_run: float | None
|
|
322
|
-
if isinstance(maybe_timeout, (int, float)):
|
|
323
|
-
timeout_for_run = float(maybe_timeout)
|
|
324
|
-
else:
|
|
325
|
-
timeout_for_run = None
|
|
326
|
-
forwarded_text_codec = collect_forwarded_text_codec(all_keywords)
|
|
327
|
-
completed_process: subprocess.CompletedProcess[str] = previous_runner(
|
|
328
|
-
all_invocation_tokens,
|
|
329
|
-
capture_output=True,
|
|
330
|
-
text=True,
|
|
331
|
-
timeout=timeout_for_run,
|
|
332
|
-
check=False,
|
|
333
|
-
stdin=subprocess.DEVNULL,
|
|
334
|
-
cwd=working_directory_path,
|
|
335
|
-
**forwarded_text_codec,
|
|
336
|
-
)
|
|
337
|
-
return completed_process
|
|
338
|
-
|
|
339
|
-
empty_stdin_runner: TextCapturingSubprocessRunner = _runner_with_empty_stdin
|
|
340
|
-
with chain_runner.override_chain_subprocess_runner(
|
|
341
|
-
empty_stdin_runner
|
|
342
|
-
) as previous_runner:
|
|
343
|
-
return review_claude_runner(
|
|
344
|
-
all_claude_arguments, timeout_seconds=timeout_seconds
|
|
345
|
-
)
|
|
310
|
+
) -> JobOutcome:
|
|
311
|
+
return review_claude_runner(
|
|
312
|
+
Product.CLAUDE,
|
|
313
|
+
["claude", *all_claude_arguments],
|
|
314
|
+
timeout_seconds=timeout_seconds,
|
|
315
|
+
stdin_text="",
|
|
316
|
+
cwd=working_directory,
|
|
317
|
+
encoding="utf-8",
|
|
318
|
+
errors="replace",
|
|
319
|
+
)
|
|
346
320
|
|
|
347
321
|
|
|
348
322
|
def _in_session_outcome() -> CodeReviewOutcome:
|
|
@@ -355,15 +329,17 @@ def _in_session_outcome() -> CodeReviewOutcome:
|
|
|
355
329
|
|
|
356
330
|
|
|
357
331
|
def _chain_outcome(
|
|
358
|
-
chain_outcome:
|
|
332
|
+
chain_outcome: JobOutcome,
|
|
359
333
|
*,
|
|
360
334
|
working_directory: Path,
|
|
361
335
|
) -> CodeReviewOutcome:
|
|
362
336
|
return CodeReviewOutcome(
|
|
363
337
|
mode=MODE_CHAIN,
|
|
364
|
-
served_command=chain_outcome.
|
|
338
|
+
served_command=chain_outcome.account_name,
|
|
365
339
|
returncode=chain_outcome.returncode,
|
|
366
|
-
is_dirty_tree=is_working_tree_dirty(working_directory),
|
|
340
|
+
is_dirty_tree=is_working_tree_dirty(working_directory) if chain_outcome.account_name else False,
|
|
341
|
+
status=chain_outcome.status,
|
|
342
|
+
wait_reset_at=chain_outcome.wait_reset_at.isoformat() if chain_outcome.wait_reset_at else None,
|
|
367
343
|
)
|
|
368
344
|
|
|
369
345
|
|
|
@@ -410,7 +386,7 @@ def invoke_code_review(
|
|
|
410
386
|
Args:
|
|
411
387
|
working_directory: PR working tree used as cwd for the chain spawn.
|
|
412
388
|
session_model: Caller-stated session model short alias.
|
|
413
|
-
timeout_seconds: Timeout applied to
|
|
389
|
+
timeout_seconds: Timeout applied to the broker job.
|
|
414
390
|
effort: Effort token embedded in the ``/code-review`` prompt.
|
|
415
391
|
|
|
416
392
|
Returns:
|
|
@@ -447,6 +423,8 @@ def encode_code_review_outcome(
|
|
|
447
423
|
RESULT_KEY_SERVED_COMMAND: review_outcome.served_command,
|
|
448
424
|
RESULT_KEY_RETURNCODE: review_outcome.returncode,
|
|
449
425
|
RESULT_KEY_DIRTY_TREE: review_outcome.is_dirty_tree,
|
|
426
|
+
"status": review_outcome.status,
|
|
427
|
+
"wait_reset_at": review_outcome.wait_reset_at,
|
|
450
428
|
}
|
|
451
429
|
|
|
452
430
|
|
|
@@ -469,7 +447,7 @@ def _add_review_arguments(parser: argparse.ArgumentParser) -> None:
|
|
|
469
447
|
dest="timeout_seconds",
|
|
470
448
|
type=int,
|
|
471
449
|
default=DEFAULT_CODE_REVIEW_TIMEOUT_SECONDS,
|
|
472
|
-
help="Timeout in seconds applied to
|
|
450
|
+
help="Timeout in seconds applied to the broker job.",
|
|
473
451
|
)
|
|
474
452
|
|
|
475
453
|
|
|
@@ -509,7 +487,7 @@ def _run_plain_review_cli(*, parsed_arguments: argparse.Namespace, effort: str)
|
|
|
509
487
|
timeout_seconds=parsed_arguments.timeout_seconds,
|
|
510
488
|
effort=effort,
|
|
511
489
|
)
|
|
512
|
-
except
|
|
490
|
+
except BrokerConfigurationError:
|
|
513
491
|
review_outcome = _failure_code_review_outcome(CHAIN_CONFIG_ERROR_EXIT_CODE)
|
|
514
492
|
except ValueError:
|
|
515
493
|
review_outcome = _failure_code_review_outcome(HOST_PROFILE_ERROR_RETURNCODE)
|
|
@@ -23,6 +23,7 @@ APPROVED_TEST_PATHS_BY_PRODUCTION_PATH: dict[
|
|
|
23
23
|
{
|
|
24
24
|
PurePosixPath("packages/claude-dev-env/bin/install.agents-home.test.mjs"),
|
|
25
25
|
PurePosixPath("packages/claude-dev-env/bin/install.cursor-rules.test.mjs"),
|
|
26
|
+
PurePosixPath("packages/claude-dev-env/bin/install.shared-settings.test.mjs"),
|
|
26
27
|
}
|
|
27
28
|
),
|
|
28
29
|
PurePosixPath(
|
|
@@ -9,7 +9,7 @@ Walk order:
|
|
|
9
9
|
On a Claude host with the claude tier disabled, stop with
|
|
10
10
|
``claude_agent_required`` so the calling skill runs the Agent tool.
|
|
11
11
|
On a third-party host, or when the claude tier is enabled, tier 3 runs
|
|
12
|
-
|
|
12
|
+
the account broker with ``-p --output-format json --agent
|
|
13
13
|
<stem>``, prompt body on stdin from the prompt file, and subprocess
|
|
14
14
|
``cwd`` set to the caller's working directory.
|
|
15
15
|
|
|
@@ -27,10 +27,9 @@ import json
|
|
|
27
27
|
import os
|
|
28
28
|
import subprocess
|
|
29
29
|
import sys
|
|
30
|
-
from collections.abc import Callable
|
|
30
|
+
from collections.abc import Callable
|
|
31
31
|
from dataclasses import dataclass
|
|
32
32
|
from pathlib import Path
|
|
33
|
-
from typing import IO
|
|
34
33
|
|
|
35
34
|
_scripts_directory_path = Path(__file__).resolve().parent
|
|
36
35
|
_scripts_directory = str(_scripts_directory_path)
|
|
@@ -57,14 +56,12 @@ from tier_model_ids import detect_host_profile # noqa: E402
|
|
|
57
56
|
from advisor_scripts_constants.model_tier_run_validator_constants import ( # noqa: E402
|
|
58
57
|
HOST_PROFILE_CLAUDE,
|
|
59
58
|
)
|
|
60
|
-
|
|
61
|
-
from
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
from dev_env_scripts_constants.claude_chain_constants import ( # noqa: E402
|
|
67
|
-
collect_forwarded_text_codec,
|
|
59
|
+
from account_broker import run_job
|
|
60
|
+
from dev_env_scripts_constants.account_broker_constants import (
|
|
61
|
+
BrokerConfigurationError,
|
|
62
|
+
JobOutcome,
|
|
63
|
+
Product,
|
|
64
|
+
WAIT_EXIT_CODE,
|
|
68
65
|
)
|
|
69
66
|
from dev_env_scripts_constants.grok_worker_constants import ( # noqa: E402
|
|
70
67
|
AGENT_FLAG,
|
|
@@ -136,20 +133,16 @@ class SpawnOutcome:
|
|
|
136
133
|
captured_stdout: str
|
|
137
134
|
returncode: int
|
|
138
135
|
is_config_error: bool = False
|
|
136
|
+
status: str | None = None
|
|
137
|
+
wait_reset_at: str | None = None
|
|
139
138
|
|
|
140
139
|
|
|
141
140
|
spawn_preflight_runner = run_preflight
|
|
142
141
|
spawn_grok_runner = run_headless_worker
|
|
143
|
-
spawn_claude_runner =
|
|
142
|
+
spawn_claude_runner = run_job
|
|
144
143
|
spawn_host_profile_detector = detect_host_profile
|
|
145
144
|
|
|
146
145
|
|
|
147
|
-
TextCapturingSubprocessRunner = Callable[
|
|
148
|
-
...,
|
|
149
|
-
subprocess.CompletedProcess[str],
|
|
150
|
-
]
|
|
151
|
-
|
|
152
|
-
|
|
153
146
|
def _attempt(tier: int, *, is_ok: bool, reason: str | None) -> SpawnAttempt:
|
|
154
147
|
return SpawnAttempt(tier=tier, is_ok=is_ok, reason=reason)
|
|
155
148
|
|
|
@@ -173,51 +166,22 @@ def _build_claude_arguments(*, agent_name: str) -> list[str]:
|
|
|
173
166
|
]
|
|
174
167
|
|
|
175
168
|
|
|
176
|
-
def _timeout_seconds_from_keywords(
|
|
177
|
-
all_keywords: dict[str, object],
|
|
178
|
-
) -> float | None:
|
|
179
|
-
maybe_timeout = all_keywords.get("timeout")
|
|
180
|
-
if isinstance(maybe_timeout, (int, float)):
|
|
181
|
-
return float(maybe_timeout)
|
|
182
|
-
return None
|
|
183
|
-
|
|
184
|
-
|
|
185
169
|
def _run_claude_with_headless_overrides(
|
|
186
170
|
all_claude_arguments: list[str],
|
|
187
171
|
*,
|
|
188
172
|
timeout_seconds: int,
|
|
189
173
|
working_directory: Path,
|
|
190
|
-
|
|
191
|
-
) ->
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
forwarded_text_codec = collect_forwarded_text_codec(all_keywords)
|
|
202
|
-
completed_process: subprocess.CompletedProcess[str] = previous_runner(
|
|
203
|
-
all_invocation_tokens,
|
|
204
|
-
capture_output=True,
|
|
205
|
-
text=True,
|
|
206
|
-
timeout=_timeout_seconds_from_keywords(all_keywords),
|
|
207
|
-
check=False,
|
|
208
|
-
stdin=prompt_stdin,
|
|
209
|
-
cwd=working_directory_path,
|
|
210
|
-
**forwarded_text_codec,
|
|
211
|
-
)
|
|
212
|
-
return completed_process
|
|
213
|
-
|
|
214
|
-
headless_runner: TextCapturingSubprocessRunner = _runner_with_headless_overrides
|
|
215
|
-
with chain_runner.override_chain_subprocess_runner(
|
|
216
|
-
headless_runner
|
|
217
|
-
) as previous_runner:
|
|
218
|
-
return spawn_claude_runner(
|
|
219
|
-
all_claude_arguments, timeout_seconds=timeout_seconds
|
|
220
|
-
)
|
|
174
|
+
prompt_text: str,
|
|
175
|
+
) -> JobOutcome:
|
|
176
|
+
return spawn_claude_runner(
|
|
177
|
+
Product.CLAUDE,
|
|
178
|
+
["claude", *all_claude_arguments],
|
|
179
|
+
timeout_seconds=timeout_seconds,
|
|
180
|
+
stdin_text=prompt_text,
|
|
181
|
+
cwd=working_directory,
|
|
182
|
+
encoding="utf-8",
|
|
183
|
+
errors="replace",
|
|
184
|
+
)
|
|
221
185
|
|
|
222
186
|
|
|
223
187
|
def _prompt_file_unreadable_outcome(
|
|
@@ -261,9 +225,9 @@ def _claude_agent_required_outcome(
|
|
|
261
225
|
|
|
262
226
|
def _served_claude_outcome(
|
|
263
227
|
all_attempts: list[SpawnAttempt],
|
|
264
|
-
chain_outcome:
|
|
228
|
+
chain_outcome: JobOutcome,
|
|
265
229
|
) -> SpawnOutcome:
|
|
266
|
-
is_served = chain_outcome.
|
|
230
|
+
is_served = chain_outcome.account_name is not None
|
|
267
231
|
is_ok = is_served and chain_outcome.returncode == SPAWN_SERVED_EXIT_CODE
|
|
268
232
|
all_attempts.append(_attempt(TIER_CLAUDE_HEADLESS, is_ok=is_ok, reason=None))
|
|
269
233
|
if not is_served:
|
|
@@ -273,6 +237,8 @@ def _served_claude_outcome(
|
|
|
273
237
|
all_attempts=tuple(all_attempts),
|
|
274
238
|
captured_stdout=chain_outcome.stdout,
|
|
275
239
|
returncode=chain_outcome.returncode,
|
|
240
|
+
status=chain_outcome.status,
|
|
241
|
+
wait_reset_at=chain_outcome.wait_reset_at.isoformat() if chain_outcome.wait_reset_at else None,
|
|
276
242
|
)
|
|
277
243
|
return SpawnOutcome(
|
|
278
244
|
tier_used=TIER_CLAUDE_HEADLESS,
|
|
@@ -280,6 +246,7 @@ def _served_claude_outcome(
|
|
|
280
246
|
all_attempts=tuple(all_attempts),
|
|
281
247
|
captured_stdout=chain_outcome.stdout,
|
|
282
248
|
returncode=chain_outcome.returncode,
|
|
249
|
+
status=chain_outcome.status,
|
|
283
250
|
)
|
|
284
251
|
|
|
285
252
|
|
|
@@ -293,18 +260,15 @@ def _run_tier_claude_headless(
|
|
|
293
260
|
) -> SpawnOutcome:
|
|
294
261
|
all_claude_arguments = _build_claude_arguments(agent_name=agent_name)
|
|
295
262
|
try:
|
|
296
|
-
|
|
263
|
+
prompt_text = prompt_file.read_text(encoding=UTF8_ENCODING)
|
|
297
264
|
except OSError:
|
|
298
265
|
return _prompt_file_unreadable_outcome(all_attempts)
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
)
|
|
306
|
-
finally:
|
|
307
|
-
prompt_stdin.close()
|
|
266
|
+
chain_outcome = _run_claude_with_headless_overrides(
|
|
267
|
+
all_claude_arguments,
|
|
268
|
+
timeout_seconds=timeout_seconds,
|
|
269
|
+
working_directory=working_directory,
|
|
270
|
+
prompt_text=prompt_text,
|
|
271
|
+
)
|
|
308
272
|
return _served_claude_outcome(all_attempts, chain_outcome)
|
|
309
273
|
|
|
310
274
|
|
|
@@ -505,6 +469,8 @@ def encode_spawn_outcome(spawn_outcome: SpawnOutcome) -> dict[str, object]:
|
|
|
505
469
|
RESULT_KEY_ATTEMPTS: all_encoded_attempts,
|
|
506
470
|
RESULT_KEY_OUTPUT: spawn_outcome.captured_stdout,
|
|
507
471
|
RESULT_KEY_RETURNCODE: spawn_outcome.returncode,
|
|
472
|
+
"status": spawn_outcome.status,
|
|
473
|
+
"wait_reset_at": spawn_outcome.wait_reset_at,
|
|
508
474
|
}
|
|
509
475
|
|
|
510
476
|
|
|
@@ -568,6 +534,8 @@ def _exit_code_for_outcome(
|
|
|
568
534
|
) -> int:
|
|
569
535
|
if is_config_error or spawn_outcome.is_config_error:
|
|
570
536
|
return SPAWN_CONFIG_ERROR_EXIT_CODE
|
|
537
|
+
if spawn_outcome.status in {"wait", "exhausted"}:
|
|
538
|
+
return WAIT_EXIT_CODE
|
|
571
539
|
if spawn_outcome.tier_used is None:
|
|
572
540
|
return SPAWN_EXHAUSTED_EXIT_CODE
|
|
573
541
|
return SPAWN_SERVED_EXIT_CODE
|
|
@@ -639,7 +607,7 @@ def main(all_command_arguments: list[str]) -> int:
|
|
|
639
607
|
|
|
640
608
|
A timeout outside the accepted bounds is a config fault: the run prints a
|
|
641
609
|
structured outcome whose attempt reason is ``timeout_out_of_bounds`` and
|
|
642
|
-
exits ``3``, rather than raising out of the CLI. A
|
|
610
|
+
exits ``3``, rather than raising out of the CLI. A broker configuration error,
|
|
643
611
|
or an unknown host profile refused by ``detect_host_profile``, prints the
|
|
644
612
|
same exit code with the refusal text as its output.
|
|
645
613
|
|
|
@@ -672,7 +640,7 @@ def main(all_command_arguments: list[str]) -> int:
|
|
|
672
640
|
except WorkerTimeoutOutOfBoundsError as bounds_error:
|
|
673
641
|
is_config_error = True
|
|
674
642
|
spawn_outcome = _timeout_out_of_bounds_outcome(bounds_error)
|
|
675
|
-
except (
|
|
643
|
+
except (BrokerConfigurationError, ValueError) as configuration_error:
|
|
676
644
|
is_config_error = True
|
|
677
645
|
spawn_outcome = _config_error_outcome(configuration_error)
|
|
678
646
|
return _write_spawn_outcome_and_exit_code(
|
|
@@ -7,10 +7,6 @@ from pathlib import Path
|
|
|
7
7
|
SCRIPTS = Path(__file__).resolve().parent
|
|
8
8
|
ALLOWED_LEGACY_MODULES = frozenset(
|
|
9
9
|
{
|
|
10
|
-
"claude_account_choice.py",
|
|
11
|
-
"claude_account_worker.py",
|
|
12
|
-
"claude_chain_runner.py",
|
|
13
|
-
"claude_chain_usage.py",
|
|
14
10
|
"codex_account_choice.py",
|
|
15
11
|
"codex_account_meters.py",
|
|
16
12
|
}
|