claude-dev-env 8.13.0 → 8.15.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/.agents/skills/everything-search/SKILL.md +1 -1
- package/.agents/skills/second-account-workers/.claude/CLAUDE.md +1 -0
- package/.agents/skills/second-account-workers/AGENTS.md +1 -0
- package/.agents/skills/second-account-workers/SKILL.md +65 -0
- package/.agents/skills/team-advisor/SKILL.md +1 -1
- package/_shared/advisor/advisor-protocol.md +19 -19
- package/_shared/advisor/reference/advisor-block.md +1 -1
- package/_shared/advisor/reference/astra-rung.md +6 -6
- package/_shared/advisor/reference/identity.md +4 -4
- package/_shared/advisor/reference/lifecycle.md +2 -2
- package/_shared/advisor/reference/spawn-walk-log.md +4 -4
- package/_shared/advisor/reference/third-party-bind.md +6 -6
- package/_shared/advisor/reference/warm-up.md +3 -3
- package/_shared/advisor/scripts/config/advisor_scripts_constants/advisor_route_constants.py +2 -2
- package/_shared/advisor/scripts/config/advisor_scripts_constants/model_tier_run_validator_constants.py +3 -3
- package/_shared/advisor/scripts/model_tier_run_validator.py +8 -9
- package/_shared/advisor/scripts/tests/test_model_tier_run_validator.py +91 -91
- package/bin/ever-shipped-skills.mjs +1 -0
- package/bin/install.prompt-context.test.mjs +42 -0
- package/docs/DJANGO_PATTERNS.md +2 -2
- package/docs/TEST_QUALITY.md +1 -13
- package/docs/second-claude-account.md +4 -0
- package/hooks/hooks.json +1 -6
- package/hooks/session/style_reminder_prompt.py +18 -4
- package/hooks/session/test_style_reminder_prompt.py +57 -3
- package/package.json +1 -1
- package/rules/research-mode.md +1 -1
- package/scripts/claude_account_worker.py +347 -0
- package/scripts/claude_account_worker_process.py +169 -0
- package/scripts/claude_account_worker_report.py +170 -0
- package/scripts/dev_env_scripts_constants/claude_account_worker_constants.py +139 -0
- package/scripts/grok_headless_runner.py +2 -5
- package/scripts/subprocess_stream_text.py +28 -0
- package/scripts/task_usage_events.py +387 -0
- package/scripts/task_usage_report.py +391 -0
- package/scripts/test_claude_account_worker.py +331 -0
- package/scripts/test_task_usage_events.py +47 -0
- package/scripts/test_task_usage_report.py +603 -0
|
@@ -218,19 +218,19 @@ def test_non_object_evidence_reports_the_same_message_at_validate_and_load(
|
|
|
218
218
|
def test_clean_single_spawn_at_top_of_slice_passes() -> None:
|
|
219
219
|
run = ModelTierRun(
|
|
220
220
|
own_tier="Opus",
|
|
221
|
-
candidate_tiers=["
|
|
222
|
-
attempts=[{"tier": "
|
|
223
|
-
selected_tier="
|
|
221
|
+
candidate_tiers=["Opus"],
|
|
222
|
+
attempts=[{"tier": "Opus", "result": "spawned"}],
|
|
223
|
+
selected_tier="Opus",
|
|
224
224
|
)
|
|
225
225
|
assert validate_model_tier_run(run) is None
|
|
226
226
|
|
|
227
227
|
|
|
228
|
-
def
|
|
228
|
+
def test_astra_codex_bind_succeeds_after_opus_when_enabled() -> None:
|
|
229
229
|
run = ModelTierRun(
|
|
230
230
|
own_tier="Opus",
|
|
231
|
-
candidate_tiers=["
|
|
231
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
232
232
|
attempts=[
|
|
233
|
-
{"tier": "
|
|
233
|
+
{"tier": "Opus", "result": "unavailable"},
|
|
234
234
|
{"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
|
|
235
235
|
],
|
|
236
236
|
selected_tier=ADVISOR_MODEL_TIER,
|
|
@@ -239,12 +239,12 @@ def test_astra_codex_bind_succeeds_after_fable_when_enabled() -> None:
|
|
|
239
239
|
assert validate_model_tier_run(run) is None
|
|
240
240
|
|
|
241
241
|
|
|
242
|
-
def
|
|
242
|
+
def test_opus_success_with_astra_enabled_stops_before_astra() -> None:
|
|
243
243
|
run = ModelTierRun(
|
|
244
244
|
own_tier="Opus",
|
|
245
|
-
candidate_tiers=["
|
|
246
|
-
attempts=[{"tier": "
|
|
247
|
-
selected_tier="
|
|
245
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
246
|
+
attempts=[{"tier": "Opus", "result": "spawned"}],
|
|
247
|
+
selected_tier="Opus",
|
|
248
248
|
is_astra_enabled=True,
|
|
249
249
|
)
|
|
250
250
|
assert validate_model_tier_run(run) is None
|
|
@@ -253,7 +253,7 @@ def test_fable_success_with_astra_enabled_stops_before_astra() -> None:
|
|
|
253
253
|
def test_astra_first_walk_raises_when_astra_is_enabled() -> None:
|
|
254
254
|
run = ModelTierRun(
|
|
255
255
|
own_tier="Opus",
|
|
256
|
-
candidate_tiers=[ADVISOR_MODEL_TIER, "
|
|
256
|
+
candidate_tiers=[ADVISOR_MODEL_TIER, "Opus"],
|
|
257
257
|
attempts=[{"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN}],
|
|
258
258
|
selected_tier=ADVISOR_MODEL_TIER,
|
|
259
259
|
is_astra_enabled=True,
|
|
@@ -262,12 +262,12 @@ def test_astra_first_walk_raises_when_astra_is_enabled() -> None:
|
|
|
262
262
|
validate_model_tier_run(run)
|
|
263
263
|
|
|
264
264
|
|
|
265
|
-
def
|
|
265
|
+
def test_astra_rung_follows_opus_on_third_party_cli_floor_when_enabled() -> None:
|
|
266
266
|
run = ModelTierRun(
|
|
267
267
|
own_tier="ThirdParty",
|
|
268
|
-
candidate_tiers=["
|
|
268
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
269
269
|
attempts=[
|
|
270
|
-
{"tier": "
|
|
270
|
+
{"tier": "Opus", "result": "unavailable"},
|
|
271
271
|
{"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
|
|
272
272
|
],
|
|
273
273
|
selected_tier=ADVISOR_MODEL_TIER,
|
|
@@ -281,9 +281,9 @@ def test_astra_rung_follows_fable_on_third_party_cli_floor_when_enabled() -> Non
|
|
|
281
281
|
def test_astra_codex_result_requires_astra_candidate() -> None:
|
|
282
282
|
run = ModelTierRun(
|
|
283
283
|
own_tier="Opus",
|
|
284
|
-
candidate_tiers=["
|
|
285
|
-
attempts=[{"tier": "
|
|
286
|
-
selected_tier="
|
|
284
|
+
candidate_tiers=["Opus"],
|
|
285
|
+
attempts=[{"tier": "Opus", "result": CODEX_BIND_SUCCESS_TOKEN}],
|
|
286
|
+
selected_tier="Opus",
|
|
287
287
|
)
|
|
288
288
|
with pytest.raises(ModelTierRunError):
|
|
289
289
|
validate_model_tier_run(run)
|
|
@@ -292,9 +292,9 @@ def test_astra_codex_result_requires_astra_candidate() -> None:
|
|
|
292
292
|
def test_astra_spawned_result_does_not_count_as_codex_success() -> None:
|
|
293
293
|
run = ModelTierRun(
|
|
294
294
|
own_tier="Opus",
|
|
295
|
-
candidate_tiers=["
|
|
295
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
296
296
|
attempts=[
|
|
297
|
-
{"tier": "
|
|
297
|
+
{"tier": "Opus", "result": "unavailable"},
|
|
298
298
|
{"tier": ADVISOR_MODEL_TIER, "result": "spawned"},
|
|
299
299
|
],
|
|
300
300
|
selected_tier=ADVISOR_MODEL_TIER,
|
|
@@ -304,13 +304,13 @@ def test_astra_spawned_result_does_not_count_as_codex_success() -> None:
|
|
|
304
304
|
validate_model_tier_run(run)
|
|
305
305
|
|
|
306
306
|
|
|
307
|
-
def
|
|
307
|
+
def test_exhausted_opus_walk_fails_closed() -> None:
|
|
308
308
|
run = ModelTierRun(
|
|
309
309
|
own_tier="Opus",
|
|
310
|
-
candidate_tiers=["
|
|
311
|
-
attempts=[{"tier": "
|
|
310
|
+
candidate_tiers=["Opus"],
|
|
311
|
+
attempts=[{"tier": "Opus", "result": "unavailable"}],
|
|
312
312
|
selected_tier=None,
|
|
313
|
-
fallback_reason="
|
|
313
|
+
fallback_reason="Opus did not bind; no advisor",
|
|
314
314
|
)
|
|
315
315
|
assert validate_model_tier_run(run) is None
|
|
316
316
|
|
|
@@ -318,8 +318,8 @@ def test_exhausted_fable_walk_fails_closed() -> None:
|
|
|
318
318
|
def test_fully_exhausted_walk_with_fallback_reason_passes() -> None:
|
|
319
319
|
run = ModelTierRun(
|
|
320
320
|
own_tier="Opus",
|
|
321
|
-
candidate_tiers=["
|
|
322
|
-
attempts=[{"tier": "
|
|
321
|
+
candidate_tiers=["Opus"],
|
|
322
|
+
attempts=[{"tier": "Opus", "result": "unavailable"}],
|
|
323
323
|
selected_tier=None,
|
|
324
324
|
fallback_reason="every candidate tier failed",
|
|
325
325
|
)
|
|
@@ -329,9 +329,9 @@ def test_fully_exhausted_walk_with_fallback_reason_passes() -> None:
|
|
|
329
329
|
def test_opus_candidate_on_advisor_walk_raises() -> None:
|
|
330
330
|
run = ModelTierRun(
|
|
331
331
|
own_tier="Opus",
|
|
332
|
-
candidate_tiers=["
|
|
333
|
-
attempts=[{"tier": "
|
|
334
|
-
selected_tier="
|
|
332
|
+
candidate_tiers=["Opus", "Opus"],
|
|
333
|
+
attempts=[{"tier": "Opus", "result": "spawned"}],
|
|
334
|
+
selected_tier="Opus",
|
|
335
335
|
)
|
|
336
336
|
with pytest.raises(ModelTierRunError):
|
|
337
337
|
validate_model_tier_run(run)
|
|
@@ -340,7 +340,7 @@ def test_opus_candidate_on_advisor_walk_raises() -> None:
|
|
|
340
340
|
def test_attempt_tier_outside_candidate_slice_raises() -> None:
|
|
341
341
|
run = ModelTierRun(
|
|
342
342
|
own_tier="Opus",
|
|
343
|
-
candidate_tiers=["
|
|
343
|
+
candidate_tiers=["Opus"],
|
|
344
344
|
attempts=[{"tier": "Haiku", "result": "spawned"}],
|
|
345
345
|
selected_tier="Haiku",
|
|
346
346
|
)
|
|
@@ -351,10 +351,10 @@ def test_attempt_tier_outside_candidate_slice_raises() -> None:
|
|
|
351
351
|
def test_attempts_out_of_ladder_order_raises() -> None:
|
|
352
352
|
run = ModelTierRun(
|
|
353
353
|
own_tier="Opus",
|
|
354
|
-
candidate_tiers=["
|
|
354
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
355
355
|
attempts=[
|
|
356
356
|
{"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
|
|
357
|
-
{"tier": "
|
|
357
|
+
{"tier": "Opus", "result": "unavailable"},
|
|
358
358
|
],
|
|
359
359
|
selected_tier=ADVISOR_MODEL_TIER,
|
|
360
360
|
is_astra_enabled=True,
|
|
@@ -366,12 +366,12 @@ def test_attempts_out_of_ladder_order_raises() -> None:
|
|
|
366
366
|
def test_selected_tier_not_first_spawned_attempt_raises() -> None:
|
|
367
367
|
run = ModelTierRun(
|
|
368
368
|
own_tier="Opus",
|
|
369
|
-
candidate_tiers=["
|
|
369
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
370
370
|
attempts=[
|
|
371
|
-
{"tier": "
|
|
371
|
+
{"tier": "Opus", "result": "unavailable"},
|
|
372
372
|
{"tier": ADVISOR_MODEL_TIER, "result": CODEX_BIND_SUCCESS_TOKEN},
|
|
373
373
|
],
|
|
374
|
-
selected_tier="
|
|
374
|
+
selected_tier="Opus",
|
|
375
375
|
is_astra_enabled=True,
|
|
376
376
|
)
|
|
377
377
|
with pytest.raises(
|
|
@@ -387,9 +387,9 @@ def test_selected_tier_not_first_spawned_attempt_raises() -> None:
|
|
|
387
387
|
def test_exhausted_walk_with_non_null_selected_tier_raises() -> None:
|
|
388
388
|
run = ModelTierRun(
|
|
389
389
|
own_tier="Opus",
|
|
390
|
-
candidate_tiers=["
|
|
391
|
-
attempts=[{"tier": "
|
|
392
|
-
selected_tier="
|
|
390
|
+
candidate_tiers=["Opus"],
|
|
391
|
+
attempts=[{"tier": "Opus", "result": "unavailable"}],
|
|
392
|
+
selected_tier="Opus",
|
|
393
393
|
fallback_reason="every candidate tier failed",
|
|
394
394
|
)
|
|
395
395
|
with pytest.raises(ModelTierRunError):
|
|
@@ -399,8 +399,8 @@ def test_exhausted_walk_with_non_null_selected_tier_raises() -> None:
|
|
|
399
399
|
def test_exhausted_walk_missing_fallback_reason_raises() -> None:
|
|
400
400
|
run = ModelTierRun(
|
|
401
401
|
own_tier="Opus",
|
|
402
|
-
candidate_tiers=["
|
|
403
|
-
attempts=[{"tier": "
|
|
402
|
+
candidate_tiers=["Opus"],
|
|
403
|
+
attempts=[{"tier": "Opus", "result": "unavailable"}],
|
|
404
404
|
selected_tier=None,
|
|
405
405
|
)
|
|
406
406
|
with pytest.raises(ModelTierRunError):
|
|
@@ -421,7 +421,7 @@ def test_unknown_own_tier_raises() -> None:
|
|
|
421
421
|
def test_empty_attempts_with_null_selected_tier_raises() -> None:
|
|
422
422
|
run = ModelTierRun(
|
|
423
423
|
own_tier="Opus",
|
|
424
|
-
candidate_tiers=["
|
|
424
|
+
candidate_tiers=["Opus"],
|
|
425
425
|
attempts=[],
|
|
426
426
|
selected_tier=None,
|
|
427
427
|
fallback_reason="skipped straight to CLI fallback",
|
|
@@ -433,10 +433,10 @@ def test_empty_attempts_with_null_selected_tier_raises() -> None:
|
|
|
433
433
|
def test_incomplete_fallback_walk_before_astra_raises() -> None:
|
|
434
434
|
run = ModelTierRun(
|
|
435
435
|
own_tier="Opus",
|
|
436
|
-
candidate_tiers=["
|
|
437
|
-
attempts=[{"tier": "
|
|
436
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
437
|
+
attempts=[{"tier": "Opus", "result": "unavailable"}],
|
|
438
438
|
selected_tier=None,
|
|
439
|
-
fallback_reason="stopped after
|
|
439
|
+
fallback_reason="stopped after Opus without trying Astra",
|
|
440
440
|
is_astra_enabled=True,
|
|
441
441
|
)
|
|
442
442
|
with pytest.raises(ModelTierRunError):
|
|
@@ -446,9 +446,9 @@ def test_incomplete_fallback_walk_before_astra_raises() -> None:
|
|
|
446
446
|
def test_lowercase_own_tier_and_candidates_pass() -> None:
|
|
447
447
|
run = ModelTierRun(
|
|
448
448
|
own_tier="opus",
|
|
449
|
-
candidate_tiers=["
|
|
450
|
-
attempts=[{"tier": "
|
|
451
|
-
selected_tier="
|
|
449
|
+
candidate_tiers=["opus"],
|
|
450
|
+
attempts=[{"tier": "opus", "result": "spawned"}],
|
|
451
|
+
selected_tier="opus",
|
|
452
452
|
)
|
|
453
453
|
assert validate_model_tier_run(run) is None
|
|
454
454
|
|
|
@@ -459,16 +459,16 @@ def test_cli_validates_json_log_file(tmp_path: Path) -> None:
|
|
|
459
459
|
json.dumps(
|
|
460
460
|
{
|
|
461
461
|
"own_tier": "Opus",
|
|
462
|
-
"candidate_tiers": ["
|
|
463
|
-
"attempts": [{"tier": "
|
|
464
|
-
"selected_tier": "
|
|
462
|
+
"candidate_tiers": ["Opus"],
|
|
463
|
+
"attempts": [{"tier": "Opus", "result": "spawned"}],
|
|
464
|
+
"selected_tier": "Opus",
|
|
465
465
|
}
|
|
466
466
|
),
|
|
467
467
|
encoding="utf-8",
|
|
468
468
|
)
|
|
469
469
|
assert main([str(log_path)]) == 0
|
|
470
470
|
loaded_run = load_model_tier_run_from_json_path(from_path=log_path)
|
|
471
|
-
assert loaded_run.selected_tier == "
|
|
471
|
+
assert loaded_run.selected_tier == "Opus"
|
|
472
472
|
assert loaded_run.host_profile == "Claude"
|
|
473
473
|
|
|
474
474
|
|
|
@@ -478,9 +478,9 @@ def test_cli_rejects_non_string_host_profile(tmp_path: Path) -> None:
|
|
|
478
478
|
json.dumps(
|
|
479
479
|
{
|
|
480
480
|
"own_tier": "Opus",
|
|
481
|
-
"candidate_tiers": ["
|
|
482
|
-
"attempts": [{"tier": "
|
|
483
|
-
"selected_tier": "
|
|
481
|
+
"candidate_tiers": ["Opus"],
|
|
482
|
+
"attempts": [{"tier": "Opus", "result": "spawned"}],
|
|
483
|
+
"selected_tier": "Opus",
|
|
484
484
|
"host_profile": 1,
|
|
485
485
|
}
|
|
486
486
|
),
|
|
@@ -495,9 +495,9 @@ def test_cli_rejects_non_boolean_astra_enabled(tmp_path: Path) -> None:
|
|
|
495
495
|
json.dumps(
|
|
496
496
|
{
|
|
497
497
|
"own_tier": "Opus",
|
|
498
|
-
"candidate_tiers": ["
|
|
499
|
-
"attempts": [{"tier": "
|
|
500
|
-
"selected_tier": "
|
|
498
|
+
"candidate_tiers": ["Opus"],
|
|
499
|
+
"attempts": [{"tier": "Opus", "result": "spawned"}],
|
|
500
|
+
"selected_tier": "Opus",
|
|
501
501
|
"astra_enabled": "false",
|
|
502
502
|
}
|
|
503
503
|
),
|
|
@@ -512,8 +512,8 @@ def test_cli_rejects_incomplete_fallback_log(tmp_path: Path) -> None:
|
|
|
512
512
|
json.dumps(
|
|
513
513
|
{
|
|
514
514
|
"own_tier": "Opus",
|
|
515
|
-
"candidate_tiers": ["
|
|
516
|
-
"attempts": [{"tier": "
|
|
515
|
+
"candidate_tiers": ["Opus", "Astra"],
|
|
516
|
+
"attempts": [{"tier": "Opus", "result": "unavailable"}],
|
|
517
517
|
"selected_tier": None,
|
|
518
518
|
"fallback_reason": "incomplete",
|
|
519
519
|
"astra_enabled": True,
|
|
@@ -531,9 +531,9 @@ def test_cli_loads_astra_enabled_fallback_walk(tmp_path: Path) -> None:
|
|
|
531
531
|
{
|
|
532
532
|
"own_tier": "ThirdParty",
|
|
533
533
|
"host_profile": "ThirdParty",
|
|
534
|
-
"candidate_tiers": ["
|
|
534
|
+
"candidate_tiers": ["Opus", "Astra"],
|
|
535
535
|
"attempts": [
|
|
536
|
-
{"tier": "
|
|
536
|
+
{"tier": "Opus", "result": "unavailable"},
|
|
537
537
|
{"tier": "Astra", "result": "codex"},
|
|
538
538
|
],
|
|
539
539
|
"selected_tier": "Astra",
|
|
@@ -552,12 +552,12 @@ def test_cli_missing_path_returns_usage_exit_code() -> None:
|
|
|
552
552
|
assert main([]) == 2
|
|
553
553
|
|
|
554
554
|
|
|
555
|
-
def
|
|
555
|
+
def test_cli_bind_at_opus_passes() -> None:
|
|
556
556
|
run = ModelTierRun(
|
|
557
557
|
own_tier="Opus",
|
|
558
|
-
candidate_tiers=["
|
|
559
|
-
attempts=[{"tier": "
|
|
560
|
-
selected_tier="
|
|
558
|
+
candidate_tiers=["Opus"],
|
|
559
|
+
attempts=[{"tier": "Opus", "result": "cli"}],
|
|
560
|
+
selected_tier="Opus",
|
|
561
561
|
)
|
|
562
562
|
assert validate_model_tier_run(run) is None
|
|
563
563
|
|
|
@@ -565,9 +565,9 @@ def test_cli_bind_at_fable_passes() -> None:
|
|
|
565
565
|
def test_cli_bind_fallthrough_to_opus_raises() -> None:
|
|
566
566
|
run = ModelTierRun(
|
|
567
567
|
own_tier="Opus",
|
|
568
|
-
candidate_tiers=["
|
|
568
|
+
candidate_tiers=["Opus", "Opus"],
|
|
569
569
|
attempts=[
|
|
570
|
-
{"tier": "
|
|
570
|
+
{"tier": "Opus", "result": "unavailable"},
|
|
571
571
|
{"tier": "Opus", "result": "cli"},
|
|
572
572
|
],
|
|
573
573
|
selected_tier="Opus",
|
|
@@ -576,12 +576,12 @@ def test_cli_bind_fallthrough_to_opus_raises() -> None:
|
|
|
576
576
|
validate_model_tier_run(run)
|
|
577
577
|
|
|
578
578
|
|
|
579
|
-
def
|
|
579
|
+
def test_third_party_own_tier_maps_to_opus_cli_bind_passes() -> None:
|
|
580
580
|
run = ModelTierRun(
|
|
581
581
|
own_tier="ThirdParty",
|
|
582
|
-
candidate_tiers=["
|
|
583
|
-
attempts=[{"tier": "
|
|
584
|
-
selected_tier="
|
|
582
|
+
candidate_tiers=["Opus"],
|
|
583
|
+
attempts=[{"tier": "Opus", "result": "cli"}],
|
|
584
|
+
selected_tier="Opus",
|
|
585
585
|
)
|
|
586
586
|
assert validate_model_tier_run(run) is None
|
|
587
587
|
|
|
@@ -589,9 +589,9 @@ def test_third_party_own_tier_maps_to_fable_cli_bind_passes() -> None:
|
|
|
589
589
|
def test_third_party_own_tier_lowercase_cli_bind_passes() -> None:
|
|
590
590
|
run = ModelTierRun(
|
|
591
591
|
own_tier="thirdparty",
|
|
592
|
-
candidate_tiers=["
|
|
593
|
-
attempts=[{"tier": "
|
|
594
|
-
selected_tier="
|
|
592
|
+
candidate_tiers=["opus"],
|
|
593
|
+
attempts=[{"tier": "opus", "result": "cli"}],
|
|
594
|
+
selected_tier="opus",
|
|
595
595
|
)
|
|
596
596
|
assert validate_model_tier_run(run) is None
|
|
597
597
|
|
|
@@ -599,9 +599,9 @@ def test_third_party_own_tier_lowercase_cli_bind_passes() -> None:
|
|
|
599
599
|
def test_self_token_is_not_bind_success_raises() -> None:
|
|
600
600
|
run = ModelTierRun(
|
|
601
601
|
own_tier="Opus",
|
|
602
|
-
candidate_tiers=["
|
|
603
|
-
attempts=[{"tier": "
|
|
604
|
-
selected_tier="
|
|
602
|
+
candidate_tiers=["Opus"],
|
|
603
|
+
attempts=[{"tier": "Opus", "result": "self"}],
|
|
604
|
+
selected_tier="Opus",
|
|
605
605
|
)
|
|
606
606
|
with pytest.raises(ModelTierRunError):
|
|
607
607
|
validate_model_tier_run(run)
|
|
@@ -610,9 +610,9 @@ def test_self_token_is_not_bind_success_raises() -> None:
|
|
|
610
610
|
def test_third_party_self_token_is_not_bind_success_raises() -> None:
|
|
611
611
|
run = ModelTierRun(
|
|
612
612
|
own_tier="ThirdParty",
|
|
613
|
-
candidate_tiers=["
|
|
614
|
-
attempts=[{"tier": "
|
|
615
|
-
selected_tier="
|
|
613
|
+
candidate_tiers=["Opus"],
|
|
614
|
+
attempts=[{"tier": "Opus", "result": "self"}],
|
|
615
|
+
selected_tier="Opus",
|
|
616
616
|
)
|
|
617
617
|
with pytest.raises(ModelTierRunError):
|
|
618
618
|
validate_model_tier_run(run)
|
|
@@ -632,8 +632,8 @@ def test_third_party_host_legacy_single_tier_self_bind_raises() -> None:
|
|
|
632
632
|
def test_third_party_cli_exhausted_fail_closed_passes() -> None:
|
|
633
633
|
run = ModelTierRun(
|
|
634
634
|
own_tier="ThirdParty",
|
|
635
|
-
candidate_tiers=["
|
|
636
|
-
attempts=[{"tier": "
|
|
635
|
+
candidate_tiers=["Opus"],
|
|
636
|
+
attempts=[{"tier": "Opus", "result": "unavailable"}],
|
|
637
637
|
selected_tier=None,
|
|
638
638
|
fallback_reason=(
|
|
639
639
|
"third-party host CLI Claude-chain exhausted; fail closed"
|
|
@@ -645,8 +645,8 @@ def test_third_party_cli_exhausted_fail_closed_passes() -> None:
|
|
|
645
645
|
def test_third_party_cli_exhausted_without_fallback_reason_raises() -> None:
|
|
646
646
|
run = ModelTierRun(
|
|
647
647
|
own_tier="ThirdParty",
|
|
648
|
-
candidate_tiers=["
|
|
649
|
-
attempts=[{"tier": "
|
|
648
|
+
candidate_tiers=["Opus"],
|
|
649
|
+
attempts=[{"tier": "Opus", "result": "unavailable"}],
|
|
650
650
|
selected_tier=None,
|
|
651
651
|
)
|
|
652
652
|
with pytest.raises(ModelTierRunError):
|
|
@@ -656,9 +656,9 @@ def test_third_party_cli_exhausted_without_fallback_reason_raises() -> None:
|
|
|
656
656
|
def test_third_party_cli_selected_tier_mismatch_raises() -> None:
|
|
657
657
|
run = ModelTierRun(
|
|
658
658
|
own_tier="ThirdParty",
|
|
659
|
-
candidate_tiers=["
|
|
660
|
-
attempts=[{"tier": "
|
|
661
|
-
selected_tier="
|
|
659
|
+
candidate_tiers=["Opus"],
|
|
660
|
+
attempts=[{"tier": "Opus", "result": "cli"}],
|
|
661
|
+
selected_tier="Sonnet",
|
|
662
662
|
)
|
|
663
663
|
with pytest.raises(ModelTierRunError):
|
|
664
664
|
validate_model_tier_run(run)
|
|
@@ -667,9 +667,9 @@ def test_third_party_cli_selected_tier_mismatch_raises() -> None:
|
|
|
667
667
|
def test_claude_host_self_token_is_not_spawn_success_raises() -> None:
|
|
668
668
|
run = ModelTierRun(
|
|
669
669
|
own_tier="Opus",
|
|
670
|
-
candidate_tiers=["
|
|
671
|
-
attempts=[{"tier": "
|
|
672
|
-
selected_tier="
|
|
670
|
+
candidate_tiers=["Opus"],
|
|
671
|
+
attempts=[{"tier": "Opus", "result": "self"}],
|
|
672
|
+
selected_tier="Opus",
|
|
673
673
|
)
|
|
674
674
|
with pytest.raises(ModelTierRunError):
|
|
675
675
|
validate_model_tier_run(run)
|
|
@@ -699,10 +699,10 @@ def test_codex_host_astra_codex_token_counts_as_success() -> None:
|
|
|
699
699
|
assert validate_model_tier_run(run) is None
|
|
700
700
|
|
|
701
701
|
|
|
702
|
-
def
|
|
702
|
+
def test_codex_host_opus_then_astra_walk_raises() -> None:
|
|
703
703
|
run = ModelTierRun(
|
|
704
704
|
own_tier="Opus",
|
|
705
|
-
candidate_tiers=["
|
|
705
|
+
candidate_tiers=["Opus", ADVISOR_MODEL_TIER],
|
|
706
706
|
attempts=[{"tier": ADVISOR_MODEL_TIER, "result": "spawned"}],
|
|
707
707
|
selected_tier=ADVISOR_MODEL_TIER,
|
|
708
708
|
is_astra_enabled=True,
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import { strict as assert } from 'node:assert';
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
import { mergeHooksIntoSettings } from './install.mjs';
|
|
6
|
+
|
|
7
|
+
test('reinstall replaces both prompt hooks with one ordered context hook', () => {
|
|
8
|
+
const hooksConfig = JSON.parse(readFileSync(new URL('../hooks/hooks.json', import.meta.url), 'utf8'));
|
|
9
|
+
const userCommand = 'python C:/Users/example/hooks/user_hook.py';
|
|
10
|
+
const settings = {
|
|
11
|
+
hooks: {
|
|
12
|
+
UserPromptSubmit: [
|
|
13
|
+
{
|
|
14
|
+
matcher: '',
|
|
15
|
+
hooks: [
|
|
16
|
+
{ type: 'command', command: userCommand },
|
|
17
|
+
{
|
|
18
|
+
type: 'command',
|
|
19
|
+
command: 'python C:/Users/example/.claude/hooks/session/style_reminder_prompt.py',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
type: 'command',
|
|
23
|
+
command: 'python C:/Users/example/.claude/hooks/session/skill_loaded_reminder.py',
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
],
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
mergeHooksIntoSettings(settings, hooksConfig, 'C:/Users/example/.claude', 'python');
|
|
32
|
+
|
|
33
|
+
const userPromptHooks = settings.hooks.UserPromptSubmit.flatMap(eachGroup => eachGroup.hooks);
|
|
34
|
+
assert.equal(userPromptHooks.length, 2);
|
|
35
|
+
assert.equal(userPromptHooks[0].command, userCommand);
|
|
36
|
+
assert.match(userPromptHooks[1].command, /style_reminder_prompt\.py --include-skill-reminder$/);
|
|
37
|
+
assert.doesNotMatch(userPromptHooks[1].command, /skill_loaded_reminder/);
|
|
38
|
+
|
|
39
|
+
const firstMerge = JSON.stringify(settings);
|
|
40
|
+
mergeHooksIntoSettings(settings, hooksConfig, 'C:/Users/example/.claude', 'python');
|
|
41
|
+
assert.equal(JSON.stringify(settings), firstMerge);
|
|
42
|
+
});
|
package/docs/DJANGO_PATTERNS.md
CHANGED
|
@@ -35,7 +35,7 @@
|
|
|
35
35
|
|
|
36
36
|
## Production Migrations (Post-Launch ONLY)
|
|
37
37
|
|
|
38
|
-
|
|
38
|
+
After launch, keep model changes backwards-compatible.
|
|
39
39
|
|
|
40
40
|
**Why:** Manual migration takes 2+ minutes. New code runs against old schema during this window.
|
|
41
41
|
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
|
|
60
60
|
## API Contract Changes (Post-Launch)
|
|
61
61
|
|
|
62
|
-
|
|
62
|
+
After launch, keep API contract changes backwards-compatible.
|
|
63
63
|
|
|
64
64
|
**Why:** Users may have old client code cached. Old clients must work with new API.
|
|
65
65
|
|
package/docs/TEST_QUALITY.md
CHANGED
|
@@ -4,19 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
## Test Infrastructure Anti-Patterns
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
**ALWAYS:**
|
|
10
|
-
- Single file
|
|
11
|
-
- Simple functions
|
|
12
|
-
- Minimal abstractions
|
|
13
|
-
- Pragmatic approach
|
|
14
|
-
|
|
15
|
-
**NEVER:**
|
|
16
|
-
- Multi-file packages
|
|
17
|
-
- Cache classes
|
|
18
|
-
- Abstractions "for future"
|
|
19
|
-
- Rigid constraints
|
|
7
|
+
Test helpers drift toward over-engineering faster than production code, because nothing reviews them for size. Keep a helper to one file of plain functions with the fewest abstractions the current tests need. Add a package, a cache class, or an abstraction only when a second test needs it today.
|
|
20
8
|
|
|
21
9
|
**Pre-check (MANDATORY):**
|
|
22
10
|
- [ ] ONE file?
|
|
@@ -10,6 +10,10 @@ keeps its own sign-in and history.
|
|
|
10
10
|
|---|---|
|
|
11
11
|
| `scripts/claude_account_profile.py` | Links each shared entry of `~/.claude` into the profile `~/.claude-profiles/ev`, moves stale copies into `.replaced/<time>/`, and writes the `claude-ev.cmd` launcher into `~/.local/bin` |
|
|
12
12
|
| `scripts/claude_account_choice.py` | Reads both accounts' 5-hour and weekly meters and prints which account a job runs on |
|
|
13
|
+
| `scripts/claude_account_worker.py` | Runs one headless Claude worker using the account chosen by the picker |
|
|
14
|
+
| `scripts/claude_account_worker_process.py` | Launches the worker process, feeds it the brief, and kills it on timeout |
|
|
15
|
+
| `scripts/claude_account_worker_report.py` | Builds and writes the JSON report a worker leaves behind |
|
|
16
|
+
| `scripts/dev_env_scripts_constants/claude_account_worker_constants.py` | The worker's flag names, defaults, exit codes, and report keys |
|
|
13
17
|
| `scripts/dev_env_scripts_constants/claude_account_constants.py` | The profile name, the entries that stay per account, and the picker thresholds |
|
|
14
18
|
|
|
15
19
|
The launcher sets `CLAUDE_CONFIG_DIR` to the profile and passes every argument to
|
package/hooks/hooks.json
CHANGED
|
@@ -69,12 +69,7 @@
|
|
|
69
69
|
"hooks": [
|
|
70
70
|
{
|
|
71
71
|
"type": "command",
|
|
72
|
-
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/style_reminder_prompt.py",
|
|
73
|
-
"timeout": 10
|
|
74
|
-
},
|
|
75
|
-
{
|
|
76
|
-
"type": "command",
|
|
77
|
-
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/skill_loaded_reminder.py",
|
|
72
|
+
"command": "python3 ${CLAUDE_PLUGIN_ROOT}/hooks/session/style_reminder_prompt.py --include-skill-reminder",
|
|
78
73
|
"timeout": 10
|
|
79
74
|
}
|
|
80
75
|
]
|
|
@@ -12,8 +12,8 @@
|
|
|
12
12
|
the model sees the reminder this turn, and each turn after
|
|
13
13
|
|
|
14
14
|
Claude Code and Codex CLI both read the same ``additionalContext`` shape on
|
|
15
|
-
their ``UserPromptSubmit`` event.
|
|
16
|
-
|
|
15
|
+
their ``UserPromptSubmit`` event. The Claude hook includes the skill reminder
|
|
16
|
+
when its flag is present. The unflagged Codex hook prints style alone.
|
|
17
17
|
"""
|
|
18
18
|
|
|
19
19
|
from __future__ import annotations
|
|
@@ -23,15 +23,29 @@ import sys
|
|
|
23
23
|
|
|
24
24
|
import _path_setup # noqa: F401
|
|
25
25
|
|
|
26
|
+
from hooks_constants.pre_tool_use_stdin import read_hook_input_dictionary_from_stdin
|
|
26
27
|
from hooks_constants.style_reminder_prompt_constants import STYLE_REMINDER_PROMPT
|
|
28
|
+
from skill_loaded_reminder import reminder_for
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _additional_context_for_prompt() -> str:
|
|
32
|
+
if "--include-skill-reminder" not in sys.argv[1:]:
|
|
33
|
+
return STYLE_REMINDER_PROMPT
|
|
34
|
+
hook_input = read_hook_input_dictionary_from_stdin()
|
|
35
|
+
if hook_input is None:
|
|
36
|
+
return STYLE_REMINDER_PROMPT
|
|
37
|
+
skill_reminder = reminder_for(hook_input)
|
|
38
|
+
if skill_reminder is None:
|
|
39
|
+
return STYLE_REMINDER_PROMPT
|
|
40
|
+
return STYLE_REMINDER_PROMPT + "\n" + skill_reminder
|
|
27
41
|
|
|
28
42
|
|
|
29
43
|
def main() -> None:
|
|
30
|
-
"""Print
|
|
44
|
+
"""Print ordered UserPromptSubmit additionalContext."""
|
|
31
45
|
payload = {
|
|
32
46
|
"hookSpecificOutput": {
|
|
33
47
|
"hookEventName": "UserPromptSubmit",
|
|
34
|
-
"additionalContext":
|
|
48
|
+
"additionalContext": _additional_context_for_prompt(),
|
|
35
49
|
}
|
|
36
50
|
}
|
|
37
51
|
sys.stdout.write(json.dumps(payload) + "\n")
|