claude-dev-env 2.9.0 → 2.10.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/pr-loop/CLAUDE.md +1 -1
- package/_shared/pr-loop/audit-contract.md +17 -6
- package/_shared/pr-loop/audit-reply-template.md +4 -4
- package/_shared/pr-loop/code-rules-gate.md +3 -5
- package/_shared/pr-loop/fix-protocol.md +2 -3
- package/_shared/pr-loop/gh-payloads.md +1 -1
- package/_shared/pr-loop/scripts/CLAUDE.md +1 -1
- package/_shared/pr-loop/scripts/README.md +1 -1
- package/_shared/pr-loop/scripts/code_rules_gate.py +2 -0
- package/_shared/pr-loop/scripts/code_rules_gate_parts/gate_running.py +16 -1
- package/_shared/pr-loop/scripts/code_rules_gate_parts/git_blob_readers.py +11 -5
- package/_shared/pr-loop/scripts/preflight.py +9 -4
- package/_shared/pr-loop/scripts/reviews_disabled.py +50 -22
- package/_shared/pr-loop/scripts/tests/conftest.py +20 -0
- package/_shared/pr-loop/scripts/tests/test_claude_permissions_common.py +6 -6
- package/_shared/pr-loop/scripts/tests/test_reviews_disabled.py +50 -6
- package/_shared/pr-loop/scripts/tests/test_revoke_project_claude_permissions.py +1 -1
- package/_shared/pr-loop/state-schema.md +5 -14
- package/agents/CLAUDE.md +2 -2
- package/agents/clean-coder.md +58 -548
- package/agents/code-quality-agent.md +10 -2
- package/agents/code-verifier.md +1 -1
- package/agents/test_agent_frontmatter.py +32 -40
- package/audit-rubrics/CLAUDE.md +2 -1
- package/audit-rubrics/audit-categories.json +704 -0
- package/audit-rubrics/prompts/category-i-concurrency.md +1 -1
- package/bin/CLAUDE.md +16 -5
- package/bin/ever-shipped-skills.mjs +2 -0
- package/bin/install-plan.mjs +402 -0
- package/bin/install-transaction.mjs +455 -0
- package/bin/install.mjs +593 -147
- package/bin/install.plan.test.mjs +194 -0
- package/bin/install.profile-root.test.mjs +154 -0
- package/bin/install.profiles.test.mjs +253 -0
- package/bin/install.settings-defaults.test.mjs +200 -0
- package/bin/install.transaction.test.mjs +400 -0
- package/bin/install.uninstall-transaction.test.mjs +418 -0
- package/bin/merge_managed_permissions.mjs +130 -0
- package/bin/resolve-install-root.mjs +181 -0
- package/bin/select-install-targets.mjs +401 -0
- package/commands/CLAUDE.md +0 -2
- package/docs/references/CLAUDE.md +1 -0
- package/docs/references/advisor-tool.md +1 -1
- package/docs/references/prose-style-enforcement.md +25 -0
- package/hooks/blocking/CLAUDE.md +6 -6
- package/hooks/blocking/_path_setup.py +9 -5
- package/hooks/blocking/code_rules_docstrings.py +124 -30
- package/hooks/blocking/code_rules_enforcer.py +161 -16
- package/hooks/blocking/code_rules_shared.py +40 -23
- package/hooks/blocking/config/CLAUDE.md +3 -5
- package/hooks/blocking/config/prose_style_enforcement_constants.py +38 -0
- package/hooks/blocking/config/test_prose_style_enforcement_constants.py +45 -0
- package/hooks/blocking/eli11_reply_enforcer.py +70 -113
- package/hooks/blocking/hedging_language_blocker.py +103 -20
- package/hooks/blocking/hook_prose_detector_consistency.py +6 -0
- package/hooks/blocking/intent_only_ending_blocker.py +6 -0
- package/hooks/blocking/plain_language_blocker.py +139 -20
- package/hooks/blocking/pre_tool_use_dispatcher.py +102 -20
- package/hooks/blocking/state_description_blocker.py +7 -1
- package/hooks/blocking/tdd_enforcer.py +8 -0
- package/hooks/blocking/test__path_setup.py +28 -0
- package/hooks/blocking/test_code_rules_enforcer_agent_home_tooling.py +99 -0
- package/hooks/blocking/test_code_rules_enforcer_docstring_args_span_scope.py +232 -10
- package/hooks/blocking/test_code_rules_enforcer_ephemeral.py +1 -1
- package/hooks/blocking/test_code_rules_enforcer_join_separator_magic.py +41 -0
- package/hooks/blocking/test_code_rules_enforcer_string_magic.py +98 -0
- package/hooks/blocking/test_eli11_reply_enforcer.py +98 -165
- package/hooks/blocking/test_hedging_language_blocker.py +120 -1
- package/hooks/blocking/test_hook_prose_detector_consistency.py +28 -8
- package/hooks/blocking/test_intent_only_ending_blocker.py +27 -2
- package/hooks/blocking/test_package_inventory_stale_blocker.py +11 -4
- package/hooks/blocking/test_plain_language_blocker.py +129 -19
- package/hooks/blocking/test_plain_language_blocker_allowlist.py +70 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher.py +99 -26
- package/hooks/blocking/test_pre_tool_use_dispatcher_native.py +87 -50
- package/hooks/blocking/test_state_description_blocker.py +45 -2
- package/hooks/blocking/test_stop_dispatcher.py +11 -7
- package/hooks/blocking/test_volatile_path_in_post_blocker.py +12 -12
- package/hooks/blocking/volatile_path_in_post_blocker.py +2 -2
- package/hooks/hooks.json +15 -0
- package/hooks/hooks_constants/CLAUDE.md +14 -3
- package/hooks/hooks_constants/ask_user_question_shape.py +281 -0
- package/hooks/hooks_constants/code_rules_enforcer_constants.py +2 -1
- package/hooks/hooks_constants/eli11_reply_enforcer_constants.py +5 -12
- package/hooks/hooks_constants/hedging_uncertainty_constants.py +42 -0
- package/hooks/hooks_constants/issue_tracker_session_starter_constants.py +23 -0
- package/hooks/hooks_constants/orchestrator_auto_starter_constants.py +23 -0
- package/hooks/hooks_constants/piped_pytest_blocker_constants.py +4 -1
- package/hooks/hooks_constants/plain_language_blocker_constants.py +4 -1
- package/hooks/hooks_constants/pre_tool_use_dispatcher_constants.py +6 -0
- package/hooks/hooks_constants/project_paths_reader.py +31 -4
- package/hooks/hooks_constants/prose_matcher_precision_constants.py +40 -0
- package/hooks/hooks_constants/pytest_invocation.py +354 -0
- package/hooks/hooks_constants/session_start_injector.py +163 -0
- package/hooks/hooks_constants/session_start_injector_constants.py +46 -0
- package/hooks/hooks_constants/shell_command_pipeline.py +397 -0
- package/hooks/hooks_constants/shell_command_segments.py +5 -0
- package/hooks/hooks_constants/test_ask_user_question_shape.py +167 -0
- package/hooks/hooks_constants/test_project_paths_reader.py +29 -0
- package/hooks/hooks_constants/test_prose_metrics_parity.py +8 -0
- package/hooks/hooks_constants/test_pytest_invocation.py +130 -0
- package/hooks/hooks_constants/test_session_start_injector.py +168 -0
- package/hooks/hooks_constants/test_shell_command_pipeline.py +135 -0
- package/hooks/hooks_constants/volatile_path_in_post_blocker_constants.py +1 -1
- package/hooks/hooks_constants/working_style_prompt_constants.py +30 -0
- package/hooks/observability/CLAUDE.md +2 -0
- package/hooks/observability/prose_matcher_advisory.py +237 -0
- package/hooks/observability/test_prose_matcher_advisory.py +143 -0
- package/hooks/session/CLAUDE.md +9 -1
- package/hooks/session/_path_setup.py +13 -0
- package/hooks/session/issue_tracker_session_starter.py +135 -0
- package/hooks/session/orchestrator_auto_starter.py +100 -0
- package/hooks/session/test__path_setup.py +28 -0
- package/hooks/session/test_issue_tracker_session_starter.py +104 -0
- package/hooks/session/test_orchestrator_auto_starter.py +99 -0
- package/hooks/session/test_working_style_prompt.py +47 -0
- package/hooks/session/untracked_repo_detector.py +1 -24
- package/hooks/session/working_style_prompt.py +36 -0
- package/hooks/validators/_path_setup.py +19 -0
- package/hooks/validators/run_all_validators.py +8 -13
- package/installable-surfaces.manifest.json +21 -0
- package/output-styles/CLAUDE.md +1 -3
- package/package.json +4 -2
- package/rules/CLAUDE.md +1 -0
- package/rules/durable-post-artifacts.md +2 -2
- package/rules/eli11-replies.md +6 -1
- package/rules/hedging-claims.md +4 -2
- package/rules/long-horizon-autonomy.md +3 -1
- package/rules/opus5-communication-contract.md +45 -0
- package/rules/plain-language.md +2 -2
- package/rules/research-mode.md +1 -1
- package/scripts/CLAUDE.md +11 -0
- package/scripts/Sync-RepoMain.ps1 +215 -0
- package/scripts/active_capability_references.py +218 -0
- package/scripts/ci/windows-installer-lifecycle.ps1 +78 -0
- package/scripts/claude_chain_runner.py +394 -6
- package/scripts/claude_chain_usage.py +1 -1
- package/scripts/codex_compat_materializer.py +105 -85
- package/scripts/dev_env_scripts_constants/CLAUDE.md +2 -0
- package/scripts/dev_env_scripts_constants/active_capability_constants.py +46 -0
- package/scripts/dev_env_scripts_constants/claude_chain_constants.py +74 -0
- package/scripts/dev_env_scripts_constants/verify_installable_package_constants.py +116 -0
- package/scripts/profile-isolation-launchers/config/mcp-bundles.json +25 -0
- package/scripts/profile-isolation-launchers/config/profile-isolation-constants.mjs +60 -0
- package/scripts/profile-isolation-launchers/config/profiles.manifest.json +54 -0
- package/scripts/profile-isolation-launchers/config/shared-allowlist.json +64 -0
- package/scripts/profile-isolation-launchers/launcher-runtime.mjs +180 -0
- package/scripts/profile-isolation-launchers/lib/profile-manifest.mjs +288 -0
- package/scripts/profile-isolation-launchers/mcp-bundles.mjs +275 -0
- package/scripts/profile-isolation-launchers/profile-isolation-contract.test.mjs +221 -0
- package/scripts/profile-isolation-launchers/tests/launcher-runtime.test.mjs +108 -0
- package/scripts/profile-isolation-launchers/tests/mcp-bundles.test.mjs +147 -0
- package/scripts/profile-isolation-launchers/tests/shortcut-contract.test.ps1 +102 -0
- package/scripts/profile-isolation-launchers/tests/version-compatibility.test.mjs +210 -0
- package/scripts/profile-isolation-launchers/version-compatibility.mjs +299 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-inventory.ps1 +127 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-manifest.json +51 -0
- package/scripts/profile-isolation-launchers/windows/shortcut-reconcile.ps1 +77 -0
- package/scripts/spawn_grok_batch.py +3 -0
- package/scripts/test_active_capability_references.py +108 -0
- package/scripts/test_claude_chain_runner.py +414 -82
- package/scripts/test_claude_chain_usage.py +12 -12
- package/scripts/test_resolve_worker_spawn.py +2 -2
- package/scripts/test_verify_installable_package.py +208 -0
- package/scripts/tests/test_codex_compat_materializer.py +33 -0
- package/scripts/verify_installable_package.py +612 -0
- package/settings.json +10 -0
- package/skills/CLAUDE.md +2 -0
- package/skills/_shared/pr-loop/scripts/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/audit_category_schema.py +355 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/CLAUDE.md +1 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/audit_category_schema_constants.py +32 -0
- package/skills/_shared/pr-loop/scripts/skills_pr_loop_constants/path_resolver_constants.py +7 -19
- package/skills/_shared/pr-loop/scripts/test_audit_category_schema.py +94 -0
- package/skills/_shared/pr-loop/scripts/test_build_audit_prompt.py +21 -0
- package/skills/autoconverge/reference/convergence.md +2 -1
- package/skills/autoconverge/reference/stop-conditions.md +5 -3
- package/skills/beat-sheet/SKILL.md +54 -0
- package/skills/beat-sheet/reference/visual-beats.md +29 -0
- package/skills/bugteam/CONSTRAINTS.md +4 -4
- package/skills/bugteam/EXAMPLES.md +1 -1
- package/skills/bugteam/reference/README.md +1 -1
- package/skills/e-code-review/SKILL.md +26 -5
- package/skills/e-code-review/reference/effort-evaluation.md +35 -0
- package/skills/e-code-review/reference/medium.md +15 -4
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/__init__.py +41 -0
- package/skills/e-code-review/scripts/config/e_code_review_effort_constants/effort_constants.py +40 -0
- package/skills/e-code-review/scripts/e_code_review_scripts_constants/finding_pipeline_constants.py +49 -0
- package/skills/e-code-review/scripts/effort_defaults_evidence.json +186 -0
- package/skills/e-code-review/scripts/effort_evaluation.py +362 -0
- package/skills/e-code-review/scripts/finding_pipeline.py +140 -0
- package/skills/e-code-review/scripts/fixtures/demanding.json +26 -0
- package/skills/e-code-review/scripts/fixtures/easy.json +14 -0
- package/skills/e-code-review/scripts/fixtures/medium.json +20 -0
- package/skills/e-code-review/scripts/grok_code_review.py +16 -7
- package/skills/e-code-review/scripts/test_effort_evaluation.py +180 -0
- package/skills/e-code-review/scripts/test_finding_pipeline.py +197 -0
- package/skills/e-code-review/scripts/test_grok_code_review.py +77 -0
- package/skills/plan-to-pr/scripts/create_packet.py +4 -4
- package/skills/plan-to-pr/scripts/load_skill_constants.py +41 -0
- package/skills/plan-to-pr/scripts/validate_packet.py +4 -4
- package/skills/plan-to-pr/scripts/validate_protocol.py +4 -1
- package/skills/plan-to-pr/scripts/validate_run.py +4 -1
- package/skills/pr-converge/scripts/check_convergence.py +21 -19
- package/skills/pr-converge/scripts/check_convergence_availability.py +50 -7
- package/skills/pr-converge/scripts/conftest.py +35 -0
- package/skills/pr-converge/scripts/test_check_convergence_availability.py +65 -0
- package/skills/pr-converge/scripts/test_check_convergence_codex.py +11 -1
- package/skills/pr-converge/scripts/test_check_convergence_contract.py +9 -2
- package/skills/pr-loop-cloud-transport/SKILL.md +1 -1
- package/skills/rebase/SKILL.md +15 -3
- package/skills/reviewer-gates/SKILL.md +2 -2
- package/skills/show/SKILL.md +51 -0
- package/skills/show/references/accessibility.md +7 -0
- package/skills/show/references/art.md +3 -0
- package/skills/show/references/charts.md +3 -0
- package/skills/show/references/core-design.md +14 -0
- package/skills/show/references/erds.md +3 -0
- package/skills/show/references/flowcharts.md +3 -0
- package/skills/show/references/host-and-html.md +3 -0
- package/skills/show/references/illustrative-diagrams.md +10 -0
- package/skills/show/references/interaction.md +3 -0
- package/skills/show/references/mockups.md +3 -0
- package/skills/show/references/quality-gates.md +7 -0
- package/skills/show/references/structural-diagrams.md +3 -0
- package/skills/show/references/subject-inventory.md +21 -0
- package/skills/show/references/svg-contract.md +22 -0
- package/skills/show/routing.yaml +30 -0
- package/skills/show/samples/pr1262-v2.svg +222 -0
- package/skills/show/scripts/README.md +6 -0
- package/skills/show/scripts/validate-artifact.py +91 -0
- package/skills/show/scripts/validate-package.py +18 -0
- package/skills/show/templates/html-widget.html +4 -0
- package/skills/show/templates/svg-base.svg +19 -0
- package/skills/show/tests/fixtures/css-var.svg +6 -0
- package/skills/show/tests/fixtures/dead-ref.svg +7 -0
- package/skills/show/tests/fixtures/filled-glyph.svg +8 -0
- package/skills/show/tests/fixtures/inherited-fill.svg +18 -0
- package/skills/show/tests/fixtures/invalid.svg +1 -0
- package/skills/show/tests/fixtures/large-canvas.svg +21 -0
- package/skills/show/tests/fixtures/unfilled-connector.svg +15 -0
- package/skills/show/tests/fixtures/valid.html +1 -0
- package/skills/show/tests/test_validate-artifact.py +74 -0
- package/skills/show/tests/test_validators.py +59 -0
- package/skills/show/workflows/create-visual.md +13 -0
- package/skills/show/workflows/review-visual.md +20 -0
- package/skills/split-pr/SKILL.md +85 -0
- package/skills/split-pr/reference/path-layers.md +16 -0
- package/skills/split-pr/reference/proposal-format.md +15 -0
- package/skills/split-pr/reference/split-further-loop.md +10 -0
- package/skills/split-pr/reference/splitting-principles.md +26 -0
- package/skills/split-pr/scripts/analyze_pr.py +279 -0
- package/skills/split-pr/scripts/categorize_files.py +106 -0
- package/skills/split-pr/scripts/config/__init__.py +1 -0
- package/skills/split-pr/scripts/config/dependency_constants.py +14 -0
- package/skills/split-pr/scripts/config/git_operations_constants.py +36 -0
- package/skills/split-pr/scripts/config/packing_constants.py +61 -0
- package/skills/split-pr/scripts/config/plan_constants.py +49 -0
- package/skills/split-pr/scripts/config/split_pr_constants.py +110 -0
- package/skills/split-pr/scripts/execute_split_slices.py +82 -0
- package/skills/split-pr/scripts/pack_files_into_slices.py +212 -0
- package/skills/split-pr/scripts/split_pr_dependency_graph.py +70 -0
- package/skills/split-pr/scripts/split_pr_git_operations.py +184 -0
- package/skills/split-pr/scripts/split_pr_layer_order.py +58 -0
- package/skills/split-pr/scripts/split_pr_paginate.py +119 -0
- package/skills/split-pr/scripts/split_pr_process_runner.py +52 -0
- package/skills/split-pr/scripts/split_pr_script_types.py +126 -0
- package/skills/split-pr/scripts/split_pr_title.py +41 -0
- package/skills/split-pr/scripts/test_analyze_pr.py +228 -0
- package/skills/split-pr/scripts/test_categorize_files.py +55 -0
- package/skills/split-pr/scripts/test_categorize_files_packing.py +59 -0
- package/skills/split-pr/scripts/test_execute_split_slices.py +99 -0
- package/skills/split-pr/scripts/test_split_pr_dependency_graph.py +47 -0
- package/skills/split-pr/scripts/test_split_pr_git_operations.py +125 -0
- package/skills/split-pr/scripts/test_split_pr_layer_order.py +36 -0
- package/skills/split-pr/scripts/test_split_pr_paginate.py +65 -0
- package/skills/split-pr/scripts/test_split_pr_script_types.py +73 -0
- package/skills/split-pr/scripts/test_split_pr_title.py +28 -0
- package/skills/split-pr/scripts/test_verify_dependency_graph.py +46 -0
- package/skills/split-pr/scripts/test_verify_plan.py +56 -0
- package/skills/split-pr/scripts/test_verify_plan_contract.py +50 -0
- package/skills/split-pr/scripts/test_verify_plan_path_normalization.py +45 -0
- package/skills/split-pr/scripts/verify_dependency_graph.py +111 -0
- package/skills/split-pr/scripts/verify_plan.py +139 -0
- package/system-prompts/software-engineer.xml +11 -2
- package/commands/initialize.md +0 -90
- package/commands/stubcheck.md +0 -88
- package/output-styles/caveman-agent.md +0 -37
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
import argparse
|
|
6
|
-
import ast
|
|
7
6
|
import hashlib
|
|
8
7
|
import json
|
|
9
8
|
import os
|
|
@@ -15,6 +14,8 @@ from dataclasses import dataclass, field
|
|
|
15
14
|
from pathlib import Path
|
|
16
15
|
from typing import Callable, Iterable
|
|
17
16
|
|
|
17
|
+
import yaml
|
|
18
|
+
|
|
18
19
|
|
|
19
20
|
ManagedContent = str | bytes
|
|
20
21
|
|
|
@@ -24,7 +25,6 @@ reparse_point_attribute_name = "FILE_ATTRIBUTE_REPARSE_POINT"
|
|
|
24
25
|
manifest_indentation_width = 2
|
|
25
26
|
publish_plan_max_positional_arguments = 3
|
|
26
27
|
publish_plan_failure_injector_position = 2
|
|
27
|
-
frontmatter_required_fields = ("name", "description")
|
|
28
28
|
frontmatter_unsupported_fields = ("tools", "model", "color")
|
|
29
29
|
full_prune_opt_in_flag = "--allow-prune-all"
|
|
30
30
|
unreadable_source_root_message = (
|
|
@@ -259,73 +259,67 @@ def validate_target_path(target_root: Path, relative_path: str) -> Path:
|
|
|
259
259
|
return _validate_containment(root, candidate)
|
|
260
260
|
|
|
261
261
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
if
|
|
305
|
-
raise MaterializerError("
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
if
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
if any(character in entry for character in "[]{}:"):
|
|
320
|
-
raise MaterializerError("malformed frontmatter value")
|
|
321
|
-
return entry
|
|
322
|
-
if not isinstance(parsed, str):
|
|
323
|
-
raise MaterializerError("frontmatter list entries must be strings")
|
|
324
|
-
return parsed
|
|
262
|
+
class _UniqueKeySafeLoader(yaml.SafeLoader):
|
|
263
|
+
"""SafeLoader that rejects duplicate mapping keys (safe_load keeps last)."""
|
|
264
|
+
|
|
265
|
+
|
|
266
|
+
def _construct_mapping_rejecting_duplicates(
|
|
267
|
+
loader: yaml.SafeLoader,
|
|
268
|
+
node: yaml.nodes.MappingNode,
|
|
269
|
+
is_deep: bool = False,
|
|
270
|
+
) -> dict:
|
|
271
|
+
mapping: dict = {}
|
|
272
|
+
for each_key_node, each_field_node in node.value:
|
|
273
|
+
key = loader.construct_object(each_key_node, deep=is_deep)
|
|
274
|
+
if key in mapping:
|
|
275
|
+
raise yaml.constructor.ConstructorError(
|
|
276
|
+
None,
|
|
277
|
+
None,
|
|
278
|
+
f"duplicate key {key!r}",
|
|
279
|
+
each_key_node.start_mark,
|
|
280
|
+
)
|
|
281
|
+
mapping[key] = loader.construct_object(each_field_node, deep=is_deep)
|
|
282
|
+
return mapping
|
|
283
|
+
|
|
284
|
+
|
|
285
|
+
_UniqueKeySafeLoader.add_constructor(
|
|
286
|
+
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
|
|
287
|
+
_construct_mapping_rejecting_duplicates,
|
|
288
|
+
)
|
|
289
|
+
|
|
290
|
+
|
|
291
|
+
def _require_nonempty_string(field_content: object, source_path: Path) -> str:
|
|
292
|
+
if not isinstance(field_content, str):
|
|
293
|
+
raise MaterializerError(f"name and description are required: {source_path}")
|
|
294
|
+
if not field_content.strip():
|
|
295
|
+
raise MaterializerError(f"name and description are required: {source_path}")
|
|
296
|
+
return field_content
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
def _require_optional_string(
|
|
300
|
+
field_content: object, field_name: str, source_path: Path
|
|
301
|
+
) -> str | None:
|
|
302
|
+
if field_content is None:
|
|
303
|
+
return None
|
|
304
|
+
if not isinstance(field_content, str):
|
|
305
|
+
raise MaterializerError(f"{field_name} must be a string: {source_path}")
|
|
306
|
+
return field_content
|
|
307
|
+
|
|
308
|
+
|
|
309
|
+
def _require_tools_list(tools_content: object, source_path: Path) -> tuple[str, ...]:
|
|
310
|
+
if tools_content is None:
|
|
311
|
+
return ()
|
|
312
|
+
if isinstance(tools_content, str):
|
|
313
|
+
return (tools_content,)
|
|
314
|
+
if not isinstance(tools_content, list):
|
|
315
|
+
raise MaterializerError(f"tools must be a list: {source_path}")
|
|
316
|
+
if not all(isinstance(each_entry, str) for each_entry in tools_content):
|
|
317
|
+
raise MaterializerError(f"tools must be a list: {source_path}")
|
|
318
|
+
return tuple(tools_content)
|
|
325
319
|
|
|
326
320
|
|
|
327
321
|
def parse_frontmatter(source_path: Path, source_text: str, relative_source: str) -> ClaudeAgent:
|
|
328
|
-
"""Parse one Claude agent's frontmatter.
|
|
322
|
+
"""Parse one Claude agent's frontmatter through validated YAML.
|
|
329
323
|
|
|
330
324
|
Args:
|
|
331
325
|
source_path: Path used in validation errors.
|
|
@@ -342,30 +336,56 @@ def parse_frontmatter(source_path: Path, source_text: str, relative_source: str)
|
|
|
342
336
|
lines = source_text.splitlines()
|
|
343
337
|
if len(lines) < 3 or lines[0].strip() != "---":
|
|
344
338
|
raise MaterializerError(f"malformed frontmatter: {source_path}")
|
|
345
|
-
delimiters = [
|
|
339
|
+
delimiters = [
|
|
340
|
+
each_index for each_index, line in enumerate(lines[1:], 1) if line.strip() == "---"
|
|
341
|
+
]
|
|
346
342
|
if len(delimiters) != 1:
|
|
347
343
|
raise MaterializerError(f"malformed frontmatter delimiters: {source_path}")
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
344
|
+
frontmatter_text = line_separator.join(lines[1 : delimiters[0]]) + line_separator
|
|
345
|
+
try:
|
|
346
|
+
parsed_fields = yaml.load(frontmatter_text, Loader=_UniqueKeySafeLoader)
|
|
347
|
+
except yaml.YAMLError as yaml_error:
|
|
348
|
+
raise MaterializerError(f"malformed frontmatter: {source_path}") from yaml_error
|
|
349
|
+
if not isinstance(parsed_fields, dict):
|
|
350
|
+
raise MaterializerError(f"malformed frontmatter: {source_path}")
|
|
351
|
+
for each_key in parsed_fields:
|
|
352
|
+
if not isinstance(each_key, str) or not re.fullmatch(
|
|
353
|
+
r"[A-Za-z][A-Za-z0-9_-]*", each_key
|
|
354
|
+
):
|
|
355
355
|
raise MaterializerError(f"malformed frontmatter key: {source_path}")
|
|
356
|
-
|
|
357
|
-
|
|
356
|
+
unknown = tuple(
|
|
357
|
+
sorted(
|
|
358
|
+
each_key
|
|
359
|
+
for each_key in parsed_fields
|
|
360
|
+
if each_key not in frontmatter_allowed_fields
|
|
361
|
+
)
|
|
362
|
+
)
|
|
358
363
|
if unknown:
|
|
359
364
|
raise MaterializerError(f"unknown frontmatter keys: {source_path}")
|
|
360
|
-
unsupported = tuple(
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
365
|
+
unsupported = tuple(
|
|
366
|
+
sorted(
|
|
367
|
+
each_key
|
|
368
|
+
for each_key in parsed_fields
|
|
369
|
+
if each_key in frontmatter_unsupported_fields
|
|
370
|
+
)
|
|
371
|
+
)
|
|
372
|
+
name = _require_nonempty_string(parsed_fields.get("name"), source_path)
|
|
373
|
+
description = _require_nonempty_string(
|
|
374
|
+
parsed_fields.get("description"), source_path
|
|
375
|
+
)
|
|
376
|
+
tools = _require_tools_list(parsed_fields.get("tools"), source_path)
|
|
377
|
+
model = _require_optional_string(parsed_fields.get("model"), "model", source_path)
|
|
378
|
+
color = _require_optional_string(parsed_fields.get("color"), "color", source_path)
|
|
379
|
+
return ClaudeAgent(
|
|
380
|
+
source_path,
|
|
381
|
+
source_identity,
|
|
382
|
+
name,
|
|
383
|
+
description,
|
|
384
|
+
tools,
|
|
385
|
+
model,
|
|
386
|
+
color,
|
|
387
|
+
unsupported,
|
|
388
|
+
)
|
|
369
389
|
|
|
370
390
|
|
|
371
391
|
def convert_agent(agent: ClaudeAgent) -> str:
|
|
@@ -12,6 +12,8 @@ Named constants for scripts in `scripts/`. Follows the project convention that t
|
|
|
12
12
|
| `claude_chain_usage_constants.py` | `claude_chain_usage.py` - full weekly percent scale, usage-pause skill path segments, CLI config-path flag, JSON report keys, and probe error message templates |
|
|
13
13
|
| `grok_worker_constants.py` | `grok_worker_preflight.py`, `grok_headless_runner.py`, `spawn_grok_batch.py`, and `resolve_worker_spawn.py` - the `grok` binary name and CLI flags, model and subcommand tokens, leader-socket and scratch-file name parts, auth and usage-limit signature lists, outcome classifications, fallthrough reasons, tool-profile names and prompt headers, worker timeouts (default, plus the floor and the `MAXIMUM_WORKER_TIMEOUT_SECONDS` ceiling that the batch spec parse, the headless runner, and the spawn dispatcher all enforce, each bound carrying one rejection template shared by those sites, plus launch-failure return code and post-kill grace), the process-tree kill attempt limit and kill-failed classification, the preflight ping's single-turn cap, ping-cache keys and TTL, batch-spec and summary JSON keys, worker-advisor placeholder launcher/model/effort tokens, four verdict signals, MAXIMUM_WORKER_ADVISOR_CORRECTIONS, advisor_blocked classification, and advisor_session_id report keys, the prompt-part and report-stream join separators, and the CLI launch-error stderr prefix |
|
|
14
14
|
| `code_review_constants.py` | `invoke_code_review.py` - the `/code-review ultra --fix` prompt, opus model alias, permission-mode flag and value, result mode and JSON keys, session-model CLI flag, git dirty-check tokens, and in-session return markers; finding severity tokens (`blocker` / `high` / `medium` / `low` / `nit`), verification verdict tokens, loop terminal tokens (`clean` / `nits_fixed` / `advisor_blocked`), and pure helpers for retained-finding checks, head recording, terminal resolution, and terminal encoding |
|
|
15
|
+
| `active_capability_constants.py` | `active_capability_references.py` - package skills/agents/commands directory names, skill manifest filename, ban-listed capability names, inert fence languages, slash and backtick extract patterns, fence open/close patterns, banned-reason prefix, UTF-8 encoding, and newline join separator |
|
|
16
|
+
| `verify_installable_package_constants.py` | `verify_installable_package.py` - manifest filename and keys, npm pack / tarball / plugin-root tokens, git and node smoke argv pieces, surface classification labels, exit codes, and CLI status headers |
|
|
15
17
|
| `__init__.py` | Empty package marker |
|
|
16
18
|
|
|
17
19
|
## Convention
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"""Constants for the active_capability_references script.
|
|
2
|
+
|
|
3
|
+
Script-level scalar constants live in dev_env_scripts_constants alongside
|
|
4
|
+
timing.py and the other per-script constant modules.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
PACKAGE_SKILLS_DIRECTORY: str = "skills"
|
|
10
|
+
PACKAGE_AGENTS_DIRECTORY: str = "agents"
|
|
11
|
+
PACKAGE_COMMANDS_DIRECTORY: str = "commands"
|
|
12
|
+
SKILL_MANIFEST_FILENAME: str = "SKILL.md"
|
|
13
|
+
|
|
14
|
+
# Slash-command and skill names that must never appear as active instructions.
|
|
15
|
+
ALL_BANNED_ACTIVE_CAPABILITY_NAMES: frozenset[str] = frozenset(
|
|
16
|
+
{
|
|
17
|
+
"stub-detector",
|
|
18
|
+
"superpowers",
|
|
19
|
+
"qbug",
|
|
20
|
+
"findbugs",
|
|
21
|
+
"fixbugs",
|
|
22
|
+
"monitor-open-prs",
|
|
23
|
+
}
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# Fence languages treated as inert historical/example content.
|
|
27
|
+
ALL_INERT_FENCE_LANGUAGES: frozenset[str] = frozenset(
|
|
28
|
+
{
|
|
29
|
+
"example",
|
|
30
|
+
"history",
|
|
31
|
+
"historical",
|
|
32
|
+
"quote",
|
|
33
|
+
"diff",
|
|
34
|
+
}
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
SLASH_CAPABILITY_PATTERN: str = r"(?<![`\w])/([a-z][a-z0-9-]{2,})"
|
|
38
|
+
BACKTICK_CAPABILITY_PATTERN: str = (
|
|
39
|
+
r"`(?:skills/)?([a-z][a-z0-9-]{2,})(?:/SKILL\.md)?`"
|
|
40
|
+
)
|
|
41
|
+
FENCE_OPEN_PATTERN: str = r"^```([A-Za-z0-9_-]*)\s*$"
|
|
42
|
+
FENCE_CLOSE_PATTERN: str = r"^```\s*$"
|
|
43
|
+
BANNED_REASON_PREFIX: str = "banned_active_capability:"
|
|
44
|
+
|
|
45
|
+
UTF8_ENCODING: str = "utf-8"
|
|
46
|
+
NEWLINE_JOIN_SEPARATOR: str = "\n"
|
|
@@ -227,3 +227,77 @@ ATTEMPT_SUMMARY_ENTRY_TEMPLATE: str = "{command}={status}"
|
|
|
227
227
|
|
|
228
228
|
ATTEMPT_SUMMARY_JOIN_SEPARATOR: str = ", "
|
|
229
229
|
"""Separator joining per-attempt fragments in the exhausted-chain summary."""
|
|
230
|
+
|
|
231
|
+
AFFINITY_STATE_SCHEMA_VERSION: int = 1
|
|
232
|
+
"""Version field written into the session-to-binary affinity state document."""
|
|
233
|
+
|
|
234
|
+
AFFINITY_STATE_FILENAME: str = "claude-chain-affinity.json"
|
|
235
|
+
"""Default affinity state file name under the Claude home directory."""
|
|
236
|
+
|
|
237
|
+
AFFINITY_MAXIMUM_ENTRIES: int = 64
|
|
238
|
+
"""Hard cap on retained session-to-binary affinity rows (oldest drop first)."""
|
|
239
|
+
|
|
240
|
+
AFFINITY_KEY_SCHEMA_VERSION: str = "schema_version"
|
|
241
|
+
"""JSON key for the affinity document schema version."""
|
|
242
|
+
|
|
243
|
+
AFFINITY_KEY_ALL_BINDINGS: str = "all_bindings"
|
|
244
|
+
"""JSON key for the ordered list of session-to-command bindings."""
|
|
245
|
+
|
|
246
|
+
AFFINITY_KEY_SESSION_ID: str = "session_id"
|
|
247
|
+
"""JSON key for a bound Claude session id."""
|
|
248
|
+
|
|
249
|
+
AFFINITY_KEY_COMMAND: str = "command"
|
|
250
|
+
"""JSON key for the chain binary command bound to a session id."""
|
|
251
|
+
|
|
252
|
+
AFFINITY_TEMP_SUFFIX: str = ".tmp"
|
|
253
|
+
"""Suffix for the temporary file used during atomic affinity replacement."""
|
|
254
|
+
|
|
255
|
+
AFFINITY_BINDING_NOT_OBJECT_REASON: str = "a binding entry is not an object"
|
|
256
|
+
"""Reason when an affinity binding entry is not a JSON object."""
|
|
257
|
+
|
|
258
|
+
AFFINITY_BINDING_SESSION_ID_MISSING_REASON: str = (
|
|
259
|
+
"binding missing non-empty session_id"
|
|
260
|
+
)
|
|
261
|
+
"""Reason when an affinity binding lacks a usable session_id."""
|
|
262
|
+
|
|
263
|
+
AFFINITY_BINDING_COMMAND_MISSING_REASON: str = "binding missing non-empty command"
|
|
264
|
+
"""Reason when an affinity binding lacks a usable command."""
|
|
265
|
+
|
|
266
|
+
AFFINITY_UNSUPPORTED_SCHEMA_VERSION_REASON_TEMPLATE: str = (
|
|
267
|
+
"unsupported schema_version {schema_version!r}"
|
|
268
|
+
)
|
|
269
|
+
"""Reason when the affinity document schema version is not supported."""
|
|
270
|
+
|
|
271
|
+
AFFINITY_BINDINGS_MISSING_OR_NOT_LIST_REASON: str = (
|
|
272
|
+
"all_bindings is missing or not a list"
|
|
273
|
+
)
|
|
274
|
+
"""Reason when all_bindings is absent or the wrong type."""
|
|
275
|
+
|
|
276
|
+
AFFINITY_TOP_LEVEL_NOT_OBJECT_REASON: str = "top-level value is not a JSON object"
|
|
277
|
+
"""Reason when the affinity document root is not an object."""
|
|
278
|
+
|
|
279
|
+
AFFINITY_SESSION_ID_AND_COMMAND_REQUIRED_MESSAGE: str = (
|
|
280
|
+
"session_id and command must be non-empty"
|
|
281
|
+
)
|
|
282
|
+
"""ValueError message when record_affinity_binding receives empty ids."""
|
|
283
|
+
|
|
284
|
+
AFFINITY_MAXIMUM_ENTRIES_MINIMUM_MESSAGE: str = "maximum_entries must be at least 1"
|
|
285
|
+
"""ValueError message when maximum_entries is below one."""
|
|
286
|
+
|
|
287
|
+
AFFINITY_CORRUPT_MESSAGE_TEMPLATE: str = (
|
|
288
|
+
"Affinity state at {state_path} is corrupt or unreadable: {error}. "
|
|
289
|
+
"Delete or repair the file before retrying."
|
|
290
|
+
)
|
|
291
|
+
"""Actionable diagnostic when affinity state cannot be loaded."""
|
|
292
|
+
|
|
293
|
+
AFFINITY_WRITE_FAILED_MESSAGE_TEMPLATE: str = (
|
|
294
|
+
"Failed to write affinity state at {state_path}: {error}. "
|
|
295
|
+
"Check directory permissions and free space."
|
|
296
|
+
)
|
|
297
|
+
"""Actionable diagnostic when atomic affinity replacement fails."""
|
|
298
|
+
|
|
299
|
+
AFFINITY_JSON_INDENT_SPACES: int = 2
|
|
300
|
+
"""Indent width for the written affinity state JSON document."""
|
|
301
|
+
|
|
302
|
+
RESUME_SESSION_FLAG: str = "--resume"
|
|
303
|
+
"""Claude CLI flag that continues a prior session by id."""
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Constants for verify_installable_package — npm pack surface checks.
|
|
2
|
+
|
|
3
|
+
Holds manifest keys, pack/tarball path tokens, hook-command path markers,
|
|
4
|
+
git and smoke-tool argv pieces, and CLI status messages.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
MANIFEST_FILENAME: str = "installable-surfaces.manifest.json"
|
|
8
|
+
"""Basename of the committed installable-surfaces manifest under the package root."""
|
|
9
|
+
|
|
10
|
+
PACKAGE_JSON_FILENAME: str = "package.json"
|
|
11
|
+
"""Basename of the npm package manifest that lists the files field."""
|
|
12
|
+
|
|
13
|
+
PACKAGE_JSON_FILES_KEY: str = "files"
|
|
14
|
+
"""JSON key on package.json that lists packaged path entries."""
|
|
15
|
+
|
|
16
|
+
PACKAGE_JSON_EXCLUDE_PREFIX: str = "!"
|
|
17
|
+
"""Prefix on package.json files entries that exclude a path pattern."""
|
|
18
|
+
|
|
19
|
+
MANIFEST_DIRECTORIES_KEY: str = "directories"
|
|
20
|
+
"""JSON key listing required top-level package directories."""
|
|
21
|
+
|
|
22
|
+
MANIFEST_ROOT_FILES_KEY: str = "root_files"
|
|
23
|
+
"""JSON key listing required package-root files."""
|
|
24
|
+
|
|
25
|
+
TARBALL_PACKAGE_PREFIX: str = "package/"
|
|
26
|
+
"""Path prefix npm pack applies to every member inside the generated tarball."""
|
|
27
|
+
|
|
28
|
+
PLUGIN_ROOT_TOKEN: str = "${CLAUDE_PLUGIN_ROOT}/"
|
|
29
|
+
"""Placeholder prefix hooks.json uses for package-relative hook script paths."""
|
|
30
|
+
|
|
31
|
+
PYTHON_FILE_SUFFIX: str = ".py"
|
|
32
|
+
"""Suffix that marks a hook command token as a Python script path."""
|
|
33
|
+
|
|
34
|
+
HOOKS_DIRECTORY_NAME: str = "hooks"
|
|
35
|
+
"""Top-level package directory that holds hook scripts and hooks.json."""
|
|
36
|
+
|
|
37
|
+
HOOKS_DIRECTORY_PREFIX: str = "hooks/"
|
|
38
|
+
"""Package-relative prefix that marks a hook script path under hooks/."""
|
|
39
|
+
|
|
40
|
+
HOOKS_JSON_RELATIVE_PATH: str = "hooks/hooks.json"
|
|
41
|
+
"""Package-relative path of the hook registration map."""
|
|
42
|
+
|
|
43
|
+
JSON_COMMAND_KEY: str = "command"
|
|
44
|
+
"""JSON object key whose string value is a hook command line."""
|
|
45
|
+
|
|
46
|
+
INSTALL_ENTRYPOINT_RELATIVE_PATH: str = "bin/install.mjs"
|
|
47
|
+
"""Package-relative path of the primary install CLI entrypoint."""
|
|
48
|
+
|
|
49
|
+
PACKAGE_PATH_FROM_REPOSITORY: str = "packages/claude-dev-env"
|
|
50
|
+
"""Repository-relative path of the published package directory."""
|
|
51
|
+
|
|
52
|
+
NPM_BINARY_NAME: str = "npm"
|
|
53
|
+
"""npm CLI binary name used to build the pack tarball on POSIX hosts."""
|
|
54
|
+
|
|
55
|
+
NPM_CMD_BINARY_NAME: str = "npm.cmd"
|
|
56
|
+
"""Windows npm launcher resolved before the extensionless npm name."""
|
|
57
|
+
|
|
58
|
+
NEWLINE_JOIN_SEPARATOR: str = "\n"
|
|
59
|
+
"""Separator used when joining multi-line verification failure reports."""
|
|
60
|
+
|
|
61
|
+
NPM_PACK_SUBCOMMAND: str = "pack"
|
|
62
|
+
"""npm subcommand that writes the installable tarball."""
|
|
63
|
+
|
|
64
|
+
NPM_PACK_JSON_FLAG: str = "--json"
|
|
65
|
+
"""Flag that makes npm pack emit machine-readable filename metadata."""
|
|
66
|
+
|
|
67
|
+
NPM_PACK_DESTINATION_FLAG: str = "--pack-destination"
|
|
68
|
+
"""Flag that directs npm pack to write the tarball into a chosen directory."""
|
|
69
|
+
|
|
70
|
+
NPM_PACK_FILENAME_KEY: str = "filename"
|
|
71
|
+
"""JSON field on an npm pack --json record that holds the tarball basename."""
|
|
72
|
+
|
|
73
|
+
GIT_BINARY_NAME: str = "git"
|
|
74
|
+
"""git CLI binary name used to confirm hook scripts are committed."""
|
|
75
|
+
|
|
76
|
+
GIT_LS_FILES_SUBCOMMAND: str = "ls-files"
|
|
77
|
+
"""git subcommand that lists tracked paths in the index."""
|
|
78
|
+
|
|
79
|
+
NODE_BINARY_NAME: str = "node"
|
|
80
|
+
"""Node.js binary name used for install-entrypoint syntax smoke checks."""
|
|
81
|
+
|
|
82
|
+
NODE_CHECK_FLAG: str = "--check"
|
|
83
|
+
"""Flag that makes node parse a script without executing it."""
|
|
84
|
+
|
|
85
|
+
UTF8_ENCODING: str = "utf-8"
|
|
86
|
+
"""Text encoding for manifest, hooks.json, and subprocess text mode."""
|
|
87
|
+
|
|
88
|
+
CLASS_PACKAGED: str = "packaged"
|
|
89
|
+
"""Surface classification when a directory is on disk and listed for packaging."""
|
|
90
|
+
|
|
91
|
+
CLASS_SOURCE_ONLY: str = "source_only"
|
|
92
|
+
"""Surface classification when a directory is on disk but not listed for packaging."""
|
|
93
|
+
|
|
94
|
+
CLASS_CONTRADICTORY: str = "contradictory"
|
|
95
|
+
"""Surface classification when package.json lists a directory that is missing on disk."""
|
|
96
|
+
|
|
97
|
+
EXIT_CODE_SUCCESS: int = 0
|
|
98
|
+
"""Process exit code when every installable-surface check passes."""
|
|
99
|
+
|
|
100
|
+
EXIT_CODE_FAILURE: int = 1
|
|
101
|
+
"""Process exit code when one or more installable-surface checks fail."""
|
|
102
|
+
|
|
103
|
+
MISSING_MANIFEST_SURFACES_HEADER: str = "Missing surfaces in npm pack tarball:"
|
|
104
|
+
"""Header printed when required manifest paths are absent from the packed tarball."""
|
|
105
|
+
|
|
106
|
+
UNTRACKED_HOOK_SCRIPTS_HEADER: str = "Hook scripts missing from git index:"
|
|
107
|
+
"""Header printed when a hooks.json command resolves to an untracked or missing file."""
|
|
108
|
+
|
|
109
|
+
SMOKE_COMPILE_FAILURES_HEADER: str = "Hook scripts failed py_compile:"
|
|
110
|
+
"""Header printed when a resolved hook script fails Python syntax compilation."""
|
|
111
|
+
|
|
112
|
+
INSTALL_ENTRYPOINT_SMOKE_FAILURE_HEADER: str = "Install entrypoint failed node --check:"
|
|
113
|
+
"""Header printed when bin/install.mjs fails the Node syntax smoke check."""
|
|
114
|
+
|
|
115
|
+
VERIFICATION_PASSED_MESSAGE: str = "installable package verification passed"
|
|
116
|
+
"""Status line printed when every check succeeds."""
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"supportedActivationInterface": "claude-config-dir-mcp-json",
|
|
4
|
+
"mcpConfigFileName": "mcp.json",
|
|
5
|
+
"bundles": {
|
|
6
|
+
"lean": {
|
|
7
|
+
"id": "lean",
|
|
8
|
+
"allServerNames": ["filesystem-readonly"]
|
|
9
|
+
},
|
|
10
|
+
"full": {
|
|
11
|
+
"id": "full",
|
|
12
|
+
"allServerNames": ["filesystem-readonly", "github-readonly"]
|
|
13
|
+
}
|
|
14
|
+
},
|
|
15
|
+
"serverByName": {
|
|
16
|
+
"filesystem-readonly": {
|
|
17
|
+
"command": "npx",
|
|
18
|
+
"args": ["-y", "@modelcontextprotocol/server-filesystem", "${PROFILE_ROOT}"]
|
|
19
|
+
},
|
|
20
|
+
"github-readonly": {
|
|
21
|
+
"command": "npx",
|
|
22
|
+
"args": ["-y", "@modelcontextprotocol/server-github"]
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, join } from 'node:path';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
|
|
5
|
+
const CONFIG_DIRECTORY_PATH = dirname(fileURLToPath(import.meta.url));
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @param {string} fileName
|
|
9
|
+
* @returns {unknown}
|
|
10
|
+
*/
|
|
11
|
+
function readJsonConfigFile(fileName) {
|
|
12
|
+
const absolutePath = join(CONFIG_DIRECTORY_PATH, fileName);
|
|
13
|
+
return JSON.parse(readFileSync(absolutePath, 'utf8'));
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export const PROFILES_MANIFEST_FILE_NAME = 'profiles.manifest.json';
|
|
17
|
+
export const SHARED_ALLOWLIST_FILE_NAME = 'shared-allowlist.json';
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Sole authoritative profile-root environment variable for CLI isolation.
|
|
21
|
+
* CLAUDE_HOME is never honored as a profile root by this contract.
|
|
22
|
+
*/
|
|
23
|
+
export const CLAUDE_CONFIG_DIR_ENVIRONMENT_VARIABLE = 'CLAUDE_CONFIG_DIR';
|
|
24
|
+
export const CLAUDE_HOME_ENVIRONMENT_VARIABLE = 'CLAUDE_HOME';
|
|
25
|
+
export const CLAUDE_CODE_TMPDIR_ENVIRONMENT_VARIABLE = 'CLAUDE_CODE_TMPDIR';
|
|
26
|
+
export const CLAUDE_CODE_PLUGIN_SEED_DIR_ENVIRONMENT_VARIABLE = 'CLAUDE_CODE_PLUGIN_SEED_DIR';
|
|
27
|
+
|
|
28
|
+
export const PROFILES_ROOT_ENVIRONMENT_VARIABLE = 'LLM_SETTINGS_PROFILES_ROOT';
|
|
29
|
+
export const SHARED_SOURCE_ROOT_ENVIRONMENT_VARIABLE = 'LLM_SETTINGS_SHARED_SOURCE_ROOT';
|
|
30
|
+
export const PLUGIN_SEED_ROOT_ENVIRONMENT_VARIABLE = 'LLM_SETTINGS_PLUGIN_SEED_ROOT';
|
|
31
|
+
|
|
32
|
+
export const DEFAULT_PROFILES_ROOT_DIRECTORY_NAME = '.claude-profiles';
|
|
33
|
+
export const DEFAULT_SHARED_SOURCE_DIRECTORY_NAME = 'shared-source';
|
|
34
|
+
export const DEFAULT_PLUGIN_SEED_DIRECTORY_NAME = 'plugin-seed';
|
|
35
|
+
|
|
36
|
+
export const MIGRATION_MODE_CLEAN_LOCAL_RUNTIME = 'clean-local-runtime';
|
|
37
|
+
export const MIGRATION_MODE_MATERIALIZE_FROM_LEGACY = 'materialize-from-legacy';
|
|
38
|
+
|
|
39
|
+
export const MCP_BUNDLE_LEAN = 'lean';
|
|
40
|
+
export const MCP_BUNDLE_FULL = 'full';
|
|
41
|
+
|
|
42
|
+
export const LAUNCHER_SCHEMA_VERSION = 1;
|
|
43
|
+
export const PROFILE_ISOLATION_CONTRACT_OWNER = 'profile-isolation-contract';
|
|
44
|
+
export const PACKAGE_FILES_WHITELIST_SCRIPTS_ENTRY = 'scripts/';
|
|
45
|
+
export const LIVE_DEPLOYMENT_RESERVED_FOR = 'L1';
|
|
46
|
+
export const INSTALL_DESTINATION_ROOT_RELATIVE_PATH = 'scripts/profile-isolation-launchers';
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* @returns {Record<string, unknown>}
|
|
50
|
+
*/
|
|
51
|
+
export function loadProfilesManifestDocument() {
|
|
52
|
+
return /** @type {Record<string, unknown>} */ (readJsonConfigFile(PROFILES_MANIFEST_FILE_NAME));
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* @returns {Record<string, unknown>}
|
|
57
|
+
*/
|
|
58
|
+
export function loadSharedAllowlistDocument() {
|
|
59
|
+
return /** @type {Record<string, unknown>} */ (readJsonConfigFile(SHARED_ALLOWLIST_FILE_NAME));
|
|
60
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schemaVersion": 1,
|
|
3
|
+
"profilesRootPlaceholder": "${PROFILES_ROOT}",
|
|
4
|
+
"sharedSourcePlaceholder": "${SHARED_SOURCE_ROOT}",
|
|
5
|
+
"pluginSeedPlaceholder": "${PLUGIN_SEED_ROOT}",
|
|
6
|
+
"migrationOrder": ["profile-c", "profile-b", "profile-a", "master", "profile-d"],
|
|
7
|
+
"profiles": {
|
|
8
|
+
"master": {
|
|
9
|
+
"id": "master",
|
|
10
|
+
"aliases": ["default"],
|
|
11
|
+
"directoryName": "master",
|
|
12
|
+
"launcherNames": ["claude"],
|
|
13
|
+
"fullLauncherNames": ["claude-full"],
|
|
14
|
+
"migrationMode": "materialize-from-legacy",
|
|
15
|
+
"mcpBundle": "lean"
|
|
16
|
+
},
|
|
17
|
+
"profile-a": {
|
|
18
|
+
"id": "profile-a",
|
|
19
|
+
"aliases": [],
|
|
20
|
+
"directoryName": "profile-a",
|
|
21
|
+
"launcherNames": ["claude-profile-a"],
|
|
22
|
+
"fullLauncherNames": ["claude-profile-a-full"],
|
|
23
|
+
"migrationMode": "materialize-from-legacy",
|
|
24
|
+
"mcpBundle": "lean"
|
|
25
|
+
},
|
|
26
|
+
"profile-c": {
|
|
27
|
+
"id": "profile-c",
|
|
28
|
+
"aliases": [],
|
|
29
|
+
"directoryName": "profile-c",
|
|
30
|
+
"launcherNames": ["claude-profile-c"],
|
|
31
|
+
"fullLauncherNames": ["claude-profile-c-full"],
|
|
32
|
+
"migrationMode": "clean-local-runtime",
|
|
33
|
+
"mcpBundle": "lean"
|
|
34
|
+
},
|
|
35
|
+
"profile-b": {
|
|
36
|
+
"id": "profile-b",
|
|
37
|
+
"aliases": [],
|
|
38
|
+
"directoryName": "profile-b",
|
|
39
|
+
"launcherNames": ["claude-profile-b"],
|
|
40
|
+
"fullLauncherNames": ["claude-profile-b-full"],
|
|
41
|
+
"migrationMode": "clean-local-runtime",
|
|
42
|
+
"mcpBundle": "lean"
|
|
43
|
+
},
|
|
44
|
+
"profile-d": {
|
|
45
|
+
"id": "profile-d",
|
|
46
|
+
"aliases": [],
|
|
47
|
+
"directoryName": "profile-d",
|
|
48
|
+
"launcherNames": ["claude-profile-d"],
|
|
49
|
+
"fullLauncherNames": ["claude-profile-d-full"],
|
|
50
|
+
"migrationMode": "clean-local-runtime",
|
|
51
|
+
"mcpBundle": "lean"
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|