@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,450 @@
|
|
|
1
|
+
# SPDX-License-Identifier: MIT
|
|
2
|
+
|
|
3
|
+
"""Advisory: flag plan-suite infra files whose Recommended-Next-Step footer
|
|
4
|
+
drifts from the suite's recorded next pipeline stage.
|
|
5
|
+
|
|
6
|
+
Why this validator exists. Plan-suite infrastructure files (``PROGRESS.md``,
|
|
7
|
+
``MASTER-PLAN.md``, ``MASTER-INDEX.md``, ``TRACE-MATRIX.md``) can close with a
|
|
8
|
+
``## Recommended Next Step`` footer naming the pipeline stage the operator
|
|
9
|
+
should run next (e.g. "Run ``/plan-design``"). The ``recommend-next-step``
|
|
10
|
+
matcher only scopes ``commands/``, ``skills/``, and ``phases/`` artifacts, and
|
|
11
|
+
the per-write gate short-circuits ``.plans/`` paths, so nothing mechanically
|
|
12
|
+
verifies that an infra footer still matches the suite's *recorded* next stage.
|
|
13
|
+
Stale footers consequently survive review cycles, directly contradicting the
|
|
14
|
+
suite's own ``PROGRESS.md``.
|
|
15
|
+
|
|
16
|
+
Scope and ground truth. This validator compares a footer's ``/plan-*`` pipeline
|
|
17
|
+
stage against the suite's recorded next ``/plan-*`` stage. It reads that
|
|
18
|
+
recorded stage from ``PROGRESS.md`` in two places, supporting both the
|
|
19
|
+
canonical plan-suite template and the meta-pipeline-tracking variant:
|
|
20
|
+
|
|
21
|
+
- **Tracker** — a table under ``## Pipeline Tracker`` *or* ``## Phase Tracker``;
|
|
22
|
+
the row whose status cell is marked ``NEXT`` supplies its first ``/plan-*``
|
|
23
|
+
token.
|
|
24
|
+
- **Next action** — the Resumption Contract field labelled "Next action",
|
|
25
|
+
written either as a ``- **Next action (imperative):** Run `/plan-X``` bullet
|
|
26
|
+
or as a ``**Next action:** ...`` field. The extraction is bounded to that one
|
|
27
|
+
field so a ``/plan-*`` token in a later field or in ``### Active Decisions``
|
|
28
|
+
never leaks in.
|
|
29
|
+
|
|
30
|
+
The Resumption Contract is authoritative; the tracker NEXT row is the
|
|
31
|
+
cross-check. When both name a ``/plan-*`` stage and disagree, ``PROGRESS.md`` is
|
|
32
|
+
internally inconsistent — itself a finding. The canonical next stage is the
|
|
33
|
+
Next-action stage when present, else the tracker NEXT stage.
|
|
34
|
+
|
|
35
|
+
When there is no machine-readable next *pipeline stage* — e.g. a phase-execution
|
|
36
|
+
suite whose Next action is "Execute Phase 05" and whose tracker lists phase IDs
|
|
37
|
+
rather than ``/plan-*`` stages — the validator cannot compare a footer against a
|
|
38
|
+
``/plan-*`` ground truth without guessing. Rather than silently passing such a
|
|
39
|
+
suite, it records an advisory ``note`` naming every footer it left unvalidated.
|
|
40
|
+
|
|
41
|
+
Advisory by default. ``_main`` prints the report and exits 0 regardless of
|
|
42
|
+
findings; ``--strict`` exits 2 on findings. The ``check()`` verdict
|
|
43
|
+
(``passed = not findings``) is honest either way; only the exit code is
|
|
44
|
+
advisory. Notes never flip ``passed``.
|
|
45
|
+
"""
|
|
46
|
+
|
|
47
|
+
from __future__ import annotations
|
|
48
|
+
|
|
49
|
+
import json
|
|
50
|
+
import re
|
|
51
|
+
import sys
|
|
52
|
+
from dataclasses import asdict, dataclass, field
|
|
53
|
+
from pathlib import Path
|
|
54
|
+
from typing import Final
|
|
55
|
+
|
|
56
|
+
GREP_NAME: Final[str] = "plan-next-step-consistency-grep"
|
|
57
|
+
RULE_ANCHOR: Final[str] = "rules/recommend-next-step.md"
|
|
58
|
+
|
|
59
|
+
EXIT_PASS: Final[int] = 0
|
|
60
|
+
EXIT_FAIL: Final[int] = 2
|
|
61
|
+
|
|
62
|
+
# Opt-in flag that turns the advisory CLI into a gating one.
|
|
63
|
+
STRICT_FLAG: Final[str] = "--strict"
|
|
64
|
+
|
|
65
|
+
# The plan-suite root directory, relative to the inspected project root. The
|
|
66
|
+
# sole canonical project-local plans location is the shared ``.apothem/plans``;
|
|
67
|
+
# a legacy ``.plans`` tree is no longer canonical — operators upgrade it via
|
|
68
|
+
# ``apothem migrate-workspace``.
|
|
69
|
+
APOTHEM_PLANS_RELPATH: Final[tuple[str, str]] = (".apothem", "plans")
|
|
70
|
+
|
|
71
|
+
# The recorded-state source. A suite without it carries no machine-readable
|
|
72
|
+
# next-stage record and is skipped (no false positives on stateless suites).
|
|
73
|
+
PROGRESS_FILENAME: Final[str] = "PROGRESS.md"
|
|
74
|
+
|
|
75
|
+
# Infra files that carry a `## Recommended Next Step` footer pointing at a
|
|
76
|
+
# pipeline stage. PROGRESS.md is both the recorded-state source and an infra
|
|
77
|
+
# surface carrying its own footer (the in-file self-contradiction case).
|
|
78
|
+
INFRA_FILENAMES: Final[tuple[str, ...]] = (
|
|
79
|
+
"PROGRESS.md",
|
|
80
|
+
"MASTER-PLAN.md",
|
|
81
|
+
"MASTER-INDEX.md",
|
|
82
|
+
"TRACE-MATRIX.md",
|
|
83
|
+
)
|
|
84
|
+
|
|
85
|
+
# A pipeline-stage token in either written form: the canonical first-class
|
|
86
|
+
# command form `/plan-<stage>` or the legacy space-separated dispatch form
|
|
87
|
+
# `/plan <stage>`. The stage word is captured from the closed seven-stage set
|
|
88
|
+
# so backticks and trailing punctuation are never captured. Matches are
|
|
89
|
+
# normalized to the canonical `/plan-<stage>` form before comparison.
|
|
90
|
+
_STAGE_RE: Final[re.Pattern[str]] = re.compile(
|
|
91
|
+
r"/plan[ -](spec|generate|design|review|audit|execute|status)\b"
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
# Tracker section headings. The canonical template uses `## Phase Tracker`; the
|
|
95
|
+
# meta-pipeline-tracking variant uses `## Pipeline Tracker`. Both are accepted.
|
|
96
|
+
_PIPELINE_TRACKER_RE: Final[re.Pattern[str]] = re.compile(
|
|
97
|
+
r"^##\s+Pipeline\s+Tracker\s*$"
|
|
98
|
+
)
|
|
99
|
+
_PHASE_TRACKER_RE: Final[re.Pattern[str]] = re.compile(r"^##\s+Phase\s+Tracker\s*$")
|
|
100
|
+
_RESUMPTION_CONTRACT_RE: Final[re.Pattern[str]] = re.compile(
|
|
101
|
+
r"^##\s+Resumption\s+Contract\s*$"
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# Footer headings. The singular `## Recommended Next Step` is the canonical
|
|
105
|
+
# recommend-next-step block; the multi-action `## Next Steps` form is treated as
|
|
106
|
+
# a footer only when it carries a `**Recommended**` marker (otherwise it is a
|
|
107
|
+
# plain phase-todo list, as the canonical template emits, not a footer).
|
|
108
|
+
_RECOMMENDED_FOOTER_RE: Final[re.Pattern[str]] = re.compile(
|
|
109
|
+
r"^##\s+Recommended\s+Next\s+Step\s*$"
|
|
110
|
+
)
|
|
111
|
+
_NEXT_STEPS_RE: Final[re.Pattern[str]] = re.compile(r"^##\s+Next\s+Steps\s*$")
|
|
112
|
+
_ANY_H2_RE: Final[re.Pattern[str]] = re.compile(r"^##\s+\S")
|
|
113
|
+
|
|
114
|
+
# The Resumption Contract field naming the next imperative action.
|
|
115
|
+
_NEXT_ACTION_RE: Final[re.Pattern[str]] = re.compile(r"next\s+action", re.IGNORECASE)
|
|
116
|
+
# A line that begins a new structural element (heading, list bullet, or bold
|
|
117
|
+
# field label) — the boundary that ends the Next-action field's continuation.
|
|
118
|
+
_FIELD_START_RE: Final[re.Pattern[str]] = re.compile(r"^\s*(?:#{1,6}\s|[-*]\s|\*\*)")
|
|
119
|
+
# A tracker status cell marked NEXT — bolded `**NEXT**` or a cell whose sole
|
|
120
|
+
# alphabetic content is NEXT (e.g. `⏭️ NEXT`). Tight, so prose "next" in an
|
|
121
|
+
# artifact/detail cell does not register a non-NEXT row as the next stage.
|
|
122
|
+
_BOLD_NEXT_RE: Final[re.Pattern[str]] = re.compile(r"\*\*\s*NEXT\s*\*\*", re.IGNORECASE)
|
|
123
|
+
# Recommended marker inside a multi-action `## Next Steps` block.
|
|
124
|
+
_RECOMMENDED_RE: Final[re.Pattern[str]] = re.compile(r"\*\*Recommended\*\*")
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
@dataclass(frozen=True)
|
|
128
|
+
class Finding:
|
|
129
|
+
"""One infra-file footer (or PROGRESS.md marker) inconsistent with state."""
|
|
130
|
+
|
|
131
|
+
surface: str
|
|
132
|
+
suite: str
|
|
133
|
+
detail: str
|
|
134
|
+
rule: str = RULE_ANCHOR
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
@dataclass(frozen=True)
|
|
138
|
+
class GrepResult:
|
|
139
|
+
"""Aggregated walk result across every plan suite under the root."""
|
|
140
|
+
|
|
141
|
+
grep: str
|
|
142
|
+
root: str
|
|
143
|
+
suites_inspected: int
|
|
144
|
+
files_inspected: int
|
|
145
|
+
passed: bool
|
|
146
|
+
advisory: bool
|
|
147
|
+
findings: list[Finding] = field(default_factory=list)
|
|
148
|
+
notes: list[str] = field(default_factory=list)
|
|
149
|
+
|
|
150
|
+
def to_json(self) -> str:
|
|
151
|
+
payload = {
|
|
152
|
+
"grep": self.grep,
|
|
153
|
+
"root": self.root,
|
|
154
|
+
"suites_inspected": self.suites_inspected,
|
|
155
|
+
"files_inspected": self.files_inspected,
|
|
156
|
+
"passed": self.passed,
|
|
157
|
+
"advisory": self.advisory,
|
|
158
|
+
"findings": [asdict(f) for f in self.findings],
|
|
159
|
+
"notes": list(self.notes),
|
|
160
|
+
}
|
|
161
|
+
return json.dumps(payload, indent=2)
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
def _read_lines(path: Path) -> list[str] | None:
|
|
165
|
+
"""Return the file's lines, or None when it is absent or unreadable."""
|
|
166
|
+
try:
|
|
167
|
+
return path.read_text(encoding="utf-8").splitlines()
|
|
168
|
+
except (OSError, UnicodeDecodeError):
|
|
169
|
+
return None
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
def _rel(path: Path, root: Path) -> str:
|
|
173
|
+
"""Return path relative to root as a POSIX string, else the full path."""
|
|
174
|
+
try:
|
|
175
|
+
return path.relative_to(root).as_posix()
|
|
176
|
+
except ValueError:
|
|
177
|
+
return path.as_posix()
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
def _first_section_body(
|
|
181
|
+
lines: list[str], *heading_res: re.Pattern[str]
|
|
182
|
+
) -> list[str] | None:
|
|
183
|
+
"""Return the lines under the first matching H2 heading, up to the next H2.
|
|
184
|
+
|
|
185
|
+
The first heading in ``heading_res`` to appear in ``lines`` wins. Returns
|
|
186
|
+
None when none of the headings is present (distinct from an empty body).
|
|
187
|
+
"""
|
|
188
|
+
start: int | None = None
|
|
189
|
+
for i, line in enumerate(lines):
|
|
190
|
+
if any(heading_re.match(line) for heading_re in heading_res):
|
|
191
|
+
start = i
|
|
192
|
+
break
|
|
193
|
+
if start is None:
|
|
194
|
+
return None
|
|
195
|
+
body: list[str] = []
|
|
196
|
+
for line in lines[start + 1 :]:
|
|
197
|
+
if _ANY_H2_RE.match(line):
|
|
198
|
+
break
|
|
199
|
+
body.append(line)
|
|
200
|
+
return body
|
|
201
|
+
|
|
202
|
+
|
|
203
|
+
def _first_stage(lines: list[str]) -> str | None:
|
|
204
|
+
"""Return the first pipeline-stage token across the lines, normalized.
|
|
205
|
+
|
|
206
|
+
Both written forms are recognized; the returned token is always the
|
|
207
|
+
canonical ``/plan-<stage>`` form so comparisons are form-agnostic.
|
|
208
|
+
"""
|
|
209
|
+
for line in lines:
|
|
210
|
+
match = _STAGE_RE.search(line)
|
|
211
|
+
if match:
|
|
212
|
+
return f"/plan-{match.group(1)}"
|
|
213
|
+
return None
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
def _stage_preferring_recommended(body: list[str]) -> str | None:
|
|
217
|
+
"""Return the footer stage, preferring the ``**Recommended**`` line."""
|
|
218
|
+
recommended = [line for line in body if _RECOMMENDED_RE.search(line)]
|
|
219
|
+
if recommended:
|
|
220
|
+
stage = _first_stage(recommended)
|
|
221
|
+
if stage is not None:
|
|
222
|
+
return stage
|
|
223
|
+
return _first_stage(body)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def _resumption_next_stage(lines: list[str]) -> str | None:
|
|
227
|
+
"""Return the stage named by the Resumption Contract 'Next action' field.
|
|
228
|
+
|
|
229
|
+
The extraction is bounded to the Next-action field: its label line plus any
|
|
230
|
+
wrapped continuation, stopping at the first blank line, heading, list
|
|
231
|
+
bullet, or bold field label. A ``/plan-*`` token in a later field or in
|
|
232
|
+
``### Active Decisions`` is therefore never picked up. Returns None when the
|
|
233
|
+
field is absent or is an execution imperative with no ``/plan-*`` token.
|
|
234
|
+
"""
|
|
235
|
+
body = _first_section_body(lines, _RESUMPTION_CONTRACT_RE)
|
|
236
|
+
if body is None:
|
|
237
|
+
return None
|
|
238
|
+
idx = next(
|
|
239
|
+
(i for i, line in enumerate(body) if _NEXT_ACTION_RE.search(line)),
|
|
240
|
+
None,
|
|
241
|
+
)
|
|
242
|
+
if idx is None:
|
|
243
|
+
return None
|
|
244
|
+
block = [body[idx]]
|
|
245
|
+
for line in body[idx + 1 :]:
|
|
246
|
+
if not line.strip() or _FIELD_START_RE.match(line):
|
|
247
|
+
break
|
|
248
|
+
block.append(line)
|
|
249
|
+
return _first_stage(block)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def _cell_marks_next(cell: str) -> bool:
|
|
253
|
+
"""Return True iff a tracker status cell marks the row as the next stage."""
|
|
254
|
+
if _BOLD_NEXT_RE.search(cell):
|
|
255
|
+
return True
|
|
256
|
+
alpha = re.sub(r"[^A-Za-z]", "", cell).upper()
|
|
257
|
+
return alpha == "NEXT"
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
def _tracker_next_stage(lines: list[str]) -> str | None:
|
|
261
|
+
"""Return the stage in the tracker row marked ``NEXT``.
|
|
262
|
+
|
|
263
|
+
Accepts both the ``## Pipeline Tracker`` and ``## Phase Tracker`` headings
|
|
264
|
+
and is column-layout-agnostic: a row qualifies when any cell is a NEXT
|
|
265
|
+
status marker, and the stage is the first ``/plan-*`` token in the row. A
|
|
266
|
+
phase-execution tracker (phase IDs, no ``/plan-*`` tokens) yields None.
|
|
267
|
+
"""
|
|
268
|
+
body = _first_section_body(lines, _PIPELINE_TRACKER_RE, _PHASE_TRACKER_RE)
|
|
269
|
+
if body is None:
|
|
270
|
+
return None
|
|
271
|
+
for line in body:
|
|
272
|
+
if "|" not in line:
|
|
273
|
+
continue
|
|
274
|
+
cells = [cell.strip() for cell in line.strip().strip("|").split("|")]
|
|
275
|
+
if not any(_cell_marks_next(cell) for cell in cells):
|
|
276
|
+
continue
|
|
277
|
+
stage = _first_stage([line])
|
|
278
|
+
if stage is not None:
|
|
279
|
+
return stage
|
|
280
|
+
return None
|
|
281
|
+
|
|
282
|
+
|
|
283
|
+
def _footer_stage(lines: list[str]) -> str | None:
|
|
284
|
+
"""Return the pipeline stage named in the Recommended-Next-Step footer.
|
|
285
|
+
|
|
286
|
+
Prefers the singular ``## Recommended Next Step`` block. A ``## Next Steps``
|
|
287
|
+
block counts as a footer only when it carries a ``**Recommended**`` marker
|
|
288
|
+
(the multi-action form); a plain ``## Next Steps`` phase-todo list — as the
|
|
289
|
+
canonical template emits — is not a footer and yields None. None when no
|
|
290
|
+
footer names a pipeline stage.
|
|
291
|
+
"""
|
|
292
|
+
body = _first_section_body(lines, _RECOMMENDED_FOOTER_RE)
|
|
293
|
+
if body is not None:
|
|
294
|
+
return _stage_preferring_recommended(body)
|
|
295
|
+
body = _first_section_body(lines, _NEXT_STEPS_RE)
|
|
296
|
+
if body is None:
|
|
297
|
+
return None
|
|
298
|
+
if not any(_RECOMMENDED_RE.search(line) for line in body):
|
|
299
|
+
return None
|
|
300
|
+
return _stage_preferring_recommended(body)
|
|
301
|
+
|
|
302
|
+
|
|
303
|
+
def _inspect_suite(
|
|
304
|
+
suite_dir: Path, root: Path
|
|
305
|
+
) -> tuple[list[Finding], int, list[str]] | None:
|
|
306
|
+
"""Inspect one suite; return (findings, files-inspected, notes) or None.
|
|
307
|
+
|
|
308
|
+
Returns None when the suite carries no ``PROGRESS.md`` (no recorded state to
|
|
309
|
+
validate against). Otherwise derives the canonical next stage and compares
|
|
310
|
+
every present infra file's footer against it; an underived canonical with a
|
|
311
|
+
pipeline-stage footer present yields an advisory note rather than a silent
|
|
312
|
+
pass.
|
|
313
|
+
"""
|
|
314
|
+
progress = suite_dir / PROGRESS_FILENAME
|
|
315
|
+
if not progress.is_file():
|
|
316
|
+
return None
|
|
317
|
+
progress_lines = _read_lines(progress)
|
|
318
|
+
if progress_lines is None:
|
|
319
|
+
return (
|
|
320
|
+
[
|
|
321
|
+
Finding(
|
|
322
|
+
surface=_rel(progress, root),
|
|
323
|
+
suite=suite_dir.name,
|
|
324
|
+
detail="PROGRESS.md exists but could not be read as UTF-8 text",
|
|
325
|
+
)
|
|
326
|
+
],
|
|
327
|
+
0,
|
|
328
|
+
[],
|
|
329
|
+
)
|
|
330
|
+
|
|
331
|
+
findings: list[Finding] = []
|
|
332
|
+
next_action = _resumption_next_stage(progress_lines)
|
|
333
|
+
tracker_next = _tracker_next_stage(progress_lines)
|
|
334
|
+
canonical = next_action or tracker_next
|
|
335
|
+
|
|
336
|
+
# The two recorded-state markers must agree when both are present.
|
|
337
|
+
if next_action and tracker_next and next_action != tracker_next:
|
|
338
|
+
findings.append(
|
|
339
|
+
Finding(
|
|
340
|
+
surface=_rel(progress, root),
|
|
341
|
+
suite=suite_dir.name,
|
|
342
|
+
detail=(
|
|
343
|
+
f"PROGRESS.md internal drift — tracker marks "
|
|
344
|
+
f"`{tracker_next}` NEXT but Resumption Contract 'Next "
|
|
345
|
+
f"action' names `{next_action}`"
|
|
346
|
+
),
|
|
347
|
+
)
|
|
348
|
+
)
|
|
349
|
+
|
|
350
|
+
source = (
|
|
351
|
+
"Resumption Contract 'Next action'"
|
|
352
|
+
if next_action
|
|
353
|
+
else "Pipeline/Phase Tracker NEXT"
|
|
354
|
+
)
|
|
355
|
+
files_inspected = 0
|
|
356
|
+
unvalidated_footers: list[str] = []
|
|
357
|
+
for fname in INFRA_FILENAMES:
|
|
358
|
+
infra_lines = _read_lines(suite_dir / fname)
|
|
359
|
+
if infra_lines is None:
|
|
360
|
+
continue
|
|
361
|
+
files_inspected += 1
|
|
362
|
+
footer = _footer_stage(infra_lines)
|
|
363
|
+
if footer is None:
|
|
364
|
+
continue
|
|
365
|
+
if canonical is None:
|
|
366
|
+
# No `/plan-*` ground truth to compare against; surface rather than
|
|
367
|
+
# silently pass.
|
|
368
|
+
unvalidated_footers.append(fname)
|
|
369
|
+
continue
|
|
370
|
+
if footer == canonical:
|
|
371
|
+
continue
|
|
372
|
+
findings.append(
|
|
373
|
+
Finding(
|
|
374
|
+
surface=_rel(suite_dir / fname, root),
|
|
375
|
+
suite=suite_dir.name,
|
|
376
|
+
detail=(
|
|
377
|
+
f"`## Recommended Next Step` names `{footer}` but the "
|
|
378
|
+
f"suite's recorded next stage is `{canonical}` ({source})"
|
|
379
|
+
),
|
|
380
|
+
)
|
|
381
|
+
)
|
|
382
|
+
|
|
383
|
+
notes: list[str] = []
|
|
384
|
+
if canonical is None and unvalidated_footers:
|
|
385
|
+
notes.append(
|
|
386
|
+
f"suite '{suite_dir.name}': recorded next pipeline stage is "
|
|
387
|
+
f"indeterminate (no Pipeline/Phase Tracker NEXT row and no "
|
|
388
|
+
f"`/plan-*` 'Next action'); {len(unvalidated_footers)} footer(s) "
|
|
389
|
+
f"naming a pipeline stage were not validated "
|
|
390
|
+
f"({', '.join(unvalidated_footers)})"
|
|
391
|
+
)
|
|
392
|
+
return findings, files_inspected, notes
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
def check(root: Path) -> GrepResult:
|
|
396
|
+
"""Walk every plan suite under the canonical project-local plans tree.
|
|
397
|
+
|
|
398
|
+
The sole canonical project-local plans location is
|
|
399
|
+
``<root>/.apothem/plans``; a legacy ``<root>/.plans`` tree is no longer
|
|
400
|
+
canonical — operators upgrade it via ``apothem migrate-workspace``. Suites
|
|
401
|
+
under the canonical tree are inspected for footer drift.
|
|
402
|
+
"""
|
|
403
|
+
plans_dirs = (root.joinpath(*APOTHEM_PLANS_RELPATH),)
|
|
404
|
+
findings: list[Finding] = []
|
|
405
|
+
notes: list[str] = []
|
|
406
|
+
suites_inspected = 0
|
|
407
|
+
files_inspected = 0
|
|
408
|
+
for plans_dir in plans_dirs:
|
|
409
|
+
if not plans_dir.is_dir():
|
|
410
|
+
continue
|
|
411
|
+
for suite_dir in sorted(p for p in plans_dir.iterdir() if p.is_dir()):
|
|
412
|
+
outcome = _inspect_suite(suite_dir, root)
|
|
413
|
+
if outcome is None:
|
|
414
|
+
continue
|
|
415
|
+
suite_findings, inspected, suite_notes = outcome
|
|
416
|
+
suites_inspected += 1
|
|
417
|
+
files_inspected += inspected
|
|
418
|
+
findings.extend(suite_findings)
|
|
419
|
+
notes.extend(suite_notes)
|
|
420
|
+
return GrepResult(
|
|
421
|
+
grep=GREP_NAME,
|
|
422
|
+
root=str(root),
|
|
423
|
+
suites_inspected=suites_inspected,
|
|
424
|
+
files_inspected=files_inspected,
|
|
425
|
+
passed=not findings,
|
|
426
|
+
advisory=True,
|
|
427
|
+
findings=findings,
|
|
428
|
+
notes=notes,
|
|
429
|
+
)
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
def _read_input(argv: list[str]) -> tuple[Path, bool]:
|
|
433
|
+
"""Return (root, strict) parsed from argv; root defaults to cwd."""
|
|
434
|
+
strict = STRICT_FLAG in argv
|
|
435
|
+
positional = [arg for arg in argv[1:] if arg != STRICT_FLAG]
|
|
436
|
+
root = Path(positional[0]) if positional else Path.cwd()
|
|
437
|
+
return root, strict
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
def _main(argv: list[str]) -> int:
|
|
441
|
+
root, strict = _read_input(argv)
|
|
442
|
+
result = check(root)
|
|
443
|
+
print(result.to_json())
|
|
444
|
+
if strict and not result.passed:
|
|
445
|
+
return EXIT_FAIL
|
|
446
|
+
return EXIT_PASS
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
if __name__ == "__main__":
|
|
450
|
+
sys.exit(_main(sys.argv))
|