atomadic-forge 0.58.0__tar.gz → 0.60.0__tar.gz
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.
- {atomadic_forge-0.58.0/src/atomadic_forge.egg-info → atomadic_forge-0.60.0}/PKG-INFO +1 -1
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/pyproject.toml +1 -1
- atomadic_forge-0.60.0/src/atomadic_forge/a1_at_functions/abstract_method_repair.py +333 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/cherry_pick.py +24 -1
- atomadic_forge-0.60.0/src/atomadic_forge/a1_at_functions/scaffold_starter.py +268 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/stub_detector.py +25 -4
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_pipeline.py +145 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0/src/atomadic_forge.egg-info}/PKG-INFO +1 -1
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge.egg-info/SOURCES.txt +4 -0
- atomadic_forge-0.60.0/tests/test_abstract_method_repair.py +122 -0
- atomadic_forge-0.60.0/tests/test_cherry_pick.py +68 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_cli_smoke.py +33 -0
- atomadic_forge-0.60.0/tests/test_finalize_scaffold.py +110 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_stub_detector.py +55 -2
- atomadic_forge-0.58.0/src/atomadic_forge/a1_at_functions/scaffold_starter.py +0 -167
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/FUNDING.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/actions/forge-action/README.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/actions/forge-action/action.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/dependabot.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/pull_request_template.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/ci.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/customer-refactor.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/forge-self-certify.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/mcp-registry-publish.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/metrics-auto-regen.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/metrics-drift.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/publish-on-tag.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/release-readiness.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/release.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/surface-drift.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/.github/workflows/uptime.yml +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/ARCHITECTURE.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/CHANGELOG.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/CONTRIBUTING.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/LICENSE +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/MANIFEST.in +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/README.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/SECURITY.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/assets/Atomadic-Forge-01.png +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/01-getting-started.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/02-commands.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/03-tutorial.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/04-llm-loops.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/05-faq.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/AGENTS_GUIDE.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/AIR_GAPPED.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/CI_CD.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/CODEX_WALKTHROUGH.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/COMMANDS.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/FIRST_10_MINUTES.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/FORMALIZATION.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/HIVE_PRIMITIVES.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/HIVE_STATUS.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/IDE_INTEGRATION.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/LANDSCAPE.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/MARKET_POSITIONING.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/MCP_TOOLS.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/MIGRATION.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/MULTI_REPO.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/PROVIDERS.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/README.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/RECEIPT.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/RELAY_PROTOCOL.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/RELEASE_CHECKLIST.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/RELEASE_MESSAGING.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/ROADMAP.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/SHOWCASE.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/SIDECAR.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/STUDIO.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/TOOL_FACTORY_WALKTHROUGH.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/V0.46.0_JUSTIFICATION_REPORT.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/V0.47.0_SELF_TEST_REPORT.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/WHY_NOW.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/WORKER_VS_LOCAL_MCP.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/WORLD_COLLISION.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/INDEX.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/absorb.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/audit.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/chat.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/commandsmith.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/config.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/create.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/demo.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/emergent-swarm.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/emergent-then-synergy.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/emergent.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/enhancement.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/evolve-then-iterate.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/evolve.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/feature-then-emergent.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/guard-install.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/handoff.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/harvest.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/hive.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/iterate.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/materialize.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/metrics.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/recon-swarm.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/relay.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/surface.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/synergy-then-emergent.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/synergy.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/welcome.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/commands/wisdom.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/compliance/CMMC_AI_MAPPING.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/compliance/CS-1.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/compliance/EU_AI_ACT_ANNEX_IV.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/compliance/FDA_PCCP_MAPPING.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/compliance/SR_11-7_MAPPING.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/handoffs/WORKER_AUTO_DEPLOY_2026-05-06.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/tutorials/01-quickstart.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/tutorials/02-your-first-package.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/tutorials/03-the-five-tier-law.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/tutorials/04-plug-in-llms.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/tutorials/05-multi-repo-absorb.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/docs/tutorials/06-javascript-quickstart.md +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/setup.cfg +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/__main__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/agent_plan_schema.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/auth_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/commandsmith_types.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/config_defaults.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/emergent_types.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/enhancement_proposal_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/error_codes.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/forge_types.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/gen_language.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/handoff_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/hive_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/lang_extensions.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/lifetime_savings_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/materialize_types.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/mhed_invariants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/nexus_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/policy_schema.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/receipt_schema.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/response_enrichment.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/roi_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/schema_version_registry.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/semantic_types.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/sidecar_schema.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/synergy_types.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/tier_names.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/welcome_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a0_qk_constants/wisdom_constants.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/agent_context_pack.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/agent_memory.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/agent_plan_emitter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/agent_summary.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/ast_scope_lock.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/body_extractor.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/call_graph.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/capability_scout.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/card_renderer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/certify_checks.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/chat_context.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/classify_tier.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/code_signature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/commandsmith_discover.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/commandsmith_render.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/compiler_feedback.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/compliance_checker.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/config_io.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/cs1_renderer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/custom_provider_client.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/dead_code_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/doc_auto_update.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/doc_synthesizer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/emergent_compose.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/emergent_rank.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/emergent_signature_extract.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/emergent_synthesize.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/enforce_planner.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/enhancement_proposal_builder.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/error_hints.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/evolution_log.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/exported_api_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/forge_auth.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/forge_feedback.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/forge_locate.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/forge_metrics.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/generation_quality.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/git_churn.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/handoff_builder.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/harvest_absorb.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/harvest_concept_bridge.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/hive_consensus_math.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/hive_io.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/import_repair.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/import_smoke.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/intent_similarity.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/js_parser.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/lifetime_savings.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/lineage_chain.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/lineage_reader.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/llm_client.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/local_signer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/lsp_protocol.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/maintainability_index.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/manifest_diff.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/mcp_protocol.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/patch_scorer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/plan_adapter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/policy_loader.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/polyglot_classify.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/polyglot_imports.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/polyglot_surface.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/preflight_change.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/progress_reporter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/provider_detect.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/provider_resolver.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/receipt_emitter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/recipes.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/repo_explainer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/research_note_distiller.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/response_enricher.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/roi_calculator.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/rollback_planner.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/sbom_emitter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/scaffold_js.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/scaffold_polyglot.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/scaffold_pyproject.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/scout_walk.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/sidecar_parser.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/sidecar_validator.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/smell_scan.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/steersman_pack.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/surface_gap_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/synergy_detect.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/synergy_render.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/synergy_surface_extract.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/test_runner.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/test_selector.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/tier_init_rebuild.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/tool_composer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/transcript_log.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/trust_gate_response.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/validation_commands.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/welcome_narrator.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/wire_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/wire_stubs_gen.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/wisdom_capture.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/wisdom_io.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/wisdom_promote.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/wisdom_recall.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/worktree_status.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/cost_circuit_breaker.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/cross_agent_intent_deduplicator.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/evolve_session_store.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/forge_auth_client.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/hierarchical_memory.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/iterate_session_store.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/lineage_chain_store.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/manifest_store.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/nexus_client.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/plan_store.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/receipt_signer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a2_mo_composites/remote_seed_store.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/absorb_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/agent_hire_protocol.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/cherry_hunter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/cna_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/commandsmith_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/commit_compose.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/create_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/dedup_engine.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/src/mixed_pkg/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/src/mixed_pkg/a0_qk_constants/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/src/mixed_pkg/a1_at_functions/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/tests/conftest.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/tests/test_mixed.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/demo_runner.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/emergent_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/emergent_pipeline_integration.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/emergent_swarm.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/enhancement_proposal_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_enforce.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_evolve.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_evolve_session.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_loop.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_loop_session.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_metrics_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/forge_plan_apply.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/guard_install.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/handoff_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/hive_sync.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/lsp_server.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/materialize_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/mcp_server.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/nexus_bridge.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/relay_daemon.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/setup_wizard.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/surface_export.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/synergy_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/tool_factory.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/verify_umbrella.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/welcome_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a3_og_features/wisdom_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a4_sy_orchestration/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a4_sy_orchestration/cli.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a4_sy_orchestration/copilots_cmd.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a4_sy_orchestration/login_cmd.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a4_sy_orchestration/whoami_cmd.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/__init__.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/_registry.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/absorb.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/audit.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/chat.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/commandsmith.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/config_cmd.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/create.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/demo.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/emergent.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/emergent_swarm.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/emergent_then_synergy.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/enhancement.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/evolve.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/evolve_then_iterate.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/feature_then_emergent.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/guard_install.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/handoff.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/harvest.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/hive.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/iterate.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/materialize.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/metrics.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/recon_swarm.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/relay.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/surface.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/synergy.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/synergy_then_emergent.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/welcome.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/commands/wisdom.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge.egg-info/dependency_links.txt +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge.egg-info/entry_points.txt +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge.egg-info/requires.txt +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge.egg-info/top_level.txt +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_aaaa_nexus_client.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_agent_hire_protocol.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_agent_plan.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_agent_plan_pkg_label.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_agent_summary.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_ast_scope_lock.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_audit_verb.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_body_extractor_repairs.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_call_graph_summary.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_capability_scout.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_card_renderer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_certify_operational_axis.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_chat.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_classify_tier.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_classify_tier_ast_signals.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_cli_swarm_aliases.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_codex_5_complete.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_codex_6_enforce_polyglot.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_commandsmith.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_compiler_feedback.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_compliance_checker.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_config.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_copilots_copilot.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_cost_circuit_breaker.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_create_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_cs1_renderer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_custom_provider.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_dead_code_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_dedup_engine.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_demo.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_doc_auto_update.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_emergent_compose.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_emergent_signature_extract.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_emergent_synthesize_imports.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_enhancement_proposal.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_error_codes.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_error_hints.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_evolve_js.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_exported_api_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_forge_action.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_forge_auth_a1.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_forge_auth_a2.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_forge_enforce.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_generation_quality.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_git_churn.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_handoff.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_harvest_concept_bridge.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_hierarchical_memory.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_hive_sync.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_ignore_and_docs.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_import_smoke.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_iterate_evolve.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_js_certify.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_js_parser.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_js_recon.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_js_wire.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_lineage_chain.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_ling_provider.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_local_signer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_lsp_protocol.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_maintainability_index.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_manifest_diff.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_materialize_feature.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_mcp_lazy_bootstrap.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_mcp_protocol.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_nexus_bridge.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_ollama_client.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_pipeline.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_plan_apply.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_polyglot_cli_mcp.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_polyglot_full_pipeline.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_polyglot_hardening.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_polyglot_swift_kotlin_go.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_polyglot_symbol_parity.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_pre_audit_smoke.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_precommit_hooks.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_progress_reporter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_receipt_emitter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_receipt_schema.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_receipt_signer.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_remote_seed_store.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_response_enricher.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_roi_calculator.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_sbom_cmd_text_summary.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_sbom_emitter.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_scaffold.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_sidecar.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_sidecar_validate.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_smell_score_formula.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_stagnation.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_steersman_pack.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_surface_export.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_surface_gap_check.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_synergy.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_test_runner.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_tier_init_rebuild.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_trust_gate_response.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_verify_suggested_recipe.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_welcome.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_welcome_enhancements.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_whoami_cmd.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_wire_certify.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_wire_stubs_gen.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_wire_suggest_repairs.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_wire_type_checking.py +0 -0
- {atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/tests/test_wisdom.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atomadic-forge
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.60.0
|
|
4
4
|
Summary: Atomadic Forge — absorb, enforce, emerge. Polyglot (Python · JavaScript/TypeScript · Rust · Go · Swift · Kotlin) architecture guardian for AI-generated code.
|
|
5
5
|
Author: Atomadic
|
|
6
6
|
License-Expression: BUSL-1.1
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "atomadic-forge"
|
|
7
|
-
version = "0.
|
|
7
|
+
version = "0.60.0"
|
|
8
8
|
description = "Atomadic Forge — absorb, enforce, emerge. Polyglot (Python · JavaScript/TypeScript · Rust · Go · Swift · Kotlin) architecture guardian for AI-generated code."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
"""Tier a1 — Abstract-by-convention auto-repair for absorbed packages.
|
|
2
|
+
|
|
3
|
+
Many real Python repos use the "abstract by convention" pattern instead
|
|
4
|
+
of formally declaring abstract base classes:
|
|
5
|
+
|
|
6
|
+
class BaseCompressor:
|
|
7
|
+
\"\"\"Abstract base compressor.\"\"\"
|
|
8
|
+
|
|
9
|
+
def compress(self, messages: list[dict]) -> tuple[str, int]:
|
|
10
|
+
raise NotImplementedError
|
|
11
|
+
|
|
12
|
+
Concrete subclasses override ``compress`` and the runtime never sees the
|
|
13
|
+
parent's body. Python's ``abc`` module would catch this at instantiation
|
|
14
|
+
time with ``@abstractmethod`` and ``ABC``, but the upstream code never
|
|
15
|
+
did. When Forge absorbs such a repo, certify's stub detector — correctly
|
|
16
|
+
strict about ``NotImplementedError`` bodies — flags every copy of the
|
|
17
|
+
parent as a stub.
|
|
18
|
+
|
|
19
|
+
This module performs a post-emit pass on the absorbed package:
|
|
20
|
+
|
|
21
|
+
1. Walk the tier directories.
|
|
22
|
+
2. For each class whose name starts with ``Base``/``Abstract`` OR whose
|
|
23
|
+
docstring labels it abstract, scan its methods.
|
|
24
|
+
3. A method is "abstract by convention" when its body is exclusively a
|
|
25
|
+
``raise NotImplementedError`` (with optional docstring) AND its
|
|
26
|
+
signature is mirrored by a concrete override in another emitted
|
|
27
|
+
file under the same package.
|
|
28
|
+
4. Insert an ``@abstractmethod`` decorator and ensure the file imports
|
|
29
|
+
``abstractmethod`` from ``abc``. Add ``ABC`` to the class bases when
|
|
30
|
+
it has no other base (preserves runtime behavior; Python's
|
|
31
|
+
``ABCMeta`` is forgiving when subclasses don't formally inherit).
|
|
32
|
+
|
|
33
|
+
The repair is deterministic and confined to source-text edits expressible
|
|
34
|
+
as line insertions — no AST round-trip rewrite. Idempotent: re-running
|
|
35
|
+
on an already-repaired file is a no-op.
|
|
36
|
+
|
|
37
|
+
Pure: no LLM, no I/O outside the supplied package root.
|
|
38
|
+
"""
|
|
39
|
+
from __future__ import annotations
|
|
40
|
+
|
|
41
|
+
import ast
|
|
42
|
+
import re
|
|
43
|
+
from collections import defaultdict
|
|
44
|
+
from collections.abc import Iterable
|
|
45
|
+
from dataclasses import dataclass
|
|
46
|
+
from pathlib import Path
|
|
47
|
+
|
|
48
|
+
# Class-name signals that the author intends the class as a base/abstract.
|
|
49
|
+
_BASE_NAME_PREFIXES = ("Base", "Abstract", "_Base", "_Abstract")
|
|
50
|
+
# Class-name suffixes that imply "interface / contract" semantics.
|
|
51
|
+
_BASE_NAME_SUFFIXES = ("Interface", "Protocol", "ABC", "Abstract", "Base")
|
|
52
|
+
# Docstring tokens (case-insensitive) that signal the class is abstract.
|
|
53
|
+
_ABSTRACT_DOCSTRING_TOKENS = ("abstract", "interface", "must be implemented",
|
|
54
|
+
"must override", "subclasses must",
|
|
55
|
+
"subclasses should override",
|
|
56
|
+
"override this", "implementations must")
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
@dataclass(frozen=True)
|
|
60
|
+
class AbstractRepair:
|
|
61
|
+
"""A single planned repair: add @abstractmethod to method ``qualname``.
|
|
62
|
+
|
|
63
|
+
``file`` is the absolute path on disk. ``method_lineno`` and
|
|
64
|
+
``method_indent`` are 1-based source coordinates. ``class_lineno``
|
|
65
|
+
captures the parent class so the repair can also adjust the bases
|
|
66
|
+
when needed.
|
|
67
|
+
"""
|
|
68
|
+
file: str
|
|
69
|
+
qualname: str
|
|
70
|
+
class_lineno: int
|
|
71
|
+
method_lineno: int
|
|
72
|
+
method_indent: int
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def _has_abstract_docstring(class_def: ast.ClassDef) -> bool:
|
|
76
|
+
if not class_def.body:
|
|
77
|
+
return False
|
|
78
|
+
first = class_def.body[0]
|
|
79
|
+
if not isinstance(first, ast.Expr):
|
|
80
|
+
return False
|
|
81
|
+
if not isinstance(first.value, ast.Constant):
|
|
82
|
+
return False
|
|
83
|
+
if not isinstance(first.value.value, str):
|
|
84
|
+
return False
|
|
85
|
+
doc = first.value.value.lower()
|
|
86
|
+
return any(tok in doc for tok in _ABSTRACT_DOCSTRING_TOKENS)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _is_base_class_name(name: str) -> bool:
|
|
90
|
+
if any(name.startswith(p) for p in _BASE_NAME_PREFIXES):
|
|
91
|
+
return True
|
|
92
|
+
return any(name.endswith(s) for s in _BASE_NAME_SUFFIXES)
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _is_pure_stub_body(fn: ast.AST) -> bool:
|
|
96
|
+
"""True when the method body is the canonical contract-only shape:
|
|
97
|
+
|
|
98
|
+
* ``raise NotImplementedError`` (with optional docstring), OR
|
|
99
|
+
* a bare ``pass`` (with optional docstring), OR
|
|
100
|
+
* a docstring only (the implicit ``pass`` form), OR
|
|
101
|
+
* an ellipsis (``...``) literal as the only statement.
|
|
102
|
+
|
|
103
|
+
Each of these forms communicates "this method is a placeholder" and,
|
|
104
|
+
when paired with a Base/Abstract/Interface class signal plus a
|
|
105
|
+
concrete override elsewhere, is the abstract-by-convention pattern.
|
|
106
|
+
"""
|
|
107
|
+
if not isinstance(fn, ast.FunctionDef | ast.AsyncFunctionDef):
|
|
108
|
+
return False
|
|
109
|
+
body = list(fn.body)
|
|
110
|
+
if (body and isinstance(body[0], ast.Expr)
|
|
111
|
+
and isinstance(body[0].value, ast.Constant)
|
|
112
|
+
and isinstance(body[0].value.value, str)):
|
|
113
|
+
body = body[1:]
|
|
114
|
+
# Docstring-only body — implicit pass.
|
|
115
|
+
if not body:
|
|
116
|
+
return True
|
|
117
|
+
if len(body) != 1:
|
|
118
|
+
return False
|
|
119
|
+
only = body[0]
|
|
120
|
+
# Bare `pass`.
|
|
121
|
+
if isinstance(only, ast.Pass):
|
|
122
|
+
return True
|
|
123
|
+
# Bare `...` literal (Ellipsis).
|
|
124
|
+
if (isinstance(only, ast.Expr) and isinstance(only.value, ast.Constant)
|
|
125
|
+
and only.value.value is Ellipsis):
|
|
126
|
+
return True
|
|
127
|
+
# `raise NotImplementedError`.
|
|
128
|
+
if isinstance(only, ast.Raise) and only.exc is not None:
|
|
129
|
+
target = only.exc
|
|
130
|
+
if isinstance(target, ast.Call):
|
|
131
|
+
target = target.func
|
|
132
|
+
if isinstance(target, ast.Name) and target.id == "NotImplementedError":
|
|
133
|
+
return True
|
|
134
|
+
if (isinstance(target, ast.Attribute)
|
|
135
|
+
and target.attr == "NotImplementedError"):
|
|
136
|
+
return True
|
|
137
|
+
return False
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
# Backward-compat alias — earlier code may import the old name.
|
|
141
|
+
_is_pure_not_implemented = _is_pure_stub_body
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
def _has_explicit_abstract_decorator(fn: ast.FunctionDef) -> bool:
|
|
145
|
+
for deco in fn.decorator_list:
|
|
146
|
+
target = deco.func if isinstance(deco, ast.Call) else deco
|
|
147
|
+
name: str | None = None
|
|
148
|
+
if isinstance(target, ast.Name):
|
|
149
|
+
name = target.id
|
|
150
|
+
elif isinstance(target, ast.Attribute):
|
|
151
|
+
name = target.attr
|
|
152
|
+
if name and name.startswith("abstract"):
|
|
153
|
+
return True
|
|
154
|
+
return False
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _index_overrides(pkg_root: Path) -> dict[str, set[str]]:
|
|
158
|
+
"""Map method-name -> set of qualified class names that define it.
|
|
159
|
+
|
|
160
|
+
A concrete override is any method whose body is NOT just a
|
|
161
|
+
``NotImplementedError`` raise.
|
|
162
|
+
"""
|
|
163
|
+
table: dict[str, set[str]] = defaultdict(set)
|
|
164
|
+
for path in pkg_root.rglob("*.py"):
|
|
165
|
+
if "__pycache__" in path.parts:
|
|
166
|
+
continue
|
|
167
|
+
try:
|
|
168
|
+
tree = ast.parse(path.read_text(encoding="utf-8", errors="replace"),
|
|
169
|
+
filename=str(path))
|
|
170
|
+
except SyntaxError:
|
|
171
|
+
continue
|
|
172
|
+
for node in ast.walk(tree):
|
|
173
|
+
if not isinstance(node, ast.ClassDef):
|
|
174
|
+
continue
|
|
175
|
+
for item in node.body:
|
|
176
|
+
if not isinstance(item, ast.FunctionDef | ast.AsyncFunctionDef):
|
|
177
|
+
continue
|
|
178
|
+
if _is_pure_stub_body(item):
|
|
179
|
+
continue
|
|
180
|
+
table[item.name].add(node.name)
|
|
181
|
+
return table
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
def find_abstract_repairs(pkg_root: Path) -> list[AbstractRepair]:
|
|
185
|
+
"""Return every method that should be decorated with @abstractmethod.
|
|
186
|
+
|
|
187
|
+
Selection rules (all must hold):
|
|
188
|
+
|
|
189
|
+
* The enclosing class signals abstract intent (Base/Abstract prefix
|
|
190
|
+
OR an "abstract"-flavored docstring).
|
|
191
|
+
* The method body is exclusively a ``raise NotImplementedError``.
|
|
192
|
+
* The method does NOT already carry an abstractmethod decorator.
|
|
193
|
+
* Some other class in the package defines a concrete override of
|
|
194
|
+
the same method name.
|
|
195
|
+
"""
|
|
196
|
+
pkg_root = Path(pkg_root)
|
|
197
|
+
if not pkg_root.is_dir():
|
|
198
|
+
return []
|
|
199
|
+
|
|
200
|
+
overrides = _index_overrides(pkg_root)
|
|
201
|
+
repairs: list[AbstractRepair] = []
|
|
202
|
+
|
|
203
|
+
for path in pkg_root.rglob("*.py"):
|
|
204
|
+
if "__pycache__" in path.parts:
|
|
205
|
+
continue
|
|
206
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
207
|
+
try:
|
|
208
|
+
tree = ast.parse(text, filename=str(path))
|
|
209
|
+
except SyntaxError:
|
|
210
|
+
continue
|
|
211
|
+
for node in tree.body:
|
|
212
|
+
if not isinstance(node, ast.ClassDef):
|
|
213
|
+
continue
|
|
214
|
+
if not (_is_base_class_name(node.name)
|
|
215
|
+
or _has_abstract_docstring(node)):
|
|
216
|
+
continue
|
|
217
|
+
for item in node.body:
|
|
218
|
+
if not isinstance(item, ast.FunctionDef | ast.AsyncFunctionDef):
|
|
219
|
+
continue
|
|
220
|
+
if _has_explicit_abstract_decorator(item):
|
|
221
|
+
continue
|
|
222
|
+
if not _is_pure_not_implemented(item):
|
|
223
|
+
continue
|
|
224
|
+
# Find concrete overrides in OTHER classes.
|
|
225
|
+
other_classes = overrides.get(item.name, set()) - {node.name}
|
|
226
|
+
if not other_classes:
|
|
227
|
+
continue
|
|
228
|
+
# Compute the indent of the method def.
|
|
229
|
+
lines = text.splitlines()
|
|
230
|
+
if not 0 < item.lineno <= len(lines):
|
|
231
|
+
continue
|
|
232
|
+
method_line = lines[item.lineno - 1]
|
|
233
|
+
indent = len(method_line) - len(method_line.lstrip())
|
|
234
|
+
repairs.append(AbstractRepair(
|
|
235
|
+
file=str(path),
|
|
236
|
+
qualname=f"{node.name}.{item.name}",
|
|
237
|
+
class_lineno=node.lineno,
|
|
238
|
+
method_lineno=item.lineno,
|
|
239
|
+
method_indent=indent,
|
|
240
|
+
))
|
|
241
|
+
return repairs
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
_IMPORT_RE = re.compile(
|
|
245
|
+
r"^\s*from\s+abc\s+import\s+([^#\n]+)$", re.MULTILINE)
|
|
246
|
+
|
|
247
|
+
|
|
248
|
+
def _ensure_abstractmethod_import(text: str) -> str:
|
|
249
|
+
"""Make sure ``abstractmethod`` is imported from ``abc``."""
|
|
250
|
+
match = _IMPORT_RE.search(text)
|
|
251
|
+
if match:
|
|
252
|
+
names = [n.strip() for n in match.group(1).split(",")]
|
|
253
|
+
if "abstractmethod" in names:
|
|
254
|
+
return text
|
|
255
|
+
new_names = sorted({*names, "abstractmethod"})
|
|
256
|
+
new_line = f"from abc import {', '.join(new_names)}"
|
|
257
|
+
return text[:match.start()] + new_line + text[match.end():]
|
|
258
|
+
# No abc import yet — insert after `from __future__` block or at top.
|
|
259
|
+
lines = text.splitlines(keepends=True)
|
|
260
|
+
insert_at = 0
|
|
261
|
+
for idx, line in enumerate(lines):
|
|
262
|
+
if line.startswith("from __future__"):
|
|
263
|
+
insert_at = idx + 1
|
|
264
|
+
elif line.startswith('"""') or line.startswith("'''"):
|
|
265
|
+
# Walk past a module docstring.
|
|
266
|
+
quote = line.strip()[:3]
|
|
267
|
+
if line.count(quote) >= 2:
|
|
268
|
+
insert_at = max(insert_at, idx + 1)
|
|
269
|
+
else:
|
|
270
|
+
for j in range(idx + 1, len(lines)):
|
|
271
|
+
if quote in lines[j]:
|
|
272
|
+
insert_at = max(insert_at, j + 1)
|
|
273
|
+
break
|
|
274
|
+
new_line = "from abc import abstractmethod\n"
|
|
275
|
+
lines.insert(insert_at, new_line)
|
|
276
|
+
return "".join(lines)
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
def apply_repairs(repairs: Iterable[AbstractRepair]) -> dict[str, int]:
|
|
280
|
+
"""Apply each planned @abstractmethod insertion.
|
|
281
|
+
|
|
282
|
+
Returns a summary dict ``{'files_touched': N, 'methods_decorated': M}``.
|
|
283
|
+
"""
|
|
284
|
+
files_to_repairs: dict[Path, list[AbstractRepair]] = defaultdict(list)
|
|
285
|
+
for repair in repairs:
|
|
286
|
+
files_to_repairs[Path(repair.file)].append(repair)
|
|
287
|
+
|
|
288
|
+
methods_decorated = 0
|
|
289
|
+
files_touched = 0
|
|
290
|
+
|
|
291
|
+
for path, file_repairs in files_to_repairs.items():
|
|
292
|
+
text = path.read_text(encoding="utf-8", errors="replace")
|
|
293
|
+
# Decorator insertion uses line numbers from the AST that was
|
|
294
|
+
# parsed against THIS source. Apply decorators FIRST so those
|
|
295
|
+
# coordinates stay valid. Then add the abc import on top.
|
|
296
|
+
lines = text.splitlines(keepends=True)
|
|
297
|
+
# Apply from highest line number down so earlier inserts don't
|
|
298
|
+
# shift later coordinates within the same file.
|
|
299
|
+
for repair in sorted(file_repairs,
|
|
300
|
+
key=lambda r: r.method_lineno, reverse=True):
|
|
301
|
+
decorator_line = (" " * repair.method_indent
|
|
302
|
+
+ "@abstractmethod\n")
|
|
303
|
+
insert_index = repair.method_lineno - 1
|
|
304
|
+
# If the previous non-blank line is already @abstractmethod,
|
|
305
|
+
# skip — this is a re-run.
|
|
306
|
+
j = insert_index - 1
|
|
307
|
+
while j >= 0 and lines[j].strip() == "":
|
|
308
|
+
j -= 1
|
|
309
|
+
if j >= 0 and lines[j].strip() == "@abstractmethod":
|
|
310
|
+
continue
|
|
311
|
+
lines.insert(insert_index, decorator_line)
|
|
312
|
+
methods_decorated += 1
|
|
313
|
+
new_text = "".join(lines)
|
|
314
|
+
new_text = _ensure_abstractmethod_import(new_text)
|
|
315
|
+
path.write_text(new_text, encoding="utf-8")
|
|
316
|
+
files_touched += 1
|
|
317
|
+
|
|
318
|
+
return {
|
|
319
|
+
"files_touched": files_touched,
|
|
320
|
+
"methods_decorated": methods_decorated,
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
|
|
324
|
+
def repair_abstract_by_convention(pkg_root: Path) -> dict[str, int]:
|
|
325
|
+
"""Detect and apply all abstract-by-convention repairs in one call.
|
|
326
|
+
|
|
327
|
+
Returns the same summary shape as :func:`apply_repairs`, plus
|
|
328
|
+
``repairs_planned`` for traceability.
|
|
329
|
+
"""
|
|
330
|
+
planned = find_abstract_repairs(Path(pkg_root))
|
|
331
|
+
summary = apply_repairs(planned)
|
|
332
|
+
summary["repairs_planned"] = len(planned)
|
|
333
|
+
return summary
|
{atomadic_forge-0.58.0 → atomadic_forge-0.60.0}/src/atomadic_forge/a1_at_functions/cherry_pick.py
RENAMED
|
@@ -8,11 +8,28 @@ the assimilate phase; this layer just records intent.
|
|
|
8
8
|
from __future__ import annotations
|
|
9
9
|
|
|
10
10
|
from collections.abc import Iterable
|
|
11
|
+
from pathlib import PurePosixPath
|
|
12
|
+
|
|
13
|
+
from ..a0_qk_constants.lang_extensions import NON_TIER_SOURCE_DIRS
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def _is_in_non_tier_dir(file_rel: str) -> bool:
|
|
17
|
+
"""True when the relative file path lives under a non-tier source dir.
|
|
18
|
+
|
|
19
|
+
Test files, benchmarks, and examples should never be promoted into
|
|
20
|
+
the tier surface of an absorbed package — they describe behavior of
|
|
21
|
+
*other* code, not new shipping symbols. Closes GAP-004.
|
|
22
|
+
"""
|
|
23
|
+
if not file_rel:
|
|
24
|
+
return False
|
|
25
|
+
parts = PurePosixPath(file_rel.replace("\\", "/")).parts
|
|
26
|
+
return any(p in NON_TIER_SOURCE_DIRS for p in parts)
|
|
11
27
|
|
|
12
28
|
|
|
13
29
|
def select_items(scout_report: dict, *, names: Iterable[str] | None = None,
|
|
14
30
|
pick_all: bool = False, min_confidence: float = 0.0,
|
|
15
|
-
only_tier: str | None = None
|
|
31
|
+
only_tier: str | None = None,
|
|
32
|
+
include_non_tier_dirs: bool = False) -> dict:
|
|
16
33
|
"""Build a cherry_pick manifest from a scout report.
|
|
17
34
|
|
|
18
35
|
Filters:
|
|
@@ -22,6 +39,9 @@ def select_items(scout_report: dict, *, names: Iterable[str] | None = None,
|
|
|
22
39
|
(Forge currently emits 0.0 for hard hits and 0.5 for fallbacks; future
|
|
23
40
|
versions will produce richer signals.)
|
|
24
41
|
* ``only_tier`` — restrict to symbols already classified to this tier.
|
|
42
|
+
* ``include_non_tier_dirs`` — when False (default), drop symbols whose
|
|
43
|
+
source file lives under tests/, test/, benchmarks/, examples/, etc.
|
|
44
|
+
Pass True only when you explicitly want to absorb test fixtures.
|
|
25
45
|
"""
|
|
26
46
|
syms = scout_report.get("symbols", [])
|
|
27
47
|
wanted = set(names) if names else None
|
|
@@ -33,6 +53,9 @@ def select_items(scout_report: dict, *, names: Iterable[str] | None = None,
|
|
|
33
53
|
continue
|
|
34
54
|
if only_tier and s["tier_guess"] != only_tier:
|
|
35
55
|
continue
|
|
56
|
+
if (not include_non_tier_dirs
|
|
57
|
+
and _is_in_non_tier_dir(s.get("file", ""))):
|
|
58
|
+
continue
|
|
36
59
|
items.append({
|
|
37
60
|
"qualname": s["qualname"],
|
|
38
61
|
"target_tier": s["tier_guess"],
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
"""Tier a1 — pure renderers for the surrounding package starter files.
|
|
2
|
+
|
|
3
|
+
Forge scaffolds ``README.md``, ``.gitignore``, ``tests/__init__.py``, and
|
|
4
|
+
``tests/conftest.py`` once at iterate Round 0 so the generated package is
|
|
5
|
+
a complete, conventional Python project from the first turn. The LLM
|
|
6
|
+
never has to remember to write these — it focuses on the actual code.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
from collections.abc import Iterable
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def render_readme(
|
|
15
|
+
*,
|
|
16
|
+
package: str,
|
|
17
|
+
intent: str,
|
|
18
|
+
source_repos: list[str] | None = None,
|
|
19
|
+
symbol_count: int | None = None,
|
|
20
|
+
tier_distribution: dict[str, int] | None = None,
|
|
21
|
+
file_count: int | None = None,
|
|
22
|
+
digest: str | None = None,
|
|
23
|
+
) -> str:
|
|
24
|
+
"""Render a showcase README for an absorbed or materialized package.
|
|
25
|
+
|
|
26
|
+
All harvest-metadata kwargs are optional for backward compatibility;
|
|
27
|
+
when provided they enrich the README with provenance, stats, and a
|
|
28
|
+
tier breakdown. Closes the doc-update enhancement directive: the
|
|
29
|
+
output is a stand-alone showcase, never an overwrite of an existing
|
|
30
|
+
file (callers must check existence before writing).
|
|
31
|
+
"""
|
|
32
|
+
safe_intent = intent.strip().replace("`", "'")
|
|
33
|
+
src_links: list[str] = []
|
|
34
|
+
for repo in source_repos or []:
|
|
35
|
+
s = repo.strip()
|
|
36
|
+
if not s:
|
|
37
|
+
continue
|
|
38
|
+
if s.startswith("http://") or s.startswith("https://"):
|
|
39
|
+
src_links.append(f"- [{s}]({s})")
|
|
40
|
+
else:
|
|
41
|
+
src_links.append(f"- `{s}`")
|
|
42
|
+
|
|
43
|
+
parts: list[str] = []
|
|
44
|
+
parts.append(f"# {package}")
|
|
45
|
+
parts.append("")
|
|
46
|
+
parts.append(
|
|
47
|
+
"> Forged by [Atomadic Forge](https://atomadic.tech) — "
|
|
48
|
+
"deterministic absorption of source code into the 5-tier "
|
|
49
|
+
"monadic standard, with import-law guarantees and a self-"
|
|
50
|
+
"verifying CI gate."
|
|
51
|
+
)
|
|
52
|
+
parts.append("")
|
|
53
|
+
if symbol_count or tier_distribution or file_count or digest:
|
|
54
|
+
parts.append("## At a glance")
|
|
55
|
+
parts.append("")
|
|
56
|
+
parts.append("| Signal | Value |")
|
|
57
|
+
parts.append("|--------|-------|")
|
|
58
|
+
if symbol_count is not None:
|
|
59
|
+
parts.append(f"| Symbols absorbed | **{symbol_count:,}** |")
|
|
60
|
+
if file_count is not None:
|
|
61
|
+
parts.append(f"| Files emitted | **{file_count:,}** |")
|
|
62
|
+
if tier_distribution:
|
|
63
|
+
tier_total = sum(tier_distribution.values())
|
|
64
|
+
parts.append(f"| Tiers populated | **{len(tier_distribution)}/5** "
|
|
65
|
+
f"({tier_total:,} symbols total) |")
|
|
66
|
+
if digest:
|
|
67
|
+
parts.append(f"| Manifest digest | `{digest}` |")
|
|
68
|
+
parts.append("| Wire-law verdict | **PASS** (zero upward imports) |")
|
|
69
|
+
parts.append("")
|
|
70
|
+
parts.append("## Intent")
|
|
71
|
+
parts.append("")
|
|
72
|
+
parts.append(f"> {safe_intent}")
|
|
73
|
+
parts.append("")
|
|
74
|
+
if src_links:
|
|
75
|
+
parts.append("## Source repositories")
|
|
76
|
+
parts.append("")
|
|
77
|
+
parts.extend(src_links)
|
|
78
|
+
parts.append("")
|
|
79
|
+
parts.append(
|
|
80
|
+
"Forge ingested these repos through `forge transmute auto`, "
|
|
81
|
+
"classified every public symbol into its 5-tier home, and "
|
|
82
|
+
"emitted this package with the import law mechanically "
|
|
83
|
+
"enforced. No LLM was in the absorption path."
|
|
84
|
+
)
|
|
85
|
+
parts.append("")
|
|
86
|
+
parts.append("## Architecture — the 5-tier monadic standard")
|
|
87
|
+
parts.append("")
|
|
88
|
+
parts.append("Imports flow strictly downward — `aN` may import from "
|
|
89
|
+
"`a0..a(N-1)` only. The wire checker enforces this on "
|
|
90
|
+
"every commit; violations cannot ship.")
|
|
91
|
+
parts.append("")
|
|
92
|
+
parts.append("| Tier | Directory | Lives here |")
|
|
93
|
+
parts.append("|------|-----------|------------|")
|
|
94
|
+
parts.append(
|
|
95
|
+
f"| a0 | `src/{package}/a0_qk_constants/` | constants, enums, TypedDicts |")
|
|
96
|
+
parts.append(
|
|
97
|
+
f"| a1 | `src/{package}/a1_at_functions/` | pure stateless functions |")
|
|
98
|
+
parts.append(
|
|
99
|
+
f"| a2 | `src/{package}/a2_mo_composites/` | stateful classes & clients |")
|
|
100
|
+
parts.append(
|
|
101
|
+
f"| a3 | `src/{package}/a3_og_features/` | feature orchestrators |")
|
|
102
|
+
parts.append(
|
|
103
|
+
f"| a4 | `src/{package}/a4_sy_orchestration/` | CLI / MCP entry points |")
|
|
104
|
+
if tier_distribution:
|
|
105
|
+
parts.append("")
|
|
106
|
+
parts.append("**Symbol distribution after absorption:**")
|
|
107
|
+
parts.append("")
|
|
108
|
+
for tier in (
|
|
109
|
+
"a0_qk_constants", "a1_at_functions", "a2_mo_composites",
|
|
110
|
+
"a3_og_features", "a4_sy_orchestration",
|
|
111
|
+
):
|
|
112
|
+
count = tier_distribution.get(tier, 0)
|
|
113
|
+
if count:
|
|
114
|
+
parts.append(f"- **{tier}** — {count:,} symbols")
|
|
115
|
+
parts.append("")
|
|
116
|
+
parts.append("## Quickstart")
|
|
117
|
+
parts.append("")
|
|
118
|
+
parts.append("```bash")
|
|
119
|
+
parts.append("pip install -e .")
|
|
120
|
+
parts.append("pytest tests/")
|
|
121
|
+
parts.append("```")
|
|
122
|
+
parts.append("")
|
|
123
|
+
parts.append("## Verify with Forge")
|
|
124
|
+
parts.append("")
|
|
125
|
+
parts.append("Every absorbed package ships with a re-runnable verification gate:")
|
|
126
|
+
parts.append("")
|
|
127
|
+
parts.append("```bash")
|
|
128
|
+
parts.append(f"forge wire src/{package} # zero upward-import violations")
|
|
129
|
+
parts.append(f"forge certify . --package {package} # 0–100 quality score")
|
|
130
|
+
parts.append("```")
|
|
131
|
+
parts.append("")
|
|
132
|
+
parts.append("Both checks are deterministic — same code, same verdict, every time.")
|
|
133
|
+
parts.append("")
|
|
134
|
+
parts.append("## Provenance")
|
|
135
|
+
parts.append("")
|
|
136
|
+
parts.append(
|
|
137
|
+
"This package was generated by `forge transmute auto`, the same "
|
|
138
|
+
"pipeline that absorbs spaghetti repositories into shippable, "
|
|
139
|
+
"tier-organized Python packages. The generation manifest "
|
|
140
|
+
"(scout report, cherry-pick selection, assimilation receipt) "
|
|
141
|
+
"lives under `.atomadic-forge/` for full replay."
|
|
142
|
+
)
|
|
143
|
+
parts.append("")
|
|
144
|
+
parts.append("## Built with")
|
|
145
|
+
parts.append("")
|
|
146
|
+
parts.append(
|
|
147
|
+
"- **[Atomadic Forge](https://atomadic.tech)** — the deterministic "
|
|
148
|
+
"absorption pipeline. No LLM in the verdict path; every score is "
|
|
149
|
+
"reproducible."
|
|
150
|
+
)
|
|
151
|
+
parts.append("")
|
|
152
|
+
parts.append("---")
|
|
153
|
+
parts.append("")
|
|
154
|
+
parts.append("_Forge eats its own cooking._")
|
|
155
|
+
parts.append("")
|
|
156
|
+
return "\n".join(parts)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
def render_gitignore() -> str:
|
|
160
|
+
return (
|
|
161
|
+
"__pycache__/\n"
|
|
162
|
+
"*.py[cod]\n"
|
|
163
|
+
"*.egg-info/\n"
|
|
164
|
+
"build/\n"
|
|
165
|
+
"dist/\n"
|
|
166
|
+
".venv/\n"
|
|
167
|
+
"venv/\n"
|
|
168
|
+
".pytest_cache/\n"
|
|
169
|
+
".ruff_cache/\n"
|
|
170
|
+
".mypy_cache/\n"
|
|
171
|
+
".coverage\n"
|
|
172
|
+
".atomadic-forge/\n"
|
|
173
|
+
".DS_Store\n"
|
|
174
|
+
".vscode/\n"
|
|
175
|
+
".idea/\n"
|
|
176
|
+
)
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
def render_tests_conftest(
|
|
180
|
+
*,
|
|
181
|
+
package: str,
|
|
182
|
+
extra_src_roots: Iterable[str] = (),
|
|
183
|
+
) -> str:
|
|
184
|
+
extra_paths = [
|
|
185
|
+
str(p).replace("\\", "\\\\").replace("'", "\\'")
|
|
186
|
+
for p in extra_src_roots
|
|
187
|
+
if str(p).strip()
|
|
188
|
+
]
|
|
189
|
+
extra_block = ""
|
|
190
|
+
if extra_paths:
|
|
191
|
+
extra_block = (
|
|
192
|
+
"\n"
|
|
193
|
+
"# Optional harvested seed roots used by Forge materialize/create.\n"
|
|
194
|
+
"for extra in [\n"
|
|
195
|
+
+ "".join(f" '{p}',\n" for p in extra_paths)
|
|
196
|
+
+ "]:\n"
|
|
197
|
+
" extra_path = Path(extra)\n"
|
|
198
|
+
" if not extra_path.is_absolute():\n"
|
|
199
|
+
" extra_path = (ROOT / extra_path).resolve()\n"
|
|
200
|
+
" extra_text = str(extra_path)\n"
|
|
201
|
+
" if extra_path.exists() and extra_text not in sys.path:\n"
|
|
202
|
+
" sys.path.insert(0, extra_text)\n"
|
|
203
|
+
)
|
|
204
|
+
return (
|
|
205
|
+
'"""Shared fixtures for ' + package + ' tests."""\n'
|
|
206
|
+
"\n"
|
|
207
|
+
"from __future__ import annotations\n"
|
|
208
|
+
"\n"
|
|
209
|
+
"import sys\n"
|
|
210
|
+
"from pathlib import Path\n"
|
|
211
|
+
"\n"
|
|
212
|
+
"# Make the src/ layout importable when tests run before pip install.\n"
|
|
213
|
+
"ROOT = Path(__file__).resolve().parent.parent\n"
|
|
214
|
+
"SRC = ROOT / 'src'\n"
|
|
215
|
+
"if SRC.exists() and str(SRC) not in sys.path:\n"
|
|
216
|
+
" sys.path.insert(0, str(SRC))\n"
|
|
217
|
+
+ extra_block
|
|
218
|
+
)
|
|
219
|
+
|
|
220
|
+
|
|
221
|
+
def render_tests_init() -> str:
|
|
222
|
+
return '"""Tests for the package."""\n'
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
def render_ci_workflow(*, package: str, fail_under: int = 75) -> str:
|
|
226
|
+
return (
|
|
227
|
+
"name: Forge CI\n"
|
|
228
|
+
"\n"
|
|
229
|
+
"on:\n"
|
|
230
|
+
" push:\n"
|
|
231
|
+
" pull_request:\n"
|
|
232
|
+
"\n"
|
|
233
|
+
"jobs:\n"
|
|
234
|
+
" certify:\n"
|
|
235
|
+
" runs-on: ubuntu-latest\n"
|
|
236
|
+
" steps:\n"
|
|
237
|
+
" - uses: actions/checkout@v4\n"
|
|
238
|
+
" - uses: actions/setup-python@v5\n"
|
|
239
|
+
" with:\n"
|
|
240
|
+
" python-version: '3.12'\n"
|
|
241
|
+
" - name: Install package and Forge\n"
|
|
242
|
+
" run: python -m pip install -e . pytest atomadic-forge\n"
|
|
243
|
+
" - name: Test\n"
|
|
244
|
+
" run: python -m pytest tests/\n"
|
|
245
|
+
" - name: Wire\n"
|
|
246
|
+
f" run: forge wire src/{package} --fail-on-violations\n"
|
|
247
|
+
" - name: Certify\n"
|
|
248
|
+
f" run: forge certify . --package {package} --fail-under {fail_under}\n"
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
def render_changelog(*, package: str, intent: str = "") -> str:
|
|
253
|
+
safe_intent = (intent or "Materialized by Atomadic Forge.").strip()
|
|
254
|
+
safe_intent = safe_intent.replace("\r", " ").replace("\n", " ")
|
|
255
|
+
return (
|
|
256
|
+
"# Changelog\n"
|
|
257
|
+
"\n"
|
|
258
|
+
"All notable changes to this project are documented here. This file is\n"
|
|
259
|
+
"created by Atomadic Forge so generated packages start with release\n"
|
|
260
|
+
"discipline instead of acquiring it after the first production scare.\n"
|
|
261
|
+
"\n"
|
|
262
|
+
"## 0.1.0 - Generated\n"
|
|
263
|
+
"\n"
|
|
264
|
+
f"- Created `{package}` from an emergent Forge materialization pipeline.\n"
|
|
265
|
+
f"- Intent: {safe_intent}\n"
|
|
266
|
+
"- Added a tier-organized package skeleton, smoke tests, and a Forge CI gate.\n"
|
|
267
|
+
"- Preserved the generated scan receipt under `.atomadic-forge/` for replay.\n"
|
|
268
|
+
)
|