@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,21 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
CM-7 codebase isolation + frontmatter compliance.
|
|
4
|
+
|
|
5
|
+
Scope. Triggered on every Write. Skip the CM-7 scan when `target` is inside the Apothem source repo or the active harness's config root (for the Claude Code harness, `~/.claude/`) — those locations are the ecosystem meta-config and are allowed to reference plan terms. Apply the scan otherwise.
|
|
6
|
+
|
|
7
|
+
CM-7 scan. Reject content containing any term in the canonical forbidden-terms block at `CLAUDE.md` §CM-7. On hit: STOP. Rewrite the offending passage in natural domain language and re-issue the Write — do not silently strip the term, since the surrounding sentence binds to the term and breaks when the term is excised without restructuring.
|
|
8
|
+
|
|
9
|
+
Frontmatter compliance. `rules/*.md` requires a `description` field. `skills/*/SKILL.md`, `agents/*.md`, and `commands/*.md` require both `name` and `description` fields. Each field must be a non-empty string. On missing or empty fields: STOP, add them, re-issue.
|
|
10
|
+
|
|
11
|
+
Always-on rule body budget. When the Write target matches `rules/*.md` and the file's frontmatter declares `alwaysApply: true` AND `pathFilter:` empty, the substantive-token count of the body must satisfy the 500-token ceiling per `rules/token-budget-discipline.md`. The conformity-gate orchestrator runs `conformity/always_on_budget_grep.py` and reports the per-file count plus an `over_budget` flag. On `over_budget: true`: STOP, decompose along a path-filtered seam (companion sub-rule pattern; precedents at `rules/context-management.md` ↔ `rules/context-management-scratch.md`), trim the parent body, re-issue.
|
|
12
|
+
|
|
13
|
+
Scratch-convention path check.
|
|
14
|
+
|
|
15
|
+
Trigger. Every Write.
|
|
16
|
+
|
|
17
|
+
Action. Examine the target `file_path` against the scratch-convention discipline at `rules/context-management-scratch.md` §1 (scratch-file naming + closed-purpose vocabulary) and §2 (Plan-Workflow Directories + suite-locality invariant). REJECT a Write whose target violates the closed-purpose vocabulary, the disjoint-vocabulary rule, or the suite-locality invariant; ACCEPT otherwise. On a REJECT: STOP and re-issue the Write at the corrected target per the rule's recovery clause.
|
|
18
|
+
|
|
19
|
+
Non-matching paths (anything that is not a scratch or prose path): no action. The scratch-convention check is scoped to the `_inputs/` and `_spec/` directory patterns defined at `rules/context-management-scratch.md` §1–§2 and does not interact with other path classes.
|
|
20
|
+
|
|
21
|
+
**Fail-disposition.** Two layers govern failure. (a) The Python dispatcher at `hooks/dispatch.py` is fail-open: a hook-emission error converts to a structured failure envelope on stdout and the Write proceeds, so a harness error never silently blocks the tool call. (b) The assistant's interpretation of this context is fail-closed on a detected violation: when the CM-7 scan, a frontmatter gap, an over-budget body, or a scratch-path REJECT class is hit, the directive is to STOP and re-issue the Write corrected. The two layers are non-redundant: the dispatcher protects the runtime, this context protects the rule. Mechanical enforcement runs in CI and pre-commit via the strict conformity corpus gate.
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Session-start conformity posture.
|
|
4
|
+
|
|
5
|
+
**Working-trace surface.** The most-recent plan suite's PROGRESS.md Resumption Contract is the authoritative pickup point. Read its Watch Items and Blockers sections before any substantive action. The Critical Files Manifest is the deterministic next-session bootstrap order — read those files first, in that order.
|
|
6
|
+
|
|
7
|
+
**Unresolved-inquiry enumeration.** Before emitting any artifact of meaningful scope, walk the active suite for unresolved `<USER-CONFIRM:…>` placeholders and any `unresolved-inquiries:` arrays in prior phase reports' fifteen-bar gate attestation blocks. Surface every one — do not silently re-invent the answer. Required-category placeholders (identity / scope / security / public-surface naming) block emission until resolved through the canonical inquiry channel; optional-category placeholders fall back to the recommended option per the option-annotation discipline and record the fallback as a finding.
|
|
8
|
+
|
|
9
|
+
**Host-discovery freshness.** Convention discovery (formatter, linter, test framework, CI provider, branch strategy, commit-message convention) runs on-demand per the host-discovery rule, not at session start. The session-start posture only declares that discovery is the path; the actual walk fires when the first artifact-emission decision needs it.
|
|
10
|
+
|
|
11
|
+
**Pre-emission gate awareness.** Every host-project artifact emission of meaningful scope passes through the fifteen-bar pre-emission gate before it leaves the agent's hands. The gate's mechanical bars (M2, M5, M7, M8, M10, M13, M15) are operationalized as PreToolUse hooks at `apothem/conformity/*_grep.py` orchestrated by `apothem/conformity/gate.py`; the reasoned bars (M1, M3, M6, M9, M11, M12, M14) are evaluated by the operating agent and recorded in the attestation block.
|
|
12
|
+
|
|
13
|
+
**Trivial-vs-non-trivial threshold.** The threshold separating trivial from non-trivial work — non-trivial work triggers the agile sprint apparatus, the per-sub-phase reporting, and the full pre-emission gate — is the line-count + scope hybrid: a change is trivial when it is a single-file edit of ≤ 5 lines AND introduces no public-API surface change AND no behavioral shift. Anything else is non-trivial. Project-scope CLAUDE.md may override per host discipline.
|
|
14
|
+
|
|
15
|
+
**Fail-disposition.** Fail-open at every layer. The Python dispatcher at `hooks/dispatch.py` converts any exception in `session_start_bootstrap.main()` to a structured failure envelope on stdout (per the dispatcher's `_emit_failure` contract); the session itself proceeds. A bootstrap-script error degrades the operator's session-start summary but never blocks the session — there is no recovery path that would benefit from blocking. If the operator notices a missing posture block, the recovery is to re-invoke the bootstrap manually or inspect `hooks/session_start_bootstrap.py` for the diagnostic stack trace.
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<!-- SPDX-License-Identifier: MIT -->
|
|
2
|
+
|
|
3
|
+
Session-end protocol (CM-14 + CM-24 §2.5 + CM-26 + CM-22 §2/§4).
|
|
4
|
+
|
|
5
|
+
**Phase A — Mandatory externalization** (CM-14, CM-24 §2.5)
|
|
6
|
+
|
|
7
|
+
1. With an active plan suite, mid-phase: write current task state to PROGRESS.md Resumption Contract — phase id, task id, status (in_progress|partial), next action as a precise imperative.
|
|
8
|
+
2. Move every session decision to PLAN-NOTES.md § Resolved Decisions; remove from in-conversation working memory.
|
|
9
|
+
3. Update Phase Output Registry — every declared output that landed on disk gets verified status with its actual path; missing outputs get blocked status with the reason.
|
|
10
|
+
4. Update convention anchors in the Resumption Contract if any evolved this session.
|
|
11
|
+
5. Write the critical-files manifest — ordered list of files the next session must read first to resume.
|
|
12
|
+
|
|
13
|
+
**Phase B — Evaluation** (skip only on immediate-exit signal)
|
|
14
|
+
|
|
15
|
+
1. Memory evaluation per CM-26 (auto-memory rule §5): scan session for stable patterns / preferences / architectural decisions / debugging insights; write or update memory entries; prune any entry this session contradicted.
|
|
16
|
+
2. Artifact evolution per CM-22 §2 + §4: detect patterns that recurred 2+ times this session and need a new or updated rule, skill, command, hook, or agent.
|
|
17
|
+
3. Convention sweep per CM-22 §3: verify cross-references still resolve, no orphan artifacts were created, naming remains consistent.
|
|
18
|
+
|
|
19
|
+
No active suite: skip Phase A entirely; execute Phase B against working notes accumulated this session.
|
|
20
|
+
|
|
21
|
+
**No re-narration (no repeated messages).** Phases A–C externalize state to durable files; they are file-side, not conversational output. The session's single conversational close is the three-element close per `rules/session-closure.md` §3 — do not re-narrate these phases as additional end-of-session messages, and do not re-emit a close already emitted this session. On a Stop-condition / goal / loop re-engagement, advance the work and report only the delta; never re-print the prior close.
|
|
22
|
+
|
|
23
|
+
**Phase C — Conformity trace flush** (run alongside Phase A; non-negotiable when an active suite carries unresolved inquiries)
|
|
24
|
+
|
|
25
|
+
1. Working-trace emission. Verify the active suite's PROGRESS.md Resumption Contract was updated this session — if any session decision, blocker, or watch item is still in conversation memory only, write it to durable file before the session ends.
|
|
26
|
+
2. Unresolved-inquiry flush. Walk the active suite for concrete-id `<USER-CONFIRM:…>` placeholders and any `unresolved-inquiries:` arrays in this session's emitted phase reports' fifteen-bar gate attestation blocks. Surface every unresolved inquiry in the Resumption Contract Watch Items section so the next session inherits the inventory and does not silently re-invent.
|
|
27
|
+
3. Mandate-axis findings. If this session emitted any findings against the M-N mandate axs (host-discovery gaps, code-craft drift, supply-chain regressions, production-readiness gaps), summarize them in the Resumption Contract so the next session inherits the audit signal alongside its task pointer.
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
"""PostToolUse handler that mechanically operationalizes the CM-19 proactive-
|
|
4
|
+
compaction triggers.
|
|
5
|
+
|
|
6
|
+
Why this handler exists. The compaction-trigger catalog
|
|
7
|
+
(``rules/context-management-protocol.md`` §2 — ~18 tool calls since the last
|
|
8
|
+
externalization, a large cumulative emission, a heavy-read run) was
|
|
9
|
+
agent-discipline only: nothing *measured* per-session activity, so the
|
|
10
|
+
"compact before context fills" advisory fired solely on the agent's own
|
|
11
|
+
vigilance. The harness ``PreCompact`` event fires only once compaction has
|
|
12
|
+
already been initiated — too late to be proactive. This module is the
|
|
13
|
+
dispatch-routed ``PostToolUse`` handler that closes that gap: it keys off the
|
|
14
|
+
``session_id`` in the hook stdin payload, maintains a tiny per-session counter
|
|
15
|
+
file, and once a threshold from the §2 catalog is crossed it surfaces a concise
|
|
16
|
+
proactive-compaction advisory (externalize state + compact now) and then resets
|
|
17
|
+
the counter so the advisory does not fire on every subsequent tool call.
|
|
18
|
+
|
|
19
|
+
What it guarantees.
|
|
20
|
+
|
|
21
|
+
* **Advisory-only.** It NEVER blocks. A PostToolUse hook cannot block the tool
|
|
22
|
+
call that already ran; the envelope only ever carries a ``systemMessage`` plus
|
|
23
|
+
``additionalContext`` nudge, or is empty.
|
|
24
|
+
* **Fast.** A single small-file read + write (a JSON counter object keyed by
|
|
25
|
+
session id). No project scan, no engine import on the hot path.
|
|
26
|
+
* **Fail-open.** Any exception -> emit nothing (an empty envelope), never
|
|
27
|
+
disrupt the session. A tracker bug must never cost the operator a tool call.
|
|
28
|
+
* **Low-noise / anti-spam.** It emits at most once per threshold window: when a
|
|
29
|
+
threshold crosses, the per-session counters reset (back-off), so the next
|
|
30
|
+
advisory is at least another full window away.
|
|
31
|
+
|
|
32
|
+
Configuration. Two thresholds, each overridable by an environment variable
|
|
33
|
+
(falling back to a default grounded in the §2 catalog):
|
|
34
|
+
|
|
35
|
+
* ``APOTHEM_PROACTIVE_COMPACTION_TOOL_THRESHOLD`` (default ``18``) — tool calls
|
|
36
|
+
since the last advisory; mirrors the §2 "~18 tool calls" trigger.
|
|
37
|
+
* ``APOTHEM_PROACTIVE_COMPACTION_OUTPUT_THRESHOLD`` (default ``20000``) —
|
|
38
|
+
cumulative tool-output bytes since the last advisory; a mechanical proxy for
|
|
39
|
+
the §2 "large cumulative emission" / heavy-read triggers (~20 KB ≈ the
|
|
40
|
+
500-line emission band the catalog names).
|
|
41
|
+
|
|
42
|
+
A non-positive or unparseable override falls back to the default, so a typo in
|
|
43
|
+
the environment can never disable or zero-out the tracker silently.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
from __future__ import annotations
|
|
47
|
+
|
|
48
|
+
import json
|
|
49
|
+
import os
|
|
50
|
+
import sys
|
|
51
|
+
import tempfile
|
|
52
|
+
from dataclasses import dataclass
|
|
53
|
+
from pathlib import Path
|
|
54
|
+
from typing import Final
|
|
55
|
+
|
|
56
|
+
#: Environment overrides for the two thresholds. Each falls back to its default
|
|
57
|
+
#: when unset, non-numeric, or non-positive.
|
|
58
|
+
TOOL_THRESHOLD_ENV: Final[str] = "APOTHEM_PROACTIVE_COMPACTION_TOOL_THRESHOLD"
|
|
59
|
+
OUTPUT_THRESHOLD_ENV: Final[str] = "APOTHEM_PROACTIVE_COMPACTION_OUTPUT_THRESHOLD"
|
|
60
|
+
|
|
61
|
+
#: Default thresholds, grounded in the §2 compaction-trigger catalog.
|
|
62
|
+
#: ``18`` mirrors the "~18 tool calls" trigger; ``20000`` bytes is a mechanical
|
|
63
|
+
#: proxy for the "500-line emission" / heavy-read band (~20 KB).
|
|
64
|
+
DEFAULT_TOOL_THRESHOLD: Final[int] = 18
|
|
65
|
+
DEFAULT_OUTPUT_THRESHOLD: Final[int] = 20_000
|
|
66
|
+
|
|
67
|
+
#: Per-session state lives under a dedicated subdirectory of the OS temp dir —
|
|
68
|
+
#: never inside the repository's tracked tree (the hook runs in the operator's
|
|
69
|
+
#: harness, not the checkout). The subdirectory keeps the counter files grouped
|
|
70
|
+
#: and easy to purge.
|
|
71
|
+
_STATE_DIRNAME: Final[str] = "apothem-proactive-compaction"
|
|
72
|
+
|
|
73
|
+
#: Sanitized fallback when a session id is absent or unusable. A shared key is
|
|
74
|
+
#: acceptable here: the tracker is advisory, and a missing id only means the
|
|
75
|
+
#: counters are not partitioned per session for that (rare) case.
|
|
76
|
+
_DEFAULT_SESSION_KEY: Final[str] = "_default"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
@dataclass(frozen=True)
|
|
80
|
+
class Thresholds:
|
|
81
|
+
"""Resolved tool-call and output-byte thresholds for one invocation."""
|
|
82
|
+
|
|
83
|
+
tool_calls: int
|
|
84
|
+
output_bytes: int
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
@dataclass
|
|
88
|
+
class SessionState:
|
|
89
|
+
"""Mutable per-session counters since the last advisory.
|
|
90
|
+
|
|
91
|
+
``tool_calls`` counts PostToolUse firings; ``output_bytes`` accumulates the
|
|
92
|
+
estimated size of each tool's output. Both reset to zero when an advisory
|
|
93
|
+
fires (the anti-spam back-off).
|
|
94
|
+
"""
|
|
95
|
+
|
|
96
|
+
tool_calls: int = 0
|
|
97
|
+
output_bytes: int = 0
|
|
98
|
+
|
|
99
|
+
def to_dict(self) -> dict[str, int]:
|
|
100
|
+
"""Serialize to the on-disk JSON shape."""
|
|
101
|
+
return {"tool_calls": self.tool_calls, "output_bytes": self.output_bytes}
|
|
102
|
+
|
|
103
|
+
@classmethod
|
|
104
|
+
def from_obj(cls, obj: object) -> SessionState:
|
|
105
|
+
"""Reconstruct from a parsed JSON object, tolerating shape drift.
|
|
106
|
+
|
|
107
|
+
A garbage or partial object yields zeroed counters (fail-open): a
|
|
108
|
+
corrupt state file degrades to "start counting again", never a crash.
|
|
109
|
+
"""
|
|
110
|
+
if not isinstance(obj, dict):
|
|
111
|
+
return cls()
|
|
112
|
+
tool_calls = obj.get("tool_calls")
|
|
113
|
+
output_bytes = obj.get("output_bytes")
|
|
114
|
+
return cls(
|
|
115
|
+
tool_calls=tool_calls
|
|
116
|
+
if isinstance(tool_calls, int) and tool_calls >= 0
|
|
117
|
+
else 0,
|
|
118
|
+
output_bytes=(
|
|
119
|
+
output_bytes
|
|
120
|
+
if isinstance(output_bytes, int) and output_bytes >= 0
|
|
121
|
+
else 0
|
|
122
|
+
),
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def _positive_int_env(name: str, default: int) -> int:
|
|
127
|
+
"""Return a positive integer from environment variable *name*, else *default*.
|
|
128
|
+
|
|
129
|
+
A non-positive or unparseable value falls back to *default* so a typo can
|
|
130
|
+
never silently disable or zero-out the threshold.
|
|
131
|
+
"""
|
|
132
|
+
raw = os.environ.get(name, "").strip()
|
|
133
|
+
if not raw:
|
|
134
|
+
return default
|
|
135
|
+
try:
|
|
136
|
+
value = int(raw)
|
|
137
|
+
except ValueError:
|
|
138
|
+
return default
|
|
139
|
+
return value if value > 0 else default
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
def resolve_thresholds() -> Thresholds:
|
|
143
|
+
"""Resolve both thresholds from the environment with grounded defaults."""
|
|
144
|
+
return Thresholds(
|
|
145
|
+
tool_calls=_positive_int_env(TOOL_THRESHOLD_ENV, DEFAULT_TOOL_THRESHOLD),
|
|
146
|
+
output_bytes=_positive_int_env(OUTPUT_THRESHOLD_ENV, DEFAULT_OUTPUT_THRESHOLD),
|
|
147
|
+
)
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def _sanitize_session_key(session_id: object) -> str:
|
|
151
|
+
"""Map an arbitrary session id to a safe, bounded filename stem.
|
|
152
|
+
|
|
153
|
+
Keeps only ``[A-Za-z0-9._-]`` (path-traversal-safe), bounds the length, and
|
|
154
|
+
falls back to a shared default key when the id is absent, non-string, or
|
|
155
|
+
sanitizes to empty. This guarantees the state path stays inside the state
|
|
156
|
+
directory regardless of payload contents.
|
|
157
|
+
"""
|
|
158
|
+
if not isinstance(session_id, str) or not session_id.strip():
|
|
159
|
+
return _DEFAULT_SESSION_KEY
|
|
160
|
+
allowed = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789._-"
|
|
161
|
+
cleaned = "".join(ch for ch in session_id if ch in allowed)
|
|
162
|
+
cleaned = cleaned.strip("._-")
|
|
163
|
+
if not cleaned:
|
|
164
|
+
return _DEFAULT_SESSION_KEY
|
|
165
|
+
return cleaned[:120]
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def _state_dir() -> Path:
|
|
169
|
+
"""Return the per-session state directory under the OS temp dir."""
|
|
170
|
+
return Path(tempfile.gettempdir()) / _STATE_DIRNAME
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
def state_path_for(session_id: object) -> Path:
|
|
174
|
+
"""Return the counter-file path for *session_id* (never inside the repo)."""
|
|
175
|
+
return _state_dir() / f"{_sanitize_session_key(session_id)}.json"
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
def _read_state(path: Path) -> SessionState:
|
|
179
|
+
"""Load per-session counters from *path*, fail-open to zero on any error."""
|
|
180
|
+
try:
|
|
181
|
+
raw = path.read_text(encoding="utf-8")
|
|
182
|
+
except OSError:
|
|
183
|
+
return SessionState()
|
|
184
|
+
try:
|
|
185
|
+
return SessionState.from_obj(json.loads(raw))
|
|
186
|
+
except (json.JSONDecodeError, ValueError):
|
|
187
|
+
return SessionState()
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
def _write_state(path: Path, state: SessionState) -> None:
|
|
191
|
+
"""Persist per-session counters to *path*, creating the dir as needed."""
|
|
192
|
+
path.parent.mkdir(parents=True, exist_ok=True)
|
|
193
|
+
path.write_text(
|
|
194
|
+
json.dumps(state.to_dict(), separators=(",", ":")) + "\n",
|
|
195
|
+
encoding="utf-8",
|
|
196
|
+
)
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def estimate_output_bytes(payload: dict[str, object] | None) -> int:
|
|
200
|
+
"""Estimate the byte size of a PostToolUse tool result from the payload.
|
|
201
|
+
|
|
202
|
+
The harness PostToolUse stdin carries ``tool_response`` (the tool's output).
|
|
203
|
+
Its shape varies by tool, so the estimate serializes whatever is present to
|
|
204
|
+
a JSON string and measures its UTF-8 length — a stable, tool-agnostic proxy
|
|
205
|
+
for "how much did this tool emit". An absent or unserializable response
|
|
206
|
+
contributes zero (fail-open).
|
|
207
|
+
"""
|
|
208
|
+
if not payload:
|
|
209
|
+
return 0
|
|
210
|
+
response = payload.get("tool_response")
|
|
211
|
+
if response is None:
|
|
212
|
+
return 0
|
|
213
|
+
try:
|
|
214
|
+
if isinstance(response, str):
|
|
215
|
+
text = response
|
|
216
|
+
else:
|
|
217
|
+
text = json.dumps(response, separators=(",", ":"), default=str)
|
|
218
|
+
except (TypeError, ValueError):
|
|
219
|
+
return 0
|
|
220
|
+
return len(text.encode("utf-8"))
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
def _advisory_text() -> str:
|
|
224
|
+
"""Return the proactive-compaction advisory body."""
|
|
225
|
+
return (
|
|
226
|
+
"Apothem proactive-compaction advisory (CM-19): activity since the last "
|
|
227
|
+
"checkpoint has crossed a context-rot threshold. Externalize in-conversation "
|
|
228
|
+
"state to durable files now, then compact:\n"
|
|
229
|
+
" 1. Update the PROGRESS.md Resumption Contract (phase, task, next action, "
|
|
230
|
+
"convention anchors, critical-files manifest); record session decisions in "
|
|
231
|
+
"PLAN-NOTES.md. With no active suite, externalize to a scratch file under the "
|
|
232
|
+
"active harness's config root.\n"
|
|
233
|
+
" 2. Compact (or start a fresh session) so context stays lean per the "
|
|
234
|
+
"blind-execution invariant — every turn must remain executable from durable "
|
|
235
|
+
"files alone.\n"
|
|
236
|
+
"This is advisory; it does not block. The counter has reset, so the next "
|
|
237
|
+
"advisory is at least another full window away."
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
def build_envelope(state: SessionState, thresholds: Thresholds) -> dict[str, object]:
|
|
242
|
+
"""Map current counters to a hook-output envelope.
|
|
243
|
+
|
|
244
|
+
Returns the advisory envelope when either threshold is crossed (the caller
|
|
245
|
+
has already reset the counters on the crossing path), or an empty envelope
|
|
246
|
+
when below both thresholds (the silent, low-noise default).
|
|
247
|
+
"""
|
|
248
|
+
crossed = (
|
|
249
|
+
state.tool_calls >= thresholds.tool_calls
|
|
250
|
+
or state.output_bytes >= thresholds.output_bytes
|
|
251
|
+
)
|
|
252
|
+
if not crossed:
|
|
253
|
+
return {}
|
|
254
|
+
text = _advisory_text()
|
|
255
|
+
return {
|
|
256
|
+
"systemMessage": text,
|
|
257
|
+
"hookSpecificOutput": {
|
|
258
|
+
"hookEventName": "PostToolUse",
|
|
259
|
+
"additionalContext": text,
|
|
260
|
+
},
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
|
|
264
|
+
def _read_payload() -> dict[str, object] | None:
|
|
265
|
+
"""Read and parse the hook's stdin JSON payload, fail-open on any error."""
|
|
266
|
+
try:
|
|
267
|
+
if sys.stdin.isatty():
|
|
268
|
+
return None
|
|
269
|
+
raw = sys.stdin.read()
|
|
270
|
+
except OSError:
|
|
271
|
+
return None
|
|
272
|
+
if not raw or not raw.strip():
|
|
273
|
+
return None
|
|
274
|
+
try:
|
|
275
|
+
parsed = json.loads(raw)
|
|
276
|
+
except (json.JSONDecodeError, ValueError):
|
|
277
|
+
return None
|
|
278
|
+
return parsed if isinstance(parsed, dict) else None
|
|
279
|
+
|
|
280
|
+
|
|
281
|
+
def evaluate(payload: dict[str, object] | None) -> dict[str, object]:
|
|
282
|
+
"""Increment the per-session counters and return the advisory envelope.
|
|
283
|
+
|
|
284
|
+
Pre-condition: *payload* is the harness PostToolUse stdin object (or
|
|
285
|
+
``None``). Post-condition: the per-session counter file reflects this tool
|
|
286
|
+
call; when a threshold crosses, the counters are reset to zero and the
|
|
287
|
+
advisory envelope is returned; otherwise an empty envelope is returned and
|
|
288
|
+
the counters carry forward.
|
|
289
|
+
"""
|
|
290
|
+
session_id = payload.get("session_id") if isinstance(payload, dict) else None
|
|
291
|
+
path = state_path_for(session_id)
|
|
292
|
+
thresholds = resolve_thresholds()
|
|
293
|
+
|
|
294
|
+
state = _read_state(path)
|
|
295
|
+
state.tool_calls += 1
|
|
296
|
+
state.output_bytes += estimate_output_bytes(payload)
|
|
297
|
+
|
|
298
|
+
envelope = build_envelope(state, thresholds)
|
|
299
|
+
if envelope:
|
|
300
|
+
# Threshold crossed: reset the window so the advisory does not fire on
|
|
301
|
+
# the next tool call (anti-spam back-off).
|
|
302
|
+
_write_state(path, SessionState())
|
|
303
|
+
else:
|
|
304
|
+
_write_state(path, state)
|
|
305
|
+
return envelope
|
|
306
|
+
|
|
307
|
+
|
|
308
|
+
def main(argv: list[str] | None = None) -> None:
|
|
309
|
+
"""Entry point. Tracks activity and emits one envelope; never raises.
|
|
310
|
+
|
|
311
|
+
The ``argv`` parameter is accepted for signature parity with the sibling
|
|
312
|
+
dispatch handlers (the dispatcher calls ``main([])``); this handler reads no
|
|
313
|
+
flags, so it is intentionally unused.
|
|
314
|
+
|
|
315
|
+
FAIL-OPEN: any unexpected exception is swallowed and an empty (no-op)
|
|
316
|
+
envelope is written, so a tracker bug never disrupts the session.
|
|
317
|
+
"""
|
|
318
|
+
try:
|
|
319
|
+
payload = _read_payload()
|
|
320
|
+
envelope = evaluate(payload)
|
|
321
|
+
sys.stdout.write(json.dumps(envelope, separators=(",", ":")) + "\n")
|
|
322
|
+
except Exception: # noqa: BLE001, RUF100 - fail-open boundary: a tracker error must never disrupt the session; emit an empty envelope and proceed (BLE001 is the intent marker; RUF100 self-suppresses because ruff's BLE family is not active)
|
|
323
|
+
sys.stdout.write("{}\n")
|
|
324
|
+
|
|
325
|
+
|
|
326
|
+
if __name__ == "__main__":
|
|
327
|
+
main()
|