@ahmed-g-gad/apothem 0.1.1
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/CHANGELOG.md +60 -0
- package/LICENSE +21 -0
- package/LICENSES/MIT.txt +18 -0
- package/LICENSES/PSF-2.0.txt +47 -0
- package/README.md +549 -0
- package/bin/README.md +37 -0
- package/bin/apothem.mjs +78 -0
- package/package.json +75 -0
- package/pyproject.toml +347 -0
- package/src/apothem/README.md +52 -0
- package/src/apothem/__init__.py +66 -0
- package/src/apothem/__main__.py +28 -0
- package/src/apothem/_vendor/.keep +0 -0
- package/src/apothem/_vendor/__init__.py +25 -0
- package/src/apothem/_vendor/attr/__init__.py +104 -0
- package/src/apothem/_vendor/attr/__init__.pyi +389 -0
- package/src/apothem/_vendor/attr/_cmp.py +160 -0
- package/src/apothem/_vendor/attr/_cmp.pyi +13 -0
- package/src/apothem/_vendor/attr/_compat.py +99 -0
- package/src/apothem/_vendor/attr/_config.py +31 -0
- package/src/apothem/_vendor/attr/_funcs.py +497 -0
- package/src/apothem/_vendor/attr/_make.py +3406 -0
- package/src/apothem/_vendor/attr/_next_gen.py +674 -0
- package/src/apothem/_vendor/attr/_typing_compat.pyi +15 -0
- package/src/apothem/_vendor/attr/_version_info.py +89 -0
- package/src/apothem/_vendor/attr/_version_info.pyi +9 -0
- package/src/apothem/_vendor/attr/converters.py +162 -0
- package/src/apothem/_vendor/attr/converters.pyi +19 -0
- package/src/apothem/_vendor/attr/exceptions.py +95 -0
- package/src/apothem/_vendor/attr/exceptions.pyi +17 -0
- package/src/apothem/_vendor/attr/filters.py +72 -0
- package/src/apothem/_vendor/attr/filters.pyi +6 -0
- package/src/apothem/_vendor/attr/py.typed +0 -0
- package/src/apothem/_vendor/attr/setters.py +79 -0
- package/src/apothem/_vendor/attr/setters.pyi +20 -0
- package/src/apothem/_vendor/attr/validators.py +750 -0
- package/src/apothem/_vendor/attr/validators.pyi +140 -0
- package/src/apothem/_vendor/attr.LICENSE +21 -0
- package/src/apothem/_vendor/attrs/__init__.py +72 -0
- package/src/apothem/_vendor/attrs/__init__.pyi +314 -0
- package/src/apothem/_vendor/attrs/converters.py +3 -0
- package/src/apothem/_vendor/attrs/exceptions.py +3 -0
- package/src/apothem/_vendor/attrs/filters.py +3 -0
- package/src/apothem/_vendor/attrs/py.typed +0 -0
- package/src/apothem/_vendor/attrs/setters.py +3 -0
- package/src/apothem/_vendor/attrs/validators.py +3 -0
- package/src/apothem/_vendor/attrs.LICENSE +21 -0
- package/src/apothem/_vendor/jsonschema/__init__.py +120 -0
- package/src/apothem/_vendor/jsonschema/__main__.py +6 -0
- package/src/apothem/_vendor/jsonschema/_format.py +546 -0
- package/src/apothem/_vendor/jsonschema/_keywords.py +449 -0
- package/src/apothem/_vendor/jsonschema/_legacy_keywords.py +449 -0
- package/src/apothem/_vendor/jsonschema/_types.py +204 -0
- package/src/apothem/_vendor/jsonschema/_typing.py +29 -0
- package/src/apothem/_vendor/jsonschema/_utils.py +355 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/__init__.py +5 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/const_vs_enum.py +30 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/contains.py +28 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/import_benchmark.py +31 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/issue232/issue.json +2653 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/issue232.py +25 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/json_schema_test_suite.py +12 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/nested_schemas.py +56 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/subcomponents.py +42 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/unused_registry.py +35 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/useless_applicator_schemas.py +106 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/useless_keywords.py +32 -0
- package/src/apothem/_vendor/jsonschema/benchmarks/validator_creation.py +14 -0
- package/src/apothem/_vendor/jsonschema/cli.py +292 -0
- package/src/apothem/_vendor/jsonschema/exceptions.py +490 -0
- package/src/apothem/_vendor/jsonschema/protocols.py +230 -0
- package/src/apothem/_vendor/jsonschema/validators.py +1410 -0
- package/src/apothem/_vendor/jsonschema.LICENSE +19 -0
- package/src/apothem/_vendor/jsonschema_specifications/__init__.py +12 -0
- package/src/apothem/_vendor/jsonschema_specifications/_core.py +38 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/metaschema.json +42 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/applicator +56 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/content +17 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/core +57 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/format +14 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data +37 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft201909/vocabularies/validation +98 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/metaschema.json +58 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/applicator +48 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/content +17 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/core +51 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation +14 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion +14 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data +37 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated +15 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft202012/vocabularies/validation +98 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft3/metaschema.json +172 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft4/metaschema.json +149 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft6/metaschema.json +153 -0
- package/src/apothem/_vendor/jsonschema_specifications/schemas/draft7/metaschema.json +166 -0
- package/src/apothem/_vendor/jsonschema_specifications.LICENSE +19 -0
- package/src/apothem/_vendor/referencing/__init__.py +7 -0
- package/src/apothem/_vendor/referencing/_attrs.py +31 -0
- package/src/apothem/_vendor/referencing/_attrs.pyi +21 -0
- package/src/apothem/_vendor/referencing/_core.py +739 -0
- package/src/apothem/_vendor/referencing/exceptions.py +165 -0
- package/src/apothem/_vendor/referencing/jsonschema.py +642 -0
- package/src/apothem/_vendor/referencing/py.typed +0 -0
- package/src/apothem/_vendor/referencing/retrieval.py +94 -0
- package/src/apothem/_vendor/referencing/typing.py +61 -0
- package/src/apothem/_vendor/referencing.LICENSE +19 -0
- package/src/apothem/_vendor/rpds/__init__.py +251 -0
- package/src/apothem/_vendor/typing_extensions.LICENSE +279 -0
- package/src/apothem/_vendor/typing_extensions.py +4317 -0
- package/src/apothem/_vendor/vendor.txt +22 -0
- package/src/apothem/_vendor/yaml/__init__.py +389 -0
- package/src/apothem/_vendor/yaml/composer.py +138 -0
- package/src/apothem/_vendor/yaml/constructor.py +748 -0
- package/src/apothem/_vendor/yaml/cyaml.py +100 -0
- package/src/apothem/_vendor/yaml/dumper.py +61 -0
- package/src/apothem/_vendor/yaml/emitter.py +1137 -0
- package/src/apothem/_vendor/yaml/error.py +74 -0
- package/src/apothem/_vendor/yaml/events.py +85 -0
- package/src/apothem/_vendor/yaml/loader.py +63 -0
- package/src/apothem/_vendor/yaml/nodes.py +48 -0
- package/src/apothem/_vendor/yaml/parser.py +588 -0
- package/src/apothem/_vendor/yaml/reader.py +185 -0
- package/src/apothem/_vendor/yaml/representer.py +388 -0
- package/src/apothem/_vendor/yaml/resolver.py +226 -0
- package/src/apothem/_vendor/yaml/scanner.py +1435 -0
- package/src/apothem/_vendor/yaml/serializer.py +110 -0
- package/src/apothem/_vendor/yaml/tokens.py +103 -0
- package/src/apothem/_vendor/yaml.LICENSE +20 -0
- package/src/apothem/agents/README.md +60 -0
- package/src/apothem/agents/codebase-explorer.md +91 -0
- package/src/apothem/agents/convention-auditor.md +93 -0
- package/src/apothem/agents/dependency-auditor.md +97 -0
- package/src/apothem/agents/fact-checker.md +84 -0
- package/src/apothem/agents/mcp-builder.md +86 -0
- package/src/apothem/agents/memory-auditor.md +93 -0
- package/src/apothem/agents/prompt-evaluator.md +87 -0
- package/src/apothem/agents/quality-gate.md +103 -0
- package/src/apothem/agents/refactor-surgeon.md +74 -0
- package/src/apothem/agents/research-scout.md +73 -0
- package/src/apothem/agents/security-scanner.md +83 -0
- package/src/apothem/agents/test-runner.md +84 -0
- package/src/apothem/audit/README.md +73 -0
- package/src/apothem/audit/_scan_lib.py +182 -0
- package/src/apothem/audit/analyze_graph.py +260 -0
- package/src/apothem/audit/build_capability_graph.py +607 -0
- package/src/apothem/audit/build_inventory.py +657 -0
- package/src/apothem/audit/build_plans_provenance.py +997 -0
- package/src/apothem/audit/check_links.py +389 -0
- package/src/apothem/audit/classify_artifacts.py +381 -0
- package/src/apothem/audit/deprecated-tokens.txt +10 -0
- package/src/apothem/audit/execute_plans_migration.py +491 -0
- package/src/apothem/audit/known-projects.txt +15 -0
- package/src/apothem/audit/render_capability_index.py +467 -0
- package/src/apothem/audit/render_inventory.py +405 -0
- package/src/apothem/audit/scan_ai_surfaces.py +1125 -0
- package/src/apothem/audit/scan_ai_surfaces_coarse.py +261 -0
- package/src/apothem/audit/scan_drift_features.py +143 -0
- package/src/apothem/audit/scan_frontmatter.py +293 -0
- package/src/apothem/audit/scan_header_coverage.py +1134 -0
- package/src/apothem/audit/scan_plan_leakage.py +540 -0
- package/src/apothem/audit/scan_plans_discipline.py +188 -0
- package/src/apothem/audit/scan_secrets_pii.py +245 -0
- package/src/apothem/audit/scan_stale_tokens.py +296 -0
- package/src/apothem/audit/synthesize_drift.py +205 -0
- package/src/apothem/benchmarks/README.md +33 -0
- package/src/apothem/benchmarks/__init__.py +3 -0
- package/src/apothem/benchmarks/bench_agents.py +63 -0
- package/src/apothem/benchmarks/bench_hooks.py +93 -0
- package/src/apothem/benchmarks/bench_install.py +58 -0
- package/src/apothem/benchmarks/bench_tests.py +93 -0
- package/src/apothem/benchmarks/bench_validate_ecosystem.py +84 -0
- package/src/apothem/cli/README.md +33 -0
- package/src/apothem/cli/__init__.py +229 -0
- package/src/apothem/cli/_cmd_completion.py +88 -0
- package/src/apothem/cli/_cmd_diff.py +181 -0
- package/src/apothem/cli/_cmd_doctor.py +143 -0
- package/src/apothem/cli/_cmd_harnesses.py +167 -0
- package/src/apothem/cli/_cmd_install.py +327 -0
- package/src/apothem/cli/_cmd_migrate_workspace.py +143 -0
- package/src/apothem/cli/_cmd_profile.py +341 -0
- package/src/apothem/cli/_cmd_status.py +180 -0
- package/src/apothem/cli/_cmd_uninstall.py +215 -0
- package/src/apothem/cli/_cmd_update.py +397 -0
- package/src/apothem/cli/_cmd_verify.py +194 -0
- package/src/apothem/cli/_common_flags.py +90 -0
- package/src/apothem/cli/_epilogs.py +296 -0
- package/src/apothem/cli/_helpers.py +857 -0
- package/src/apothem/cli/_json_formatter.py +21 -0
- package/src/apothem/cli/_materialize.py +376 -0
- package/src/apothem/cli/completions/apothem.bash +30 -0
- package/src/apothem/cli/completions/apothem.fish +19 -0
- package/src/apothem/cli/completions/apothem.ps1 +27 -0
- package/src/apothem/cli/completions/apothem.zsh +42 -0
- package/src/apothem/cli/reference_export.py +126 -0
- package/src/apothem/commands/README.md +125 -0
- package/src/apothem/commands/a11y-audit.md +203 -0
- package/src/apothem/commands/architecture-review.md +194 -0
- package/src/apothem/commands/audit.md +165 -0
- package/src/apothem/commands/code-audit.md +218 -0
- package/src/apothem/commands/code-review.md +193 -0
- package/src/apothem/commands/dependency-audit.md +209 -0
- package/src/apothem/commands/docs-review.md +199 -0
- package/src/apothem/commands/elevate.md +285 -0
- package/src/apothem/commands/eval.md +149 -0
- package/src/apothem/commands/fortress.md +172 -0
- package/src/apothem/commands/freshify.md +168 -0
- package/src/apothem/commands/github-deploy-fresh.md +178 -0
- package/src/apothem/commands/github-deploy-next.md +167 -0
- package/src/apothem/commands/perf-audit.md +198 -0
- package/src/apothem/commands/plan-amend.md +104 -0
- package/src/apothem/commands/plan-audit.md +127 -0
- package/src/apothem/commands/plan-design.md +257 -0
- package/src/apothem/commands/plan-execute.md +495 -0
- package/src/apothem/commands/plan-generate.md +351 -0
- package/src/apothem/commands/plan-review.md +555 -0
- package/src/apothem/commands/plan-spec.md +359 -0
- package/src/apothem/commands/plan-status.md +222 -0
- package/src/apothem/commands/plan.md +173 -0
- package/src/apothem/commands/projectify.md +142 -0
- package/src/apothem/commands/release-readiness.md +142 -0
- package/src/apothem/commands/research-analysis.md +241 -0
- package/src/apothem/commands/research-design.md +231 -0
- package/src/apothem/commands/research-disseminate.md +225 -0
- package/src/apothem/commands/research-experiment.md +232 -0
- package/src/apothem/commands/research-ideate.md +213 -0
- package/src/apothem/commands/research-paper.md +252 -0
- package/src/apothem/commands/research-proposal.md +220 -0
- package/src/apothem/commands/research-publish.md +255 -0
- package/src/apothem/commands/research-review.md +251 -0
- package/src/apothem/commands/research-sources.md +266 -0
- package/src/apothem/commands/research-spec.md +255 -0
- package/src/apothem/commands/research-synthesis.md +233 -0
- package/src/apothem/commands/research-theory.md +218 -0
- package/src/apothem/commands/research.md +181 -0
- package/src/apothem/commands/security-audit.md +196 -0
- package/src/apothem/commands/supply-chain-audit.md +192 -0
- package/src/apothem/commands/test-suite.md +146 -0
- package/src/apothem/commands/threat-model-audit.md +199 -0
- package/src/apothem/commands/ux-review.md +202 -0
- package/src/apothem/commands/workflow.md +162 -0
- package/src/apothem/conformity/README.md +173 -0
- package/src/apothem/conformity/__init__.py +1 -0
- package/src/apothem/conformity/_grep_base.py +93 -0
- package/src/apothem/conformity/agent_capability_grep.py +306 -0
- package/src/apothem/conformity/agents_md_coverage_grep.py +382 -0
- package/src/apothem/conformity/agnosticism_grep.py +311 -0
- package/src/apothem/conformity/always_on_budget_grep.py +318 -0
- package/src/apothem/conformity/bare_except_grep.py +115 -0
- package/src/apothem/conformity/binding_reciprocity_grep.py +151 -0
- package/src/apothem/conformity/brand_mark_grep.py +272 -0
- package/src/apothem/conformity/commented_out_code_grep.py +176 -0
- package/src/apothem/conformity/completion_claim_grep.py +169 -0
- package/src/apothem/conformity/conventional_commit_grep.py +319 -0
- package/src/apothem/conformity/copilot_instructions_presence_grep.py +324 -0
- package/src/apothem/conformity/cross_platform_matrix_grep.py +297 -0
- package/src/apothem/conformity/determinism_grep.py +306 -0
- package/src/apothem/conformity/diagram_staleness_grep.py +154 -0
- package/src/apothem/conformity/dynamism_grep.py +284 -0
- package/src/apothem/conformity/editorconfig_presence_grep.py +281 -0
- package/src/apothem/conformity/file_header_grep.py +502 -0
- package/src/apothem/conformity/freshness_token_grep.py +233 -0
- package/src/apothem/conformity/frontmatter_grep.py +274 -0
- package/src/apothem/conformity/frontmatter_value_grep.py +386 -0
- package/src/apothem/conformity/gate.py +1386 -0
- package/src/apothem/conformity/gitattributes_presence_grep.py +238 -0
- package/src/apothem/conformity/harden_runner_grep.py +320 -0
- package/src/apothem/conformity/hedging_grep.py +129 -0
- package/src/apothem/conformity/license_author_consistency_grep.py +204 -0
- package/src/apothem/conformity/link_check.py +327 -0
- package/src/apothem/conformity/magic_number_grep.py +182 -0
- package/src/apothem/conformity/multi_surface_coherence_grep.py +620 -0
- package/src/apothem/conformity/naming_grep.py +224 -0
- package/src/apothem/conformity/no_global_plans_grep.py +339 -0
- package/src/apothem/conformity/no_toplevel_docs_grep.py +120 -0
- package/src/apothem/conformity/oidc_trusted_publishing_grep.py +291 -0
- package/src/apothem/conformity/option_annotation_grep.py +352 -0
- package/src/apothem/conformity/orphan_output_grep.py +206 -0
- package/src/apothem/conformity/permissions_minimum_scope_grep.py +299 -0
- package/src/apothem/conformity/plain_language_grep.py +559 -0
- package/src/apothem/conformity/plan_next_step_consistency_grep.py +450 -0
- package/src/apothem/conformity/plan_suite_structure_grep.py +534 -0
- package/src/apothem/conformity/plans_discipline_language_grep.py +245 -0
- package/src/apothem/conformity/production_ready_pr_grep.py +200 -0
- package/src/apothem/conformity/recommend_next_step_grep.py +250 -0
- package/src/apothem/conformity/redundancy_grep.py +401 -0
- package/src/apothem/conformity/reference_token_grep.py +230 -0
- package/src/apothem/conformity/registry_capability_consistency_grep.py +368 -0
- package/src/apothem/conformity/secret_leak_grep.py +193 -0
- package/src/apothem/conformity/semver_stability_grep.py +358 -0
- package/src/apothem/conformity/smoke_install_grep.py +194 -0
- package/src/apothem/conformity/static_version_grep.py +284 -0
- package/src/apothem/conformity/token_efficiency_grep.py +185 -0
- package/src/apothem/conformity/unpinned_action_grep.py +115 -0
- package/src/apothem/conformity/user_confirm_grep.py +74 -0
- package/src/apothem/conformity/workflow_concurrency_grep.py +283 -0
- package/src/apothem/harnesses/README.md +63 -0
- package/src/apothem/harnesses/__init__.py +16 -0
- package/src/apothem/harnesses/_shared/README.md +36 -0
- package/src/apothem/harnesses/_shared/__init__.py +12 -0
- package/src/apothem/harnesses/_shared/install_driver.py +281 -0
- package/src/apothem/harnesses/_shared/install_driver_apply.py +612 -0
- package/src/apothem/harnesses/_shared/install_driver_backup.py +535 -0
- package/src/apothem/harnesses/_shared/install_driver_converters.py +310 -0
- package/src/apothem/harnesses/_shared/install_driver_lifecycle.py +495 -0
- package/src/apothem/harnesses/_shared/install_driver_materialize.py +675 -0
- package/src/apothem/harnesses/_shared/install_driver_merge.py +656 -0
- package/src/apothem/harnesses/_shared/install_driver_pathsafety.py +137 -0
- package/src/apothem/harnesses/_shared/install_driver_planvalidation.py +240 -0
- package/src/apothem/harnesses/_shared/install_driver_removal.py +366 -0
- package/src/apothem/harnesses/_shared/install_driver_treeops.py +248 -0
- package/src/apothem/harnesses/_shared/install_driver_types.py +330 -0
- package/src/apothem/harnesses/_shared/wrapper_factories.py +448 -0
- package/src/apothem/harnesses/antigravity/STANDARD-CONVENTION-PIN.md +91 -0
- package/src/apothem/harnesses/antigravity/__init__.py +70 -0
- package/src/apothem/harnesses/antigravity/capabilities.yml +40 -0
- package/src/apothem/harnesses/antigravity/install.py +63 -0
- package/src/apothem/harnesses/antigravity/templates/GEMINI.md +40 -0
- package/src/apothem/harnesses/antigravity/templates/plugin.json +5 -0
- package/src/apothem/harnesses/antigravity/uninstall.py +22 -0
- package/src/apothem/harnesses/antigravity/update.py +10 -0
- package/src/apothem/harnesses/antigravity/verify.py +11 -0
- package/src/apothem/harnesses/claude_code/STANDARD-CONVENTION-PIN.md +65 -0
- package/src/apothem/harnesses/claude_code/__init__.py +107 -0
- package/src/apothem/harnesses/claude_code/capabilities.yml +42 -0
- package/src/apothem/harnesses/claude_code/install.py +147 -0
- package/src/apothem/harnesses/claude_code/templates/settings.json +351 -0
- package/src/apothem/harnesses/claude_code/uninstall.py +23 -0
- package/src/apothem/harnesses/claude_code/update.py +10 -0
- package/src/apothem/harnesses/claude_code/verify.py +11 -0
- package/src/apothem/harnesses/codebuddy/STANDARD-CONVENTION-PIN.md +74 -0
- package/src/apothem/harnesses/codebuddy/__init__.py +49 -0
- package/src/apothem/harnesses/codebuddy/capabilities.yml +34 -0
- package/src/apothem/harnesses/codebuddy/install.py +40 -0
- package/src/apothem/harnesses/codebuddy/templates/apothem-rules.md +37 -0
- package/src/apothem/harnesses/codebuddy/uninstall.py +25 -0
- package/src/apothem/harnesses/codebuddy/update.py +10 -0
- package/src/apothem/harnesses/codebuddy/verify.py +11 -0
- package/src/apothem/harnesses/codex/STANDARD-CONVENTION-PIN.md +79 -0
- package/src/apothem/harnesses/codex/__init__.py +72 -0
- package/src/apothem/harnesses/codex/capabilities.yml +40 -0
- package/src/apothem/harnesses/codex/install.py +69 -0
- package/src/apothem/harnesses/codex/templates/AGENTS.md +40 -0
- package/src/apothem/harnesses/codex/templates/hooks.json +127 -0
- package/src/apothem/harnesses/codex/uninstall.py +23 -0
- package/src/apothem/harnesses/codex/update.py +10 -0
- package/src/apothem/harnesses/codex/verify.py +11 -0
- package/src/apothem/harnesses/cursor/STANDARD-CONVENTION-PIN.md +79 -0
- package/src/apothem/harnesses/cursor/__init__.py +48 -0
- package/src/apothem/harnesses/cursor/capabilities.yml +42 -0
- package/src/apothem/harnesses/cursor/install.py +38 -0
- package/src/apothem/harnesses/cursor/templates/apothem-rules.mdc +40 -0
- package/src/apothem/harnesses/cursor/uninstall.py +25 -0
- package/src/apothem/harnesses/cursor/update.py +10 -0
- package/src/apothem/harnesses/cursor/verify.py +11 -0
- package/src/apothem/harnesses/gemini_cli/STANDARD-CONVENTION-PIN.md +102 -0
- package/src/apothem/harnesses/gemini_cli/__init__.py +52 -0
- package/src/apothem/harnesses/gemini_cli/capabilities.yml +43 -0
- package/src/apothem/harnesses/gemini_cli/install.py +43 -0
- package/src/apothem/harnesses/gemini_cli/templates/GEMINI.md +38 -0
- package/src/apothem/harnesses/gemini_cli/uninstall.py +25 -0
- package/src/apothem/harnesses/gemini_cli/update.py +10 -0
- package/src/apothem/harnesses/gemini_cli/verify.py +11 -0
- package/src/apothem/harnesses/github_copilot/STANDARD-CONVENTION-PIN.md +84 -0
- package/src/apothem/harnesses/github_copilot/__init__.py +47 -0
- package/src/apothem/harnesses/github_copilot/capabilities.yml +42 -0
- package/src/apothem/harnesses/github_copilot/install.py +40 -0
- package/src/apothem/harnesses/github_copilot/templates/copilot-instructions.md +33 -0
- package/src/apothem/harnesses/github_copilot/uninstall.py +25 -0
- package/src/apothem/harnesses/github_copilot/update.py +10 -0
- package/src/apothem/harnesses/github_copilot/verify.py +11 -0
- package/src/apothem/harnesses/glm/STANDARD-CONVENTION-PIN.md +77 -0
- package/src/apothem/harnesses/glm/__init__.py +56 -0
- package/src/apothem/harnesses/glm/capabilities.yml +33 -0
- package/src/apothem/harnesses/glm/install.py +45 -0
- package/src/apothem/harnesses/glm/templates/glm.toml +58 -0
- package/src/apothem/harnesses/glm/uninstall.py +25 -0
- package/src/apothem/harnesses/glm/update.py +10 -0
- package/src/apothem/harnesses/glm/verify.py +11 -0
- package/src/apothem/harnesses/hermes/STANDARD-CONVENTION-PIN.md +57 -0
- package/src/apothem/harnesses/hermes/__init__.py +33 -0
- package/src/apothem/harnesses/hermes/capabilities.yml +36 -0
- package/src/apothem/harnesses/hermes/install.py +17 -0
- package/src/apothem/harnesses/hermes/materializer.py +35 -0
- package/src/apothem/harnesses/hermes/uninstall.py +33 -0
- package/src/apothem/harnesses/hermes/update.py +10 -0
- package/src/apothem/harnesses/hermes/verify.py +11 -0
- package/src/apothem/harnesses/kimi_code/STANDARD-CONVENTION-PIN.md +128 -0
- package/src/apothem/harnesses/kimi_code/__init__.py +59 -0
- package/src/apothem/harnesses/kimi_code/capabilities.yml +40 -0
- package/src/apothem/harnesses/kimi_code/install.py +42 -0
- package/src/apothem/harnesses/kimi_code/templates/AGENTS.md +43 -0
- package/src/apothem/harnesses/kimi_code/uninstall.py +27 -0
- package/src/apothem/harnesses/kimi_code/update.py +10 -0
- package/src/apothem/harnesses/kimi_code/verify.py +11 -0
- package/src/apothem/harnesses/kiro/STANDARD-CONVENTION-PIN.md +77 -0
- package/src/apothem/harnesses/kiro/__init__.py +49 -0
- package/src/apothem/harnesses/kiro/capabilities.yml +36 -0
- package/src/apothem/harnesses/kiro/install.py +39 -0
- package/src/apothem/harnesses/kiro/templates/apothem-rules.md +36 -0
- package/src/apothem/harnesses/kiro/uninstall.py +25 -0
- package/src/apothem/harnesses/kiro/update.py +10 -0
- package/src/apothem/harnesses/kiro/verify.py +11 -0
- package/src/apothem/harnesses/open_claw/STANDARD-CONVENTION-PIN.md +62 -0
- package/src/apothem/harnesses/open_claw/__init__.py +35 -0
- package/src/apothem/harnesses/open_claw/capabilities.yml +35 -0
- package/src/apothem/harnesses/open_claw/install.py +17 -0
- package/src/apothem/harnesses/open_claw/materializer.py +36 -0
- package/src/apothem/harnesses/open_claw/uninstall.py +32 -0
- package/src/apothem/harnesses/open_claw/update.py +10 -0
- package/src/apothem/harnesses/open_claw/verify.py +11 -0
- package/src/apothem/harnesses/opencode/STANDARD-CONVENTION-PIN.md +76 -0
- package/src/apothem/harnesses/opencode/__init__.py +35 -0
- package/src/apothem/harnesses/opencode/capabilities.yml +43 -0
- package/src/apothem/harnesses/opencode/install.py +17 -0
- package/src/apothem/harnesses/opencode/materializer.py +31 -0
- package/src/apothem/harnesses/opencode/uninstall.py +34 -0
- package/src/apothem/harnesses/opencode/update.py +10 -0
- package/src/apothem/harnesses/opencode/verify.py +11 -0
- package/src/apothem/harnesses/qwen_code/STANDARD-CONVENTION-PIN.md +87 -0
- package/src/apothem/harnesses/qwen_code/__init__.py +37 -0
- package/src/apothem/harnesses/qwen_code/capabilities.yml +43 -0
- package/src/apothem/harnesses/qwen_code/install.py +19 -0
- package/src/apothem/harnesses/qwen_code/materializer.py +174 -0
- package/src/apothem/harnesses/qwen_code/templates/QWEN.md +30 -0
- package/src/apothem/harnesses/qwen_code/uninstall.py +34 -0
- package/src/apothem/harnesses/qwen_code/update.py +10 -0
- package/src/apothem/harnesses/qwen_code/verify.py +11 -0
- package/src/apothem/harnesses/trae/STANDARD-CONVENTION-PIN.md +70 -0
- package/src/apothem/harnesses/trae/__init__.py +49 -0
- package/src/apothem/harnesses/trae/capabilities.yml +34 -0
- package/src/apothem/harnesses/trae/install.py +38 -0
- package/src/apothem/harnesses/trae/templates/apothem-rules.md +37 -0
- package/src/apothem/harnesses/trae/uninstall.py +25 -0
- package/src/apothem/harnesses/trae/update.py +10 -0
- package/src/apothem/harnesses/trae/verify.py +11 -0
- package/src/apothem/harnesses/windsurf/STANDARD-CONVENTION-PIN.md +91 -0
- package/src/apothem/harnesses/windsurf/__init__.py +52 -0
- package/src/apothem/harnesses/windsurf/capabilities.yml +40 -0
- package/src/apothem/harnesses/windsurf/install.py +41 -0
- package/src/apothem/harnesses/windsurf/templates/apothem-rules.md +37 -0
- package/src/apothem/harnesses/windsurf/uninstall.py +25 -0
- package/src/apothem/harnesses/windsurf/update.py +10 -0
- package/src/apothem/harnesses/windsurf/verify.py +11 -0
- package/src/apothem/harnesses/zed/STANDARD-CONVENTION-PIN.md +92 -0
- package/src/apothem/harnesses/zed/__init__.py +57 -0
- package/src/apothem/harnesses/zed/capabilities.yml +38 -0
- package/src/apothem/harnesses/zed/install.py +41 -0
- package/src/apothem/harnesses/zed/templates/apothem-rules.md +32 -0
- package/src/apothem/harnesses/zed/uninstall.py +28 -0
- package/src/apothem/harnesses/zed/update.py +10 -0
- package/src/apothem/harnesses/zed/verify.py +11 -0
- package/src/apothem/hooks/README.md +81 -0
- package/src/apothem/hooks/__init__.py +24 -0
- package/src/apothem/hooks/askuserquestion_validator.py +380 -0
- package/src/apothem/hooks/dispatch.py +296 -0
- package/src/apothem/hooks/emit_hook_context.py +444 -0
- package/src/apothem/hooks/hooks.json +318 -0
- package/src/apothem/hooks/lib/README.md +39 -0
- package/src/apothem/hooks/lib/__init__.py +18 -0
- package/src/apothem/hooks/lib/bootstrap.ps1 +129 -0
- package/src/apothem/hooks/lib/bootstrap.sh +103 -0
- package/src/apothem/hooks/lib/events.py +51 -0
- package/src/apothem/hooks/lib/find-pwsh.ps1 +78 -0
- package/src/apothem/hooks/lib/find-pwsh.sh +76 -0
- package/src/apothem/hooks/lib/find-python.ps1 +63 -0
- package/src/apothem/hooks/lib/find-python.sh +97 -0
- package/src/apothem/hooks/lib/log.py +43 -0
- package/src/apothem/hooks/lib/resolve_root.py +264 -0
- package/src/apothem/hooks/messages/postcompact.md +14 -0
- package/src/apothem/hooks/messages/posttooluse-proactive-compaction.md +46 -0
- package/src/apothem/hooks/messages/precompact.md +14 -0
- package/src/apothem/hooks/messages/pretooluse-askuserquestion-recommended.md +65 -0
- package/src/apothem/hooks/messages/pretooluse-bash-plan-guard.md +97 -0
- package/src/apothem/hooks/messages/pretooluse-bash.md +39 -0
- package/src/apothem/hooks/messages/pretooluse-conformity.md +70 -0
- package/src/apothem/hooks/messages/pretooluse-dependency-guard.md +21 -0
- package/src/apothem/hooks/messages/pretooluse-edit-header-guard.md +61 -0
- package/src/apothem/hooks/messages/pretooluse-edit.md +21 -0
- package/src/apothem/hooks/messages/pretooluse-eval-guard.md +39 -0
- package/src/apothem/hooks/messages/pretooluse-notebookedit.md +11 -0
- package/src/apothem/hooks/messages/pretooluse-write-header-guard.md +45 -0
- package/src/apothem/hooks/messages/pretooluse-write-plan-guard.md +72 -0
- package/src/apothem/hooks/messages/pretooluse-write.md +21 -0
- package/src/apothem/hooks/messages/sessionstart.md +15 -0
- package/src/apothem/hooks/messages/stop.md +27 -0
- package/src/apothem/hooks/proactive_compaction_tracker.py +327 -0
- package/src/apothem/hooks/session_start_bootstrap.py +472 -0
- package/src/apothem/lib/README.md +42 -0
- package/src/apothem/lib/__init__.py +13 -0
- package/src/apothem/lib/atomic_io.py +189 -0
- package/src/apothem/lib/auditor.py +687 -0
- package/src/apothem/lib/clean_slate.py +396 -0
- package/src/apothem/lib/contexts.py +352 -0
- package/src/apothem/lib/data_home.py +255 -0
- package/src/apothem/lib/frontmatter.py +101 -0
- package/src/apothem/lib/harness_materializer.py +213 -0
- package/src/apothem/lib/harness_protocol.py +59 -0
- package/src/apothem/lib/harness_registry.py +282 -0
- package/src/apothem/lib/harness_registry_data.py +843 -0
- package/src/apothem/lib/install_ledger.py +347 -0
- package/src/apothem/lib/learning.py +540 -0
- package/src/apothem/lib/memory.py +347 -0
- package/src/apothem/lib/parallel_sweep.py +234 -0
- package/src/apothem/lib/plan_tiers.py +200 -0
- package/src/apothem/lib/plugin_bootstrap.py +132 -0
- package/src/apothem/lib/plugin_tree.py +599 -0
- package/src/apothem/lib/profile.py +755 -0
- package/src/apothem/lib/profile_projection.py +198 -0
- package/src/apothem/lib/propagation-manifest.yaml +878 -0
- package/src/apothem/lib/propagation.py +220 -0
- package/src/apothem/lib/python_resolver.py +189 -0
- package/src/apothem/lib/reporter.py +62 -0
- package/src/apothem/lib/workspace_migration.py +323 -0
- package/src/apothem/output-styles/README.md +41 -0
- package/src/apothem/output-styles/concise-engineer.md +49 -0
- package/src/apothem/output-styles/default-architect.md +52 -0
- package/src/apothem/output-styles/default.md +113 -0
- package/src/apothem/output-styles/forensic-auditor.md +63 -0
- package/src/apothem/py.typed +0 -0
- package/src/apothem/rules/README.md +121 -0
- package/src/apothem/rules/agent-capability-discipline-matrix.md +89 -0
- package/src/apothem/rules/agent-capability-discipline.md +78 -0
- package/src/apothem/rules/agent-orchestration-patterns.md +144 -0
- package/src/apothem/rules/agent-orchestration.md +65 -0
- package/src/apothem/rules/agents-md-convention.md +86 -0
- package/src/apothem/rules/agile-sprints-elements.md +135 -0
- package/src/apothem/rules/agile-sprints.md +64 -0
- package/src/apothem/rules/agnostic-posture-checklist.md +47 -0
- package/src/apothem/rules/agnostic-posture.md +48 -0
- package/src/apothem/rules/authoritative-referencing-quotation.md +50 -0
- package/src/apothem/rules/authoritative-referencing.md +66 -0
- package/src/apothem/rules/authority-inquiry-categories.md +58 -0
- package/src/apothem/rules/authority-inquiry.md +54 -0
- package/src/apothem/rules/auto-memory-topic-files.md +86 -0
- package/src/apothem/rules/auto-memory.md +67 -0
- package/src/apothem/rules/bidirectional-binding.md +123 -0
- package/src/apothem/rules/canonical-layout-reporting-tiers.md +212 -0
- package/src/apothem/rules/canonical-layout.md +60 -0
- package/src/apothem/rules/clean-architecture-layers.md +186 -0
- package/src/apothem/rules/clean-room-generation-protocols.md +124 -0
- package/src/apothem/rules/clean-room-generation.md +59 -0
- package/src/apothem/rules/code-craft-conventions.md +101 -0
- package/src/apothem/rules/code-craft-markdown.md +138 -0
- package/src/apothem/rules/code-craft-python.md +154 -0
- package/src/apothem/rules/code-craft-shell.md +192 -0
- package/src/apothem/rules/cognitive-identity-techniques.md +180 -0
- package/src/apothem/rules/cognitive-identity.md +81 -0
- package/src/apothem/rules/context-management-budget.md +46 -0
- package/src/apothem/rules/context-management-protocol.md +161 -0
- package/src/apothem/rules/context-management-scratch.md +128 -0
- package/src/apothem/rules/context-management.md +85 -0
- package/src/apothem/rules/definitiveness-virtues.md +67 -0
- package/src/apothem/rules/definitiveness.md +58 -0
- package/src/apothem/rules/determinism.md +81 -0
- package/src/apothem/rules/disclosure-ledger-markers.md +58 -0
- package/src/apothem/rules/disclosure-ledger.md +52 -0
- package/src/apothem/rules/dynamism.md +38 -0
- package/src/apothem/rules/etc-extension.md +57 -0
- package/src/apothem/rules/expertise-posture-elements.md +68 -0
- package/src/apothem/rules/expertise-posture.md +54 -0
- package/src/apothem/rules/freshness-facade.md +64 -0
- package/src/apothem/rules/harness-adapter-shape-schemas.md +162 -0
- package/src/apothem/rules/harness-adapter-shape.md +42 -0
- package/src/apothem/rules/host-discovery-manifests.md +50 -0
- package/src/apothem/rules/host-discovery.md +56 -0
- package/src/apothem/rules/i18n-discipline-locale-cohorts.md +120 -0
- package/src/apothem/rules/i18n-discipline.md +70 -0
- package/src/apothem/rules/interactive-questions-canonical-shapes.md +590 -0
- package/src/apothem/rules/interactive-questions-detail.md +41 -0
- package/src/apothem/rules/interactive-questions-sweep-matchers.md +184 -0
- package/src/apothem/rules/interactive-questions.md +89 -0
- package/src/apothem/rules/large-file-generation.md +112 -0
- package/src/apothem/rules/large-file-reading.md +59 -0
- package/src/apothem/rules/living-docs.md +85 -0
- package/src/apothem/rules/multi-agent-workflow.md +57 -0
- package/src/apothem/rules/operational-mandates-expanded.md +78 -0
- package/src/apothem/rules/operational-mandates.md +88 -0
- package/src/apothem/rules/option-annotation-form.md +60 -0
- package/src/apothem/rules/option-annotation.md +45 -0
- package/src/apothem/rules/own-voice-reimplementation.md +86 -0
- package/src/apothem/rules/performance-discipline.md +91 -0
- package/src/apothem/rules/persistent-conventions-vigilance-checklist.md +54 -0
- package/src/apothem/rules/persistent-conventions-vigilance.md +61 -0
- package/src/apothem/rules/plain-language.md +56 -0
- package/src/apothem/rules/planning-techniques.md +130 -0
- package/src/apothem/rules/pre-emission-gate-bars.md +86 -0
- package/src/apothem/rules/pre-emission-gate.md +54 -0
- package/src/apothem/rules/production-ready-prs-surfaces.md +162 -0
- package/src/apothem/rules/production-ready-prs.md +83 -0
- package/src/apothem/rules/propagation.md +63 -0
- package/src/apothem/rules/recommend-next-step.md +106 -0
- package/src/apothem/rules/refactoring-discipline.md +76 -0
- package/src/apothem/rules/session-closure.md +44 -0
- package/src/apothem/rules/sota-elevation-exemplars.md +76 -0
- package/src/apothem/rules/sota-elevation.md +52 -0
- package/src/apothem/rules/source-accessibility.md +58 -0
- package/src/apothem/rules/surgical-manipulation.md +48 -0
- package/src/apothem/rules/systemic-participation-relations.md +108 -0
- package/src/apothem/rules/systemic-participation.md +70 -0
- package/src/apothem/rules/ten-dimension-check-dimensions.md +52 -0
- package/src/apothem/rules/ten-dimension-check.md +59 -0
- package/src/apothem/rules/token-budget-discipline.md +81 -0
- package/src/apothem/rules/token-efficiency-rewrite-protocol.md +79 -0
- package/src/apothem/rules/token-efficiency-rewrite.md +77 -0
- package/src/apothem/rules/tool-use-discipline.md +48 -0
- package/src/apothem/rules/visual-leverage.md +102 -0
- package/src/apothem/schemas/NOTICE.md +9 -0
- package/src/apothem/schemas/README.md +104 -0
- package/src/apothem/schemas/__init__.py +176 -0
- package/src/apothem/schemas/advisory-finding.schema.json +111 -0
- package/src/apothem/schemas/agent.schema.json +106 -0
- package/src/apothem/schemas/authorship-header.txt +1 -0
- package/src/apothem/schemas/cohort-manifest.yaml +248 -0
- package/src/apothem/schemas/cohort-metadata-vocabulary.yaml +168 -0
- package/src/apothem/schemas/cohort.schema.json +113 -0
- package/src/apothem/schemas/command.schema.json +68 -0
- package/src/apothem/schemas/compatibility-matrix.yaml +432 -0
- package/src/apothem/schemas/context-fragment.schema.json +64 -0
- package/src/apothem/schemas/freshness-token-denylist.txt +51 -0
- package/src/apothem/schemas/handoff-manifest.yaml +353 -0
- package/src/apothem/schemas/header-exceptions.txt +141 -0
- package/src/apothem/schemas/header-visibility.yaml +39 -0
- package/src/apothem/schemas/learning-signal.schema.json +46 -0
- package/src/apothem/schemas/memory-record.schema.json +61 -0
- package/src/apothem/schemas/output-style.schema.json +40 -0
- package/src/apothem/schemas/plan.schema.json +51 -0
- package/src/apothem/schemas/plugin.schema.json +83 -0
- package/src/apothem/schemas/profile.example.yaml +70 -0
- package/src/apothem/schemas/profile.minimal.yaml +6 -0
- package/src/apothem/schemas/profile.schema.json +396 -0
- package/src/apothem/schemas/reference-token-denylist.txt +25 -0
- package/src/apothem/schemas/skill.schema.json +75 -0
- package/src/apothem/skills/README.md +93 -0
- package/src/apothem/skills/dependency-upgrade/SKILL.md +105 -0
- package/src/apothem/skills/dev-toolkit/SKILL.md +120 -0
- package/src/apothem/skills/diagram-authoring/SKILL.md +113 -0
- package/src/apothem/skills/document-authoring/SKILL.md +118 -0
- package/src/apothem/skills/ecosystem-audit/SKILL.md +108 -0
- package/src/apothem/skills/ecosystem-audit/references/audit-fortress.md +85 -0
- package/src/apothem/skills/ecosystem-audit/references/procedure.md +162 -0
- package/src/apothem/skills/eval-harness/SKILL.md +88 -0
- package/src/apothem/skills/incident-runbook/SKILL.md +92 -0
- package/src/apothem/skills/multi-source-research/SKILL.md +90 -0
- package/src/apothem/skills/plan-suite/SKILL.md +118 -0
- package/src/apothem/skills/plan-suite/master_template.md +1324 -0
- package/src/apothem/skills/projectify/SKILL.md +117 -0
- package/src/apothem/skills/prompt-engineering/SKILL.md +122 -0
- package/src/apothem/skills/refactor-extract/SKILL.md +85 -0
- package/src/apothem/skills/research-suite/SKILL.md +170 -0
- package/src/apothem/skills/research-suite/references/directory-structure.md +47 -0
- package/src/apothem/skills/research-suite/references/lifecycle.md +67 -0
- package/src/apothem/skills/research-suite/references/principal-investigator-framework.md +37 -0
- package/src/apothem/skills/research-suite/references/rigor-mandates.md +30 -0
- package/src/apothem/skills/research-suite/research_template.md +476 -0
- package/src/apothem/skills/secret-rotation/SKILL.md +87 -0
- package/src/apothem/skills/source-synthesis/SKILL.md +92 -0
- package/src/apothem/skills/surgical-guard/SKILL.md +118 -0
- package/src/apothem/skills/test-authoring/SKILL.md +85 -0
- package/src/apothem/skills/vuln-triage/SKILL.md +91 -0
- package/src/apothem/skills/workflow/SKILL.md +139 -0
- package/src/apothem/statuslines/README.md +26 -0
- package/src/apothem/statuslines/__init__.py +20 -0
- package/src/apothem/statuslines/conformity.json +5 -0
- package/src/apothem/statuslines/render.py +334 -0
- package/src/apothem/statuslines/statusline.md +50 -0
- package/src/apothem/templates/README.md +43 -0
- package/src/apothem/templates/agents-md-template.md +80 -0
- package/src/apothem/templates/consideration-log.md +39 -0
- package/src/apothem/templates/expertise-gap-log.md +56 -0
- package/src/apothem/templates/master-index-template.md +93 -0
- package/src/apothem/templates/potency-map.md +53 -0
- package/src/apothem/templates/preservation-audit.md +60 -0
- package/src/apothem/templates/question-resolution-audit.md +52 -0
- package/src/apothem/templates/trace-matrix-template.md +77 -0
|
@@ -0,0 +1,675 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
"""Install dispatch and the run_install orchestration entrypoint."""
|
|
4
|
+
|
|
5
|
+
from __future__ import annotations
|
|
6
|
+
|
|
7
|
+
import contextlib
|
|
8
|
+
import json
|
|
9
|
+
from collections.abc import Callable
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from typing import Any, Final
|
|
12
|
+
|
|
13
|
+
from apothem.harnesses._shared import install_driver
|
|
14
|
+
from apothem.lib import atomic_io, install_ledger
|
|
15
|
+
from apothem.lib.data_home import resolve_install_data_home
|
|
16
|
+
from apothem.lib.install_ledger import LedgerRecord
|
|
17
|
+
from apothem.lib.propagation import (
|
|
18
|
+
HarnessRules,
|
|
19
|
+
InstallEntry,
|
|
20
|
+
resolve_target,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
from .install_driver_apply import (
|
|
24
|
+
_COHORT_DOC_FILES,
|
|
25
|
+
apply_codex_agents,
|
|
26
|
+
apply_command_skills,
|
|
27
|
+
apply_gemini_agents,
|
|
28
|
+
apply_gemini_commands,
|
|
29
|
+
apply_markdown_commands,
|
|
30
|
+
apply_merge_tree_entries,
|
|
31
|
+
apply_opencode_agents,
|
|
32
|
+
apply_qwen_agents,
|
|
33
|
+
apply_replace_tree,
|
|
34
|
+
apply_write_text,
|
|
35
|
+
)
|
|
36
|
+
from .install_driver_backup import _compensating_rollback, _install_lock_path
|
|
37
|
+
from .install_driver_converters import (
|
|
38
|
+
_codex_agent_text,
|
|
39
|
+
_gemini_agent_text,
|
|
40
|
+
_gemini_command_text,
|
|
41
|
+
_generated_skill_text,
|
|
42
|
+
_native_markdown_command_text,
|
|
43
|
+
_opencode_agent_text,
|
|
44
|
+
_qwen_agent_text,
|
|
45
|
+
)
|
|
46
|
+
from .install_driver_merge import (
|
|
47
|
+
_merged_json_text,
|
|
48
|
+
_operator_owned_preview,
|
|
49
|
+
apply_sentinel_merge,
|
|
50
|
+
render_content_tokens,
|
|
51
|
+
)
|
|
52
|
+
from .install_driver_pathsafety import _allowed_write_root, _root_for
|
|
53
|
+
from .install_driver_planvalidation import (
|
|
54
|
+
_projected_profile_body,
|
|
55
|
+
_validate_install_plan,
|
|
56
|
+
make_ignore,
|
|
57
|
+
)
|
|
58
|
+
from .install_driver_treeops import (
|
|
59
|
+
_directory_contents_equal,
|
|
60
|
+
_single_file_directory_matches,
|
|
61
|
+
sweep_stale,
|
|
62
|
+
)
|
|
63
|
+
from .install_driver_types import (
|
|
64
|
+
AuthorizeFn,
|
|
65
|
+
IgnoreFn,
|
|
66
|
+
MaterializationError,
|
|
67
|
+
MaterializationOutcome,
|
|
68
|
+
MaterializationResult,
|
|
69
|
+
MaterializationRun,
|
|
70
|
+
_is_excluded_path,
|
|
71
|
+
_result,
|
|
72
|
+
_with_detail,
|
|
73
|
+
resolve_source,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def _capability_projection_results(harness_name: str) -> list[MaterializationResult]:
|
|
78
|
+
"""Return registry capability warnings for unsupported projection cells."""
|
|
79
|
+
from apothem.lib.harness_registry import get_harness_entry
|
|
80
|
+
|
|
81
|
+
try:
|
|
82
|
+
entry = get_harness_entry(harness_name)
|
|
83
|
+
except KeyError:
|
|
84
|
+
return []
|
|
85
|
+
results: list[MaterializationResult] = []
|
|
86
|
+
for capability in sorted(entry.capability_status):
|
|
87
|
+
status = entry.capability_status[capability]
|
|
88
|
+
if status not in {"unsupported", "discovery-pending"}:
|
|
89
|
+
continue
|
|
90
|
+
rationale = entry.unsupported_rationale.get(
|
|
91
|
+
capability,
|
|
92
|
+
f"{capability} is not projected for {entry.public_id}.",
|
|
93
|
+
)
|
|
94
|
+
results.append(
|
|
95
|
+
MaterializationResult(
|
|
96
|
+
outcome="warning",
|
|
97
|
+
operation="capability_projection",
|
|
98
|
+
path=entry.capabilities_path,
|
|
99
|
+
message=rationale,
|
|
100
|
+
detail={"capability": capability, "status": status},
|
|
101
|
+
)
|
|
102
|
+
)
|
|
103
|
+
return results
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
#: The uniform message every dry-run result carries. A dry run writes nothing,
|
|
107
|
+
#: so the message states only that; the prospective ``outcome`` word
|
|
108
|
+
#: (``created`` / ``updated`` / ``unchanged``) carries the would-this-change
|
|
109
|
+
#: distinction, exactly as the stale-sweep dry-run results already do.
|
|
110
|
+
_DRY_RUN_MESSAGE: Final[str] = "dry run: no filesystem changes made"
|
|
111
|
+
|
|
112
|
+
#: Per-file directory modes whose native target keeps the source basename and
|
|
113
|
+
#: whose body is a pure (source_path -> text) conversion. ``gemini_commands``
|
|
114
|
+
#: is excluded — it renames to a ``.toml`` target and is handled inline.
|
|
115
|
+
_NATIVE_FILE_CONVERTERS: Final[dict[str, Callable[[Path], str]]] = {
|
|
116
|
+
"gemini_agents": _gemini_agent_text,
|
|
117
|
+
"opencode_agents": _opencode_agent_text,
|
|
118
|
+
"qwen_agents": _qwen_agent_text,
|
|
119
|
+
"markdown_commands": _native_markdown_command_text,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _prospective_file_outcome(target: Path, content: bytes) -> MaterializationOutcome:
|
|
124
|
+
"""Classify the no-write outcome of writing *content* to *target*.
|
|
125
|
+
|
|
126
|
+
Mirrors the create / update / no-op decision
|
|
127
|
+
:func:`install_driver_backup.write_bytes_safely` makes at write time —
|
|
128
|
+
absent target → ``created``; on-disk bytes equal → ``unchanged``; on-disk
|
|
129
|
+
bytes differ → ``updated`` — without touching the filesystem.
|
|
130
|
+
"""
|
|
131
|
+
if not target.exists():
|
|
132
|
+
return "created"
|
|
133
|
+
try:
|
|
134
|
+
return "unchanged" if target.read_bytes() == content else "updated"
|
|
135
|
+
except OSError:
|
|
136
|
+
# An unreadable existing target would be backed up and overwritten.
|
|
137
|
+
return "updated"
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def _aggregate_dir_outcome(
|
|
141
|
+
child_outcomes: list[MaterializationOutcome], *, target_dir: Path
|
|
142
|
+
) -> MaterializationOutcome:
|
|
143
|
+
"""Fold a directory entry's per-child outcomes into one entry outcome.
|
|
144
|
+
|
|
145
|
+
Every child unchanged (or an empty source directory) → the whole entry is
|
|
146
|
+
``unchanged``. Otherwise the entry reports ``created`` when its target
|
|
147
|
+
directory does not yet exist (a fresh install) and ``updated`` when it
|
|
148
|
+
exists but its contents would change.
|
|
149
|
+
"""
|
|
150
|
+
if not child_outcomes or all(outcome == "unchanged" for outcome in child_outcomes):
|
|
151
|
+
return "unchanged"
|
|
152
|
+
return "created" if not target_dir.exists() else "updated"
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def _prospective_child_outcomes(
|
|
156
|
+
entry: InstallEntry,
|
|
157
|
+
*,
|
|
158
|
+
src: Path,
|
|
159
|
+
dst: Path,
|
|
160
|
+
ignore: IgnoreFn,
|
|
161
|
+
exclude: list[str],
|
|
162
|
+
root: Path,
|
|
163
|
+
harness_root: Path | None,
|
|
164
|
+
project_root: Path | None,
|
|
165
|
+
harness_name: str,
|
|
166
|
+
) -> list[MaterializationOutcome]:
|
|
167
|
+
"""Classify each child of a per-file directory mode without writing.
|
|
168
|
+
|
|
169
|
+
Each branch mirrors the matching ``apply_*`` function in
|
|
170
|
+
:mod:`install_driver_apply` — the same source enumeration, the same
|
|
171
|
+
cohort-doc exclusion, the same native-text conversion — so the no-write
|
|
172
|
+
classification tracks what the real install would decide.
|
|
173
|
+
"""
|
|
174
|
+
outcomes: list[MaterializationOutcome] = []
|
|
175
|
+
if entry.mode == "merge_tree_entries":
|
|
176
|
+
for source_path in sorted(src.iterdir()):
|
|
177
|
+
if _is_excluded_path(source_path, exclude):
|
|
178
|
+
continue
|
|
179
|
+
if source_path.name in ignore(str(src), [source_path.name]):
|
|
180
|
+
continue
|
|
181
|
+
target = dst / source_path.name
|
|
182
|
+
if source_path.is_dir():
|
|
183
|
+
if _directory_contents_equal(source_path, target, ignore):
|
|
184
|
+
outcomes.append("unchanged")
|
|
185
|
+
else:
|
|
186
|
+
outcomes.append("updated" if target.exists() else "created")
|
|
187
|
+
elif source_path.is_file():
|
|
188
|
+
data = source_path.read_bytes()
|
|
189
|
+
if b"${" in data:
|
|
190
|
+
with contextlib.suppress(UnicodeDecodeError):
|
|
191
|
+
data = render_content_tokens(
|
|
192
|
+
data.decode("utf-8"),
|
|
193
|
+
harness_root=harness_root,
|
|
194
|
+
project_root=project_root,
|
|
195
|
+
).encode("utf-8")
|
|
196
|
+
outcomes.append(_prospective_file_outcome(target, data))
|
|
197
|
+
return outcomes
|
|
198
|
+
for source_path in sorted(src.glob("*.md")):
|
|
199
|
+
if source_path.name in _COHORT_DOC_FILES:
|
|
200
|
+
continue
|
|
201
|
+
if entry.mode == "command_skills":
|
|
202
|
+
skill_dir = dst / source_path.stem
|
|
203
|
+
content = _generated_skill_text(
|
|
204
|
+
source_path, harness_name=harness_name, install_root=root
|
|
205
|
+
)
|
|
206
|
+
if _single_file_directory_matches(skill_dir, "SKILL.md", content):
|
|
207
|
+
outcomes.append("unchanged")
|
|
208
|
+
else:
|
|
209
|
+
outcomes.append("updated" if skill_dir.exists() else "created")
|
|
210
|
+
continue
|
|
211
|
+
if entry.mode == "codex_agents":
|
|
212
|
+
target = dst / f"{source_path.stem}.toml"
|
|
213
|
+
outcome = _prospective_file_outcome(
|
|
214
|
+
target, _codex_agent_text(source_path).encode("utf-8")
|
|
215
|
+
)
|
|
216
|
+
# A stale ``.md`` from a prior layout is removed before the ``.toml``
|
|
217
|
+
# is written, so its presence makes the child a change even when the
|
|
218
|
+
# rendered ``.toml`` already matches.
|
|
219
|
+
if outcome == "unchanged" and (dst / source_path.name).exists():
|
|
220
|
+
outcome = "updated"
|
|
221
|
+
outcomes.append(outcome)
|
|
222
|
+
continue
|
|
223
|
+
if entry.mode == "gemini_commands":
|
|
224
|
+
outcomes.append(
|
|
225
|
+
_prospective_file_outcome(
|
|
226
|
+
dst / f"{source_path.stem}.toml",
|
|
227
|
+
_gemini_command_text(source_path).encode("utf-8"),
|
|
228
|
+
)
|
|
229
|
+
)
|
|
230
|
+
continue
|
|
231
|
+
converter = _NATIVE_FILE_CONVERTERS.get(entry.mode)
|
|
232
|
+
if converter is not None:
|
|
233
|
+
outcomes.append(
|
|
234
|
+
_prospective_file_outcome(
|
|
235
|
+
dst / source_path.name, converter(source_path).encode("utf-8")
|
|
236
|
+
)
|
|
237
|
+
)
|
|
238
|
+
return outcomes
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def _prospective_entry_outcome(
|
|
242
|
+
entry: InstallEntry,
|
|
243
|
+
*,
|
|
244
|
+
target: Path,
|
|
245
|
+
src: Path,
|
|
246
|
+
ignore: IgnoreFn,
|
|
247
|
+
exclude: list[str],
|
|
248
|
+
root: Path,
|
|
249
|
+
harness_root: Path | None,
|
|
250
|
+
project_root: Path | None,
|
|
251
|
+
harness_name: str,
|
|
252
|
+
) -> MaterializationOutcome:
|
|
253
|
+
"""Classify an Apothem-owned ``write_text`` or any tree entry, no writes.
|
|
254
|
+
|
|
255
|
+
Operator-owned ``write_text`` / ``sentinel_merge`` entries route through
|
|
256
|
+
:func:`_operator_owned_preview` instead (it also yields the unified diff);
|
|
257
|
+
this covers the Apothem-owned ``write_text`` direct copy and every directory
|
|
258
|
+
mode. The plan validator guarantees each source exists.
|
|
259
|
+
"""
|
|
260
|
+
if entry.mode == "write_text":
|
|
261
|
+
content = render_content_tokens(
|
|
262
|
+
src.read_text(encoding="utf-8"),
|
|
263
|
+
harness_root=harness_root,
|
|
264
|
+
project_root=project_root,
|
|
265
|
+
)
|
|
266
|
+
if target.suffix.lower() == ".json" and target.exists():
|
|
267
|
+
with contextlib.suppress(json.JSONDecodeError, OSError):
|
|
268
|
+
content = _merged_json_text(target, content, prefer_existing=True)
|
|
269
|
+
return _prospective_file_outcome(target, content.encode("utf-8"))
|
|
270
|
+
if entry.mode == "replace_tree":
|
|
271
|
+
if target.exists() and _directory_contents_equal(src, target, ignore):
|
|
272
|
+
return "unchanged"
|
|
273
|
+
return "updated" if target.exists() else "created"
|
|
274
|
+
return _aggregate_dir_outcome(
|
|
275
|
+
_prospective_child_outcomes(
|
|
276
|
+
entry,
|
|
277
|
+
src=src,
|
|
278
|
+
dst=target,
|
|
279
|
+
ignore=ignore,
|
|
280
|
+
exclude=exclude,
|
|
281
|
+
root=root,
|
|
282
|
+
harness_root=harness_root,
|
|
283
|
+
project_root=project_root,
|
|
284
|
+
harness_name=harness_name,
|
|
285
|
+
),
|
|
286
|
+
target_dir=target,
|
|
287
|
+
)
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _dry_run_results(
|
|
291
|
+
rules: HarnessRules,
|
|
292
|
+
*,
|
|
293
|
+
root: Path,
|
|
294
|
+
harness_root: Path | None,
|
|
295
|
+
project_root: Path | None,
|
|
296
|
+
harness_name: str,
|
|
297
|
+
profile_body: str | None,
|
|
298
|
+
) -> list[MaterializationResult]:
|
|
299
|
+
"""Return prospective no-write results for the validated plan.
|
|
300
|
+
|
|
301
|
+
Each install entry is classified against its current on-disk target —
|
|
302
|
+
``created`` (target absent), ``updated`` (target present and differing), or
|
|
303
|
+
``unchanged`` (target present and already matching) — by mirroring what the
|
|
304
|
+
matching ``apply_*`` function would decide, without touching the filesystem.
|
|
305
|
+
A re-preview after install therefore reports the unchanged targets as no-ops
|
|
306
|
+
instead of phantom writes. The plan validator has already run, so every
|
|
307
|
+
entry's source exists; *profile_body* is folded into ``sentinel_merge``
|
|
308
|
+
anchors so their classification matches the projected managed block.
|
|
309
|
+
"""
|
|
310
|
+
ignore = make_ignore(rules.exclude, rules.per_directory_filters)
|
|
311
|
+
results: list[MaterializationResult] = []
|
|
312
|
+
for legacy in rules.stale_sweep:
|
|
313
|
+
stale = root / legacy
|
|
314
|
+
results.append(
|
|
315
|
+
_result(
|
|
316
|
+
"skipped" if stale.exists() else "unchanged",
|
|
317
|
+
"sweep_stale",
|
|
318
|
+
stale,
|
|
319
|
+
_DRY_RUN_MESSAGE,
|
|
320
|
+
)
|
|
321
|
+
)
|
|
322
|
+
for entry in rules.install:
|
|
323
|
+
target = resolve_target(
|
|
324
|
+
entry.target,
|
|
325
|
+
harness_root=harness_root,
|
|
326
|
+
project_root=project_root,
|
|
327
|
+
)
|
|
328
|
+
src = resolve_source(entry.source)
|
|
329
|
+
detail: dict[str, str] = {"ownership_class": entry.ownership_class}
|
|
330
|
+
outcome: MaterializationOutcome
|
|
331
|
+
operator_owned_write = entry.mode == "sentinel_merge" or (
|
|
332
|
+
entry.mode == "write_text" and entry.ownership_class == "operator-owned"
|
|
333
|
+
)
|
|
334
|
+
if operator_owned_write:
|
|
335
|
+
preview = _operator_owned_preview(
|
|
336
|
+
entry,
|
|
337
|
+
harness_root=harness_root,
|
|
338
|
+
project_root=project_root,
|
|
339
|
+
profile_body=profile_body,
|
|
340
|
+
)
|
|
341
|
+
if preview is None:
|
|
342
|
+
outcome = "skipped"
|
|
343
|
+
else:
|
|
344
|
+
target, outcome, diff, gate_required = preview
|
|
345
|
+
if entry.ownership_class == "operator-owned":
|
|
346
|
+
if diff:
|
|
347
|
+
detail["diff"] = diff
|
|
348
|
+
if gate_required:
|
|
349
|
+
detail["destructive_gate"] = "required"
|
|
350
|
+
else:
|
|
351
|
+
outcome = _prospective_entry_outcome(
|
|
352
|
+
entry,
|
|
353
|
+
target=target,
|
|
354
|
+
src=src,
|
|
355
|
+
ignore=ignore,
|
|
356
|
+
exclude=rules.exclude,
|
|
357
|
+
root=root,
|
|
358
|
+
harness_root=harness_root,
|
|
359
|
+
project_root=project_root,
|
|
360
|
+
harness_name=harness_name,
|
|
361
|
+
)
|
|
362
|
+
results.append(
|
|
363
|
+
_with_detail(
|
|
364
|
+
_result(outcome, entry.mode, target, _DRY_RUN_MESSAGE, source=src),
|
|
365
|
+
detail,
|
|
366
|
+
)
|
|
367
|
+
)
|
|
368
|
+
return results
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def _dispatch_install_entry(
|
|
372
|
+
entry: InstallEntry,
|
|
373
|
+
ignore: IgnoreFn,
|
|
374
|
+
rules: HarnessRules,
|
|
375
|
+
*,
|
|
376
|
+
harness_root: Path | None,
|
|
377
|
+
project_root: Path | None,
|
|
378
|
+
harness_name: str,
|
|
379
|
+
authorize: AuthorizeFn | None = None,
|
|
380
|
+
profile_body: str | None = None,
|
|
381
|
+
) -> list[MaterializationResult]:
|
|
382
|
+
"""Apply one validated install entry and return structured results."""
|
|
383
|
+
if entry.mode == "write_text":
|
|
384
|
+
return apply_write_text(
|
|
385
|
+
entry,
|
|
386
|
+
harness_root=harness_root,
|
|
387
|
+
project_root=project_root,
|
|
388
|
+
harness_name=harness_name,
|
|
389
|
+
authorize=authorize,
|
|
390
|
+
)
|
|
391
|
+
if entry.mode == "sentinel_merge":
|
|
392
|
+
return apply_sentinel_merge(
|
|
393
|
+
entry,
|
|
394
|
+
harness_root=harness_root,
|
|
395
|
+
project_root=project_root,
|
|
396
|
+
harness_name=harness_name,
|
|
397
|
+
authorize=authorize,
|
|
398
|
+
profile_body=profile_body,
|
|
399
|
+
)
|
|
400
|
+
if entry.mode == "replace_tree":
|
|
401
|
+
return apply_replace_tree(
|
|
402
|
+
entry,
|
|
403
|
+
ignore,
|
|
404
|
+
harness_root=harness_root,
|
|
405
|
+
project_root=project_root,
|
|
406
|
+
harness_name=harness_name,
|
|
407
|
+
)
|
|
408
|
+
if entry.mode == "merge_tree_entries":
|
|
409
|
+
return apply_merge_tree_entries(
|
|
410
|
+
entry,
|
|
411
|
+
ignore,
|
|
412
|
+
rules.exclude,
|
|
413
|
+
harness_root=harness_root,
|
|
414
|
+
project_root=project_root,
|
|
415
|
+
harness_name=harness_name,
|
|
416
|
+
)
|
|
417
|
+
if entry.mode == "command_skills":
|
|
418
|
+
return apply_command_skills(
|
|
419
|
+
entry,
|
|
420
|
+
harness_root=harness_root,
|
|
421
|
+
project_root=project_root,
|
|
422
|
+
harness_name=harness_name,
|
|
423
|
+
)
|
|
424
|
+
if entry.mode == "codex_agents":
|
|
425
|
+
return apply_codex_agents(
|
|
426
|
+
entry,
|
|
427
|
+
harness_root=harness_root,
|
|
428
|
+
project_root=project_root,
|
|
429
|
+
harness_name=harness_name,
|
|
430
|
+
)
|
|
431
|
+
if entry.mode == "gemini_agents":
|
|
432
|
+
return apply_gemini_agents(
|
|
433
|
+
entry,
|
|
434
|
+
harness_root=harness_root,
|
|
435
|
+
project_root=project_root,
|
|
436
|
+
harness_name=harness_name,
|
|
437
|
+
)
|
|
438
|
+
if entry.mode == "opencode_agents":
|
|
439
|
+
return apply_opencode_agents(
|
|
440
|
+
entry,
|
|
441
|
+
harness_root=harness_root,
|
|
442
|
+
project_root=project_root,
|
|
443
|
+
harness_name=harness_name,
|
|
444
|
+
)
|
|
445
|
+
if entry.mode == "qwen_agents":
|
|
446
|
+
return apply_qwen_agents(
|
|
447
|
+
entry,
|
|
448
|
+
harness_root=harness_root,
|
|
449
|
+
project_root=project_root,
|
|
450
|
+
harness_name=harness_name,
|
|
451
|
+
)
|
|
452
|
+
if entry.mode == "gemini_commands":
|
|
453
|
+
return apply_gemini_commands(
|
|
454
|
+
entry,
|
|
455
|
+
harness_root=harness_root,
|
|
456
|
+
project_root=project_root,
|
|
457
|
+
harness_name=harness_name,
|
|
458
|
+
)
|
|
459
|
+
if entry.mode == "markdown_commands":
|
|
460
|
+
return apply_markdown_commands(
|
|
461
|
+
entry,
|
|
462
|
+
harness_root=harness_root,
|
|
463
|
+
project_root=project_root,
|
|
464
|
+
harness_name=harness_name,
|
|
465
|
+
)
|
|
466
|
+
raise ValueError(
|
|
467
|
+
f"unknown install entry mode '{entry.mode}' for source '{entry.source}'"
|
|
468
|
+
)
|
|
469
|
+
|
|
470
|
+
|
|
471
|
+
def _materialize_data_surfaces(
|
|
472
|
+
harness_name: str, root: Path, *, profile: dict[str, Any] | None = None
|
|
473
|
+
) -> list[MaterializationResult]:
|
|
474
|
+
"""Materialize the shared memory, contexts, and learning data surfaces.
|
|
475
|
+
|
|
476
|
+
Every target sharing *root* resolves to the SAME Apothem-owned working
|
|
477
|
+
directory (``<base>/.apothem/``, where *base* is derived from the profile's
|
|
478
|
+
``workspace`` block) — seeded with an empty memory store, an empty contexts
|
|
479
|
+
store, and an empty learning store so the surfaces exist as concrete
|
|
480
|
+
artifacts after install. The seed is idempotent and non-destructive: an
|
|
481
|
+
operator's accumulated records, fragments, and captured learning signals are
|
|
482
|
+
never overwritten, so a re-install — or a second harness installing into the
|
|
483
|
+
same base — preserves them and reports ``unchanged``. Because the home is
|
|
484
|
+
shared, a write under one target is visible to every other target sharing
|
|
485
|
+
the base.
|
|
486
|
+
|
|
487
|
+
Seeding the learning surface captures nothing — it only creates the empty
|
|
488
|
+
store. Continuous-learning capture stays default-off: it activates only
|
|
489
|
+
when the operator sets ``enforcement.learning_loop`` and is gated at
|
|
490
|
+
:func:`apothem.lib.learning.capture`.
|
|
491
|
+
|
|
492
|
+
Args:
|
|
493
|
+
harness_name: The harness identifier whose install pass triggered the
|
|
494
|
+
materialization. Retained for the result message only — the home is
|
|
495
|
+
shared, not keyed by this identifier.
|
|
496
|
+
root: The install root (harness root or project root) the shared
|
|
497
|
+
working directory is anchored to under project-local scope.
|
|
498
|
+
profile: The install profile dict carrying the ``workspace`` block, or
|
|
499
|
+
``None`` for the non-interactive path (project-local ``.apothem``).
|
|
500
|
+
|
|
501
|
+
Returns:
|
|
502
|
+
One materialization result per data surface (memory, contexts,
|
|
503
|
+
learning). An OS-level failure is reported as a ``warning`` result
|
|
504
|
+
rather than aborting the surrounding install pass.
|
|
505
|
+
"""
|
|
506
|
+
from apothem.lib.contexts import ContextStore
|
|
507
|
+
from apothem.lib.learning import LearningStore
|
|
508
|
+
from apothem.lib.memory import MemoryStore
|
|
509
|
+
|
|
510
|
+
home_spec = resolve_install_data_home(root, profile=profile)
|
|
511
|
+
preexisting = home_spec.root.exists()
|
|
512
|
+
outcome: MaterializationOutcome = "unchanged" if preexisting else "created"
|
|
513
|
+
try:
|
|
514
|
+
home = home_spec.ensure()
|
|
515
|
+
memory_path = MemoryStore(home).ensure_initialized()
|
|
516
|
+
contexts_path = ContextStore(home).ensure_initialized()
|
|
517
|
+
learning_path = LearningStore(home).ensure_initialized()
|
|
518
|
+
except OSError as exc:
|
|
519
|
+
return [
|
|
520
|
+
_result(
|
|
521
|
+
"warning",
|
|
522
|
+
"data_surface",
|
|
523
|
+
home_spec.root,
|
|
524
|
+
f"could not materialize memory/contexts/learning data surfaces: {exc}",
|
|
525
|
+
)
|
|
526
|
+
]
|
|
527
|
+
return [
|
|
528
|
+
_result(
|
|
529
|
+
outcome,
|
|
530
|
+
"data_surface",
|
|
531
|
+
memory_path,
|
|
532
|
+
"materialized memory surface data home",
|
|
533
|
+
),
|
|
534
|
+
_result(
|
|
535
|
+
outcome,
|
|
536
|
+
"data_surface",
|
|
537
|
+
contexts_path,
|
|
538
|
+
"materialized contexts surface data home",
|
|
539
|
+
),
|
|
540
|
+
_result(
|
|
541
|
+
outcome,
|
|
542
|
+
"data_surface",
|
|
543
|
+
learning_path,
|
|
544
|
+
"materialized learning surface data home",
|
|
545
|
+
),
|
|
546
|
+
]
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
def run_install(
|
|
550
|
+
harness_name: str,
|
|
551
|
+
*,
|
|
552
|
+
harness_root: Path | None = None,
|
|
553
|
+
project_root: Path | None = None,
|
|
554
|
+
dry_run: bool = False,
|
|
555
|
+
authorize: AuthorizeFn | None = None,
|
|
556
|
+
profile: dict[str, Any] | None = None,
|
|
557
|
+
) -> MaterializationRun:
|
|
558
|
+
"""Propagate *harness_name*'s convention surface to its install root.
|
|
559
|
+
|
|
560
|
+
User-scope callers pass ``harness_root`` (created if absent); project-scope
|
|
561
|
+
callers pass ``project_root`` (assumed to exist). The manifest's
|
|
562
|
+
stale-sweep entries are removed first, then each install entry is applied
|
|
563
|
+
in declaration order. Destructive replacements are reversible: existing
|
|
564
|
+
targets are copied to ``~/.apothem/backups/`` before replacement or
|
|
565
|
+
stale-sweep deletion.
|
|
566
|
+
|
|
567
|
+
When *profile* is supplied, its projected managed block is folded into every
|
|
568
|
+
``sentinel_merge`` instruction anchor (alongside the template governance),
|
|
569
|
+
so the shared profile reaches the harness's instruction surface.
|
|
570
|
+
|
|
571
|
+
When *authorize* is supplied, every non-additive overwrite of an
|
|
572
|
+
operator-owned target is gated through it: returning ``False`` skips that
|
|
573
|
+
write and leaves the operator's file untouched. ``None`` (the default) is
|
|
574
|
+
the non-interactive path — operator content is merge-preserved and backed
|
|
575
|
+
up, never silently lost.
|
|
576
|
+
"""
|
|
577
|
+
rules = install_driver.load_rules(harness_name)
|
|
578
|
+
profile_body = _projected_profile_body(harness_name, profile)
|
|
579
|
+
root = _root_for(harness_root, project_root)
|
|
580
|
+
results = _capability_projection_results(harness_name)
|
|
581
|
+
errors = _validate_install_plan(
|
|
582
|
+
rules,
|
|
583
|
+
root=root,
|
|
584
|
+
harness_root=harness_root,
|
|
585
|
+
project_root=project_root,
|
|
586
|
+
)
|
|
587
|
+
if errors:
|
|
588
|
+
run = MaterializationRun(
|
|
589
|
+
harness=harness_name,
|
|
590
|
+
dry_run=dry_run,
|
|
591
|
+
results=(*results, *errors),
|
|
592
|
+
)
|
|
593
|
+
first_error = errors[0]
|
|
594
|
+
raise MaterializationError(
|
|
595
|
+
f"materialization validation failed: {first_error.message}",
|
|
596
|
+
run,
|
|
597
|
+
)
|
|
598
|
+
if dry_run:
|
|
599
|
+
return MaterializationRun(
|
|
600
|
+
harness=harness_name,
|
|
601
|
+
dry_run=True,
|
|
602
|
+
results=(
|
|
603
|
+
*results,
|
|
604
|
+
*_dry_run_results(
|
|
605
|
+
rules,
|
|
606
|
+
root=root,
|
|
607
|
+
harness_root=harness_root,
|
|
608
|
+
project_root=project_root,
|
|
609
|
+
harness_name=harness_name,
|
|
610
|
+
profile_body=profile_body,
|
|
611
|
+
),
|
|
612
|
+
),
|
|
613
|
+
)
|
|
614
|
+
if harness_root is not None:
|
|
615
|
+
harness_root.mkdir(parents=True, exist_ok=True)
|
|
616
|
+
ignore = make_ignore(rules.exclude, rules.per_directory_filters)
|
|
617
|
+
write_root = _allowed_write_root(harness_root, project_root)
|
|
618
|
+
|
|
619
|
+
# Transactional pass: serialize concurrent installs into the same
|
|
620
|
+
# (harness, root) behind one advisory lock (a different root keys a different
|
|
621
|
+
# lock and is not blocked), and on a mid-pass failure restore every target
|
|
622
|
+
# written so far from its just-captured backup before re-raising — a partial
|
|
623
|
+
# install never leaves a half-materialized tree. The lock is released on
|
|
624
|
+
# success and on exception (context-manager exit).
|
|
625
|
+
with atomic_io.advisory_lock(_install_lock_path(harness_name, root)):
|
|
626
|
+
try:
|
|
627
|
+
results.extend(
|
|
628
|
+
sweep_stale(
|
|
629
|
+
rules.stale_sweep,
|
|
630
|
+
root,
|
|
631
|
+
harness_name=harness_name,
|
|
632
|
+
allowed_root=write_root,
|
|
633
|
+
)
|
|
634
|
+
)
|
|
635
|
+
for entry in rules.install:
|
|
636
|
+
entry_results = install_driver._dispatch_install_entry(
|
|
637
|
+
entry,
|
|
638
|
+
ignore,
|
|
639
|
+
rules,
|
|
640
|
+
harness_root=harness_root,
|
|
641
|
+
project_root=project_root,
|
|
642
|
+
harness_name=harness_name,
|
|
643
|
+
authorize=authorize,
|
|
644
|
+
profile_body=profile_body,
|
|
645
|
+
)
|
|
646
|
+
results.extend(entry_results)
|
|
647
|
+
entry_errors = [
|
|
648
|
+
result for result in entry_results if result.outcome == "error"
|
|
649
|
+
]
|
|
650
|
+
if entry_errors:
|
|
651
|
+
raise MaterializationError(
|
|
652
|
+
f"materialization write failed: {entry_errors[0].message}",
|
|
653
|
+
MaterializationRun(
|
|
654
|
+
harness=harness_name,
|
|
655
|
+
dry_run=False,
|
|
656
|
+
results=tuple(results),
|
|
657
|
+
),
|
|
658
|
+
)
|
|
659
|
+
results.extend(
|
|
660
|
+
_materialize_data_surfaces(harness_name, root, profile=profile)
|
|
661
|
+
)
|
|
662
|
+
except BaseException:
|
|
663
|
+
_compensating_rollback(results, allowed_root=write_root)
|
|
664
|
+
with contextlib.suppress(Exception):
|
|
665
|
+
install_ledger.append_record(
|
|
666
|
+
LedgerRecord.create(
|
|
667
|
+
harness=harness_name, root=root, kind="rollback"
|
|
668
|
+
)
|
|
669
|
+
)
|
|
670
|
+
raise
|
|
671
|
+
return MaterializationRun(
|
|
672
|
+
harness=harness_name,
|
|
673
|
+
dry_run=False,
|
|
674
|
+
results=tuple(results),
|
|
675
|
+
)
|