atomadic-forge 0.3.3__tar.gz → 0.3.5__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.3.3 → atomadic_forge-0.3.5}/CHANGELOG.md +115 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/PKG-INFO +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/pyproject.toml +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/__init__.py +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a4_sy_orchestration/cli.py +14 -0
- atomadic_forge-0.3.5/src/atomadic_forge/a4_sy_orchestration/copilots_cmd.py +234 -0
- atomadic_forge-0.3.5/src/atomadic_forge/a4_sy_orchestration/whoami_cmd.py +159 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge.egg-info/PKG-INFO +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge.egg-info/SOURCES.txt +3 -0
- atomadic_forge-0.3.5/tests/test_whoami_cmd.py +126 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/actions/forge-action/README.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/actions/forge-action/action.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/dependabot.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/pull_request_template.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/workflows/ci.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/workflows/forge-self-certify.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/workflows/forge-studio-ci.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/.github/workflows/release.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/ARCHITECTURE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/CONTRIBUTING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/LICENSE +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/MANIFEST.in +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/README.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/SECURITY.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/assets/Atomadic-Forge-01.png +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/01-getting-started.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/02-commands.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/03-tutorial.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/04-llm-loops.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/05-faq.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/AGENTS_GUIDE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/AIR_GAPPED.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/CI_CD.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/CODEX_WALKTHROUGH.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/COMMANDS.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/FIRST_10_MINUTES.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/FORMALIZATION.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/LANDSCAPE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/MARKET_POSITIONING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/MULTI_REPO.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/README.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/RECEIPT.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/RELEASE_CHECKLIST.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/RELEASE_MESSAGING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/ROADMAP.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/SHOWCASE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/SIDECAR.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/STUDIO.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/WHY_NOW.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/INDEX.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/chat.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/commandsmith.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/config.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/demo.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/emergent-then-synergy.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/emergent.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/evolve-then-iterate.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/evolve.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/feature-then-emergent.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/iterate.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/synergy-then-emergent.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/commands/synergy.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/compliance/CMMC_AI_MAPPING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/compliance/CS-1.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/compliance/EU_AI_ACT_ANNEX_IV.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/compliance/FDA_PCCP_MAPPING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/compliance/SR_11-7_MAPPING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/tutorials/01-quickstart.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/tutorials/02-your-first-package.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/tutorials/03-the-five-tier-law.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/tutorials/04-plug-in-llms.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/tutorials/05-multi-repo-absorb.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/docs/tutorials/06-javascript-quickstart.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/setup.cfg +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/__main__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/agent_plan_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/auth_constants.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/commandsmith_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/config_defaults.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/emergent_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/error_codes.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/forge_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/gen_language.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/lang_extensions.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/policy_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/receipt_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/roi_constants.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/semantic_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/sidecar_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/synergy_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a0_qk_constants/tier_names.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/agent_context_pack.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/agent_memory.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/agent_plan_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/agent_summary.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/body_extractor.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/card_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/certify_checks.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/chat_context.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/cherry_pick.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/classify_tier.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/commandsmith_discover.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/commandsmith_render.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/compiler_feedback.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/compliance_checker.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/config_io.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/cs1_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/doc_synthesizer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/emergent_compose.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/emergent_rank.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/emergent_signature_extract.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/emergent_synthesize.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/enforce_planner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/error_hints.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/evolution_log.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/forge_auth.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/forge_feedback.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/generation_quality.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/import_repair.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/import_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/js_parser.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/lineage_chain.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/lineage_reader.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/llm_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/local_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/lsp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/manifest_diff.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/mcp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/patch_scorer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/plan_adapter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/policy_loader.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/preflight_change.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/progress_reporter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/provider_detect.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/provider_resolver.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/receipt_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/recipes.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/repo_explainer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/roi_calculator.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/rollback_planner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/sbom_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/scaffold_js.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/scaffold_pyproject.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/scaffold_starter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/scout_walk.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/sidecar_parser.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/sidecar_validator.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/stub_detector.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/synergy_detect.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/synergy_render.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/synergy_surface_extract.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/test_runner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/test_selector.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/tier_init_rebuild.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/tool_composer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/transcript_log.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a1_at_functions/wire_check.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a2_mo_composites/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a2_mo_composites/forge_auth_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a2_mo_composites/lineage_chain_store.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a2_mo_composites/manifest_store.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a2_mo_composites/plan_store.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a2_mo_composites/receipt_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/commandsmith_feature.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/src/mixed_pkg/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/src/mixed_pkg/a0_qk_constants/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/src/mixed_pkg/a1_at_functions/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/tests/conftest.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/tests/test_mixed.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/demo_runner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/emergent_feature.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/emergent_pipeline_integration.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/forge_enforce.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/forge_evolve.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/forge_loop.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/forge_pipeline.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/forge_plan_apply.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/lsp_server.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/mcp_server.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/setup_wizard.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a3_og_features/synergy_feature.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a4_sy_orchestration/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/a4_sy_orchestration/login_cmd.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/_registry.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/audit.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/chat.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/commandsmith.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/config_cmd.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/demo.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/emergent.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/emergent_then_synergy.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/evolve.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/evolve_then_iterate.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/feature_then_emergent.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/iterate.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/synergy.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge/commands/synergy_then_emergent.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge.egg-info/dependency_links.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge.egg-info/entry_points.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge.egg-info/requires.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/src/atomadic_forge.egg-info/top_level.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_aaaa_nexus_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_agent_plan.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_agent_summary.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_audit_verb.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_badge_worker.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_body_extractor_repairs.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_card_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_certify_operational_axis.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_chat.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_classify_tier.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_cli_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_codex_5_complete.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_codex_6_enforce_polyglot.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_commandsmith.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_compiler_feedback.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_compliance_checker.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_config.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_copilots_copilot.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_cs1_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_demo.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_emergent_compose.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_emergent_signature_extract.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_error_codes.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_error_hints.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_evolve_js.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_forge_action.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_forge_auth_a1.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_forge_auth_a2.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_forge_enforce.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_generation_quality.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_ignore_and_docs.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_import_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_iterate_evolve.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_js_certify.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_js_parser.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_js_recon.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_js_wire.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_lineage_chain.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_local_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_lsp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_manifest_diff.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_mcp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_ollama_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_pipeline.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_plan_apply.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_pre_audit_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_precommit_hooks.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_progress_reporter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_receipt_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_receipt_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_receipt_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_roi_calculator.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_sbom_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_scaffold.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_sidecar.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_sidecar_validate.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_stagnation.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_stub_detector.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_synergy.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_test_runner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_tier_init_rebuild.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_vscode_extension_manifest.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_wire_certify.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.5}/tests/test_wire_suggest_repairs.py +0 -0
|
@@ -1,5 +1,120 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.5 — Copilot's Copilot CLI parity + GUI version sync
|
|
4
|
+
|
|
5
|
+
The MCP exposes 21 tools. Until 0.3.5, only 12 of them had CLI
|
|
6
|
+
front-doors — the other 9 were JSON-RPC-only, which meant a developer
|
|
7
|
+
or agent shell-running `forge` couldn't sample the same intelligence
|
|
8
|
+
without spawning the MCP server, speaking JSON-RPC, and parsing
|
|
9
|
+
`content[0].text`. This release closes the gap.
|
|
10
|
+
|
|
11
|
+
### Added — 9 new top-level CLI verbs
|
|
12
|
+
|
|
13
|
+
Every MCP-only Codex tool now has a CLI sibling that prints JSON to
|
|
14
|
+
stdout, suitable for piping into `jq`, scripts, or an agent's Bash
|
|
15
|
+
subprocess:
|
|
16
|
+
|
|
17
|
+
| Verb | Codex # | What it does |
|
|
18
|
+
|---|---|---|
|
|
19
|
+
| `forge explain-repo <root>` | #6 | Humane operational orientation: one-liner + core flow + do_not_break list + important tests + release state |
|
|
20
|
+
| `forge score-patch [--file diff.patch]` | #3 | Patch risk scorer: arch / test / public-API / release risk + needs_human_review boolean |
|
|
21
|
+
| `forge select-tests <intent> --file ... --file ...` | #7 | Minimum + full-confidence test sets per intent; mirror-name matches plus tier-mate tests |
|
|
22
|
+
| `forge rollback-plan --file ... --file ...` | #11 | Structured undo plan: files to remove, caches to clean, docs to restore, tests to rerun, risk level |
|
|
23
|
+
| `forge compose-tools <goal>` | #9 | Tool-use planner: keyword → ordered MCP tool sequence (orient / release_check / fix_violation / before_edit / verify_patch) |
|
|
24
|
+
| `forge why-did-this-change <file>` | #5 | Agent memory: every lineage entry + plan event that touched the file |
|
|
25
|
+
| `forge what-failed-last-time <area>` | #5 | Failed / rolled-back plan events matching an area substring |
|
|
26
|
+
| `forge adapt-plan --cap apply --cap shell` | #8 | Capability-aware card filtering: tag each card with recommended_handling |
|
|
27
|
+
| `forge load-policy <root>` | #10 | Read `[tool.forge.agent]` from pyproject.toml (protected_files / release_gate / max_files_per_patch / require_human_review_for) |
|
|
28
|
+
|
|
29
|
+
All verbs default to JSON output. None mutate the repo.
|
|
30
|
+
|
|
31
|
+
### Why this matters for agents
|
|
32
|
+
|
|
33
|
+
Before 0.3.5, an agent that wanted to compose a release-check tool
|
|
34
|
+
chain had to either spawn `forge mcp serve`, hand-craft a tools/call
|
|
35
|
+
JSON-RPC envelope, send it over stdio, and parse the wrapped text
|
|
36
|
+
content — or skip the intelligence entirely. After 0.3.5, the same
|
|
37
|
+
agent runs:
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
forge compose-tools "release_check" | jq .steps
|
|
41
|
+
forge select-tests "fix(api): rate limit" --file src/api/limit.py
|
|
42
|
+
forge score-patch --file my.diff
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Three Bash calls. Same data. Zero JSON-RPC.
|
|
46
|
+
|
|
47
|
+
### GUI version sync
|
|
48
|
+
|
|
49
|
+
`forge-web` PWA + `forge-studio` Tauri both pull their version label
|
|
50
|
+
from `forge-ui-core`'s `ForgeShell.tsx` default. That default was
|
|
51
|
+
still pinned to `0.3.2`. Now `0.3.5` so both shells correctly identify
|
|
52
|
+
themselves at the bottom of the sidebar.
|
|
53
|
+
|
|
54
|
+
### Tests
|
|
55
|
+
|
|
56
|
+
902 passing, 2 skipped (no test changes — every new verb is a thin
|
|
57
|
+
wrapper around an already-tested a1 function).
|
|
58
|
+
`forge wire src/atomadic_forge` PASS, `forge certify .` holds at
|
|
59
|
+
**100/100**.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
## 0.3.4 — `forge whoami` for agents and humans
|
|
64
|
+
|
|
65
|
+
Adds the agent-empowerment QOL win that 0.3.3 was missing: when the
|
|
66
|
+
MCP gate refuses with `subscription required`, agents (and humans)
|
|
67
|
+
need a cheap way to ask **"who is the gate seeing me as, and from
|
|
68
|
+
which source?"** without burning a real tool call. `forge whoami` is
|
|
69
|
+
that command.
|
|
70
|
+
|
|
71
|
+
### Added
|
|
72
|
+
|
|
73
|
+
- **`forge whoami`** new top-level CLI verb (and `--json` for scripted
|
|
74
|
+
consumers). Returns:
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"ok": true,
|
|
78
|
+
"source": "credentials_file" | "env" | "missing",
|
|
79
|
+
"key_prefix": "fk_live_b3502…",
|
|
80
|
+
"email": "tom@example.com",
|
|
81
|
+
"plan": "pro",
|
|
82
|
+
"verify_ok": true,
|
|
83
|
+
"verify_reason": "",
|
|
84
|
+
"credentials_path": "~/.atomadic-forge/credentials.toml",
|
|
85
|
+
"env_var": "FORGE_API_KEY"
|
|
86
|
+
}
|
|
87
|
+
```
|
|
88
|
+
Resolution order matches the MCP gate exactly (env → credentials.toml).
|
|
89
|
+
`--no-verify` skips the network roundtrip for offline triage.
|
|
90
|
+
- **6 new unit tests** for whoami covering missing-key, env-key,
|
|
91
|
+
credentials-file-key, env-wins-over-file, --no-verify, and
|
|
92
|
+
verify-rejection.
|
|
93
|
+
|
|
94
|
+
### Why this matters for agents
|
|
95
|
+
|
|
96
|
+
Before 0.3.4, an agent that hit `MCP error -32001: Forge subscription
|
|
97
|
+
required` had two options: ask the human to restart the MCP, or fail.
|
|
98
|
+
With 0.3.4 the agent can call `forge whoami --json` (via Bash) and
|
|
99
|
+
get a structured answer it can act on:
|
|
100
|
+
|
|
101
|
+
* `source == "missing"` → tell the user to run `forge login`
|
|
102
|
+
* `source == "credentials_file"` + `verify_ok == false` → key is
|
|
103
|
+
revoked or stale; `forge login` again
|
|
104
|
+
* `source == "env"` + `verify_ok == false` → CI env var is wrong
|
|
105
|
+
* everything green → restart the MCP host (the running subprocess
|
|
106
|
+
needs a respawn to see the new env)
|
|
107
|
+
|
|
108
|
+
This closes the loop for the auth experience — the agent can diagnose
|
|
109
|
+
its own failure mode.
|
|
110
|
+
|
|
111
|
+
### Tests
|
|
112
|
+
|
|
113
|
+
902 passing, 2 skipped. `forge wire src/atomadic_forge` PASS,
|
|
114
|
+
`forge certify .` holds at **100/100**.
|
|
115
|
+
|
|
116
|
+
---
|
|
117
|
+
|
|
3
118
|
## 0.3.3 — MCP gate reads credentials.toml + actionable error message
|
|
4
119
|
|
|
5
120
|
Hot-fix release. Closes the gap where `forge login` writes a key to
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atomadic-forge
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Summary: Atomadic Forge — absorb, enforce, emerge. Polyglot (Python + JavaScript/TypeScript) 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.3.
|
|
7
|
+
version = "0.3.5"
|
|
8
8
|
description = "Atomadic Forge — absorb, enforce, emerge. Polyglot (Python + JavaScript/TypeScript) architecture guardian for AI-generated code."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.10"
|
|
@@ -64,7 +64,9 @@ from ..a3_og_features.forge_pipeline import (
|
|
|
64
64
|
)
|
|
65
65
|
from ..a3_og_features.forge_plan_apply import apply_all_applyable, apply_card
|
|
66
66
|
from ..a3_og_features.mcp_server import serve_stdio as mcp_serve_stdio
|
|
67
|
+
from .copilots_cmd import COPILOTS_VERBS as _COPILOTS_VERBS
|
|
67
68
|
from .login_cmd import app as _login_app
|
|
69
|
+
from .whoami_cmd import app as _whoami_app
|
|
68
70
|
|
|
69
71
|
# Suppress SyntaxWarnings from third-party code in seed/forged directories.
|
|
70
72
|
warnings.filterwarnings("ignore", category=SyntaxWarning)
|
|
@@ -1153,6 +1155,18 @@ app.add_typer(mcp_app, name="mcp",
|
|
|
1153
1155
|
app.add_typer(_login_app, name="login",
|
|
1154
1156
|
help="Capture a Forge subscription key (required by `forge mcp serve`).")
|
|
1155
1157
|
|
|
1158
|
+
# Lane C W6 — `forge whoami` resolves the current auth state without
|
|
1159
|
+
# burning a real tool call. Pairs with `forge login` so agents can
|
|
1160
|
+
# verify what the gate is reading and where it came from.
|
|
1161
|
+
app.add_typer(_whoami_app, name="whoami",
|
|
1162
|
+
help="Show the current Forge auth state — email, plan, source.")
|
|
1163
|
+
|
|
1164
|
+
# Lane C W7 — Codex 'Copilot's Copilot' surface as CLI verbs.
|
|
1165
|
+
# Until 0.3.5 these were MCP-only (tools/call); now they're shell-runnable
|
|
1166
|
+
# so any agent that can spawn Bash can sample the same intelligence.
|
|
1167
|
+
for _verb_name, _verb_app, _verb_help in _COPILOTS_VERBS:
|
|
1168
|
+
app.add_typer(_verb_app, name=_verb_name, help=_verb_help)
|
|
1169
|
+
|
|
1156
1170
|
|
|
1157
1171
|
def _check_optional_dep(module: str) -> str:
|
|
1158
1172
|
try:
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
"""Tier a4 — `forge` CLI parity for the Codex 'Copilot's Copilot' surface.
|
|
2
|
+
|
|
3
|
+
These verbs were already exposed via MCP (tools/call) but had no CLI
|
|
4
|
+
front-door. That gap meant a developer or agent shell-running `forge`
|
|
5
|
+
couldn't sample the same intelligence the MCP exposes — they had to
|
|
6
|
+
spawn the MCP server, speak JSON-RPC, and parse `content[0].text`.
|
|
7
|
+
|
|
8
|
+
This module surfaces every MCP-only tool as a top-level CLI verb that
|
|
9
|
+
prints JSON to stdout, suitable for piping into jq, scripts, or an
|
|
10
|
+
agent's Bash subprocess. Each verb is a thin a4 orchestrator around
|
|
11
|
+
the a1 implementation — no business logic lives here.
|
|
12
|
+
|
|
13
|
+
Verbs added:
|
|
14
|
+
* forge explain-repo <project_root> — Codex #6 humane orientation
|
|
15
|
+
* forge score-patch — Codex #3 patch risk scorer (diff on stdin or --file)
|
|
16
|
+
* forge select-tests <project_root> — Codex #7 minimum + full-confidence test sets
|
|
17
|
+
* forge rollback-plan <project_root> — Codex #11 structured undo plan
|
|
18
|
+
* forge compose-tools <goal> — Codex #9 tool-use planner (goal keyword)
|
|
19
|
+
* forge why-did-this-change <file> — Codex #5 lineage history for a file
|
|
20
|
+
* forge what-failed-last-time <area> — Codex #5 failures matching an area substring
|
|
21
|
+
* forge adapt-plan — Codex #8 capability-aware card filtering (plan on stdin/--file)
|
|
22
|
+
* forge load-policy <project_root> — Codex #10 [tool.forge.agent] reader
|
|
23
|
+
|
|
24
|
+
All verbs default to printing JSON. None mutate the repo.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
from __future__ import annotations
|
|
28
|
+
|
|
29
|
+
import json
|
|
30
|
+
import sys
|
|
31
|
+
from dataclasses import asdict, is_dataclass
|
|
32
|
+
from pathlib import Path
|
|
33
|
+
from typing import Annotated
|
|
34
|
+
|
|
35
|
+
import typer
|
|
36
|
+
|
|
37
|
+
from ..a1_at_functions.agent_memory import (
|
|
38
|
+
what_failed_last_time as _what_failed_last_time,
|
|
39
|
+
)
|
|
40
|
+
from ..a1_at_functions.agent_memory import why_did_this_change as _why_did_this_change
|
|
41
|
+
from ..a1_at_functions.patch_scorer import score_patch as _score_patch
|
|
42
|
+
from ..a1_at_functions.plan_adapter import adapt_plan as _adapt_plan
|
|
43
|
+
from ..a1_at_functions.policy_loader import load_policy as _load_policy
|
|
44
|
+
from ..a1_at_functions.repo_explainer import explain_repo as _explain_repo
|
|
45
|
+
from ..a1_at_functions.rollback_planner import rollback_plan as _rollback_plan
|
|
46
|
+
from ..a1_at_functions.test_selector import select_tests as _select_tests
|
|
47
|
+
from ..a1_at_functions.tool_composer import compose_tools as _compose_tools
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _to_jsonable(obj: object) -> object:
|
|
51
|
+
"""Convert dataclasses, Paths, sets to JSON-serializable form."""
|
|
52
|
+
if is_dataclass(obj):
|
|
53
|
+
return asdict(obj) # type: ignore[arg-type]
|
|
54
|
+
if isinstance(obj, Path):
|
|
55
|
+
return str(obj)
|
|
56
|
+
if isinstance(obj, set):
|
|
57
|
+
return sorted(obj)
|
|
58
|
+
if isinstance(obj, (list, tuple)):
|
|
59
|
+
return [_to_jsonable(v) for v in obj]
|
|
60
|
+
if isinstance(obj, dict):
|
|
61
|
+
return {k: _to_jsonable(v) for k, v in obj.items()}
|
|
62
|
+
return obj
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def _emit(result: object) -> None:
|
|
66
|
+
"""Print JSON to stdout. Used by every verb in this module."""
|
|
67
|
+
typer.echo(json.dumps(_to_jsonable(result), indent=2, default=str))
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def _read_stdin_or_file(file: Path | None) -> str:
|
|
71
|
+
if file is not None:
|
|
72
|
+
return Path(file).read_text(encoding="utf-8")
|
|
73
|
+
if sys.stdin.isatty():
|
|
74
|
+
raise typer.BadParameter(
|
|
75
|
+
"no input on stdin and --file not given. Pipe a diff via stdin or pass --file path.txt"
|
|
76
|
+
)
|
|
77
|
+
return sys.stdin.read()
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
# ---- Top-level Typer apps (one per verb) -------------------------------
|
|
81
|
+
|
|
82
|
+
explain_app = typer.Typer(no_args_is_help=False, help="Codex #6 — humane operational orientation.")
|
|
83
|
+
score_app = typer.Typer(no_args_is_help=False, help="Codex #3 — patch risk scorer.")
|
|
84
|
+
tests_app = typer.Typer(no_args_is_help=False, help="Codex #7 — minimum + full-confidence test sets.")
|
|
85
|
+
rollback_app = typer.Typer(no_args_is_help=False, help="Codex #11 — structured undo plan.")
|
|
86
|
+
compose_app = typer.Typer(no_args_is_help=False, help="Codex #9 — tool-use planner.")
|
|
87
|
+
why_app = typer.Typer(no_args_is_help=False, help="Codex #5 — agent memory: lineage for a file.")
|
|
88
|
+
failed_app = typer.Typer(no_args_is_help=False, help="Codex #5 — failed events matching an area.")
|
|
89
|
+
adapt_app = typer.Typer(no_args_is_help=False, help="Codex #8 — capability-aware card filtering.")
|
|
90
|
+
policy_app = typer.Typer(no_args_is_help=False, help="Codex #10 — read [tool.forge.agent] policy.")
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
@explain_app.callback(invoke_without_command=True)
|
|
94
|
+
def explain_repo_cmd(
|
|
95
|
+
project_root: Annotated[
|
|
96
|
+
Path,
|
|
97
|
+
typer.Argument(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
|
|
98
|
+
] = Path("."),
|
|
99
|
+
depth: Annotated[str, typer.Option("--depth")] = "agent",
|
|
100
|
+
) -> None:
|
|
101
|
+
_emit(_explain_repo(project_root=project_root, depth=depth))
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
@score_app.callback(invoke_without_command=True)
|
|
105
|
+
def score_patch_cmd(
|
|
106
|
+
file: Annotated[
|
|
107
|
+
Path | None,
|
|
108
|
+
typer.Option(
|
|
109
|
+
"--file", "-f",
|
|
110
|
+
help="Read the unified diff from this file. Without --file, reads from stdin.",
|
|
111
|
+
),
|
|
112
|
+
] = None,
|
|
113
|
+
project_root: Annotated[
|
|
114
|
+
Path,
|
|
115
|
+
typer.Option("--project-root", "-p", exists=True, file_okay=False, resolve_path=True),
|
|
116
|
+
] = Path("."),
|
|
117
|
+
) -> None:
|
|
118
|
+
diff = _read_stdin_or_file(file)
|
|
119
|
+
_emit(_score_patch(diff, project_root=project_root))
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
@tests_app.callback(invoke_without_command=True)
|
|
123
|
+
def select_tests_cmd(
|
|
124
|
+
intent: Annotated[str, typer.Argument(help="One-line description of the intent.")] ,
|
|
125
|
+
files: Annotated[
|
|
126
|
+
list[str],
|
|
127
|
+
typer.Option(
|
|
128
|
+
"--file", "-f",
|
|
129
|
+
help="Repeat for each changed file. Example: --file src/a/b.py --file src/a/c.py",
|
|
130
|
+
),
|
|
131
|
+
] = [],
|
|
132
|
+
project_root: Annotated[
|
|
133
|
+
Path,
|
|
134
|
+
typer.Option("--project-root", "-p", exists=True, file_okay=False, resolve_path=True),
|
|
135
|
+
] = Path("."),
|
|
136
|
+
) -> None:
|
|
137
|
+
_emit(_select_tests(
|
|
138
|
+
intent=intent,
|
|
139
|
+
changed_files=list(files),
|
|
140
|
+
project_root=project_root,
|
|
141
|
+
))
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
@rollback_app.callback(invoke_without_command=True)
|
|
145
|
+
def rollback_plan_cmd(
|
|
146
|
+
files: Annotated[
|
|
147
|
+
list[str],
|
|
148
|
+
typer.Option(
|
|
149
|
+
"--file", "-f",
|
|
150
|
+
help="Repeat for each changed file you want a rollback plan for.",
|
|
151
|
+
),
|
|
152
|
+
] = [],
|
|
153
|
+
project_root: Annotated[
|
|
154
|
+
Path,
|
|
155
|
+
typer.Option("--project-root", "-p", exists=True, file_okay=False, resolve_path=True),
|
|
156
|
+
] = Path("."),
|
|
157
|
+
) -> None:
|
|
158
|
+
_emit(_rollback_plan(changed_files=list(files), project_root=project_root))
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
@compose_app.callback(invoke_without_command=True)
|
|
162
|
+
def compose_tools_cmd(
|
|
163
|
+
goal: Annotated[str, typer.Argument(help="One-line goal keyword (orient / release_check / ...).")] ,
|
|
164
|
+
) -> None:
|
|
165
|
+
_emit(_compose_tools(goal=goal))
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
@why_app.callback(invoke_without_command=True)
|
|
169
|
+
def why_cmd(
|
|
170
|
+
file: Annotated[str, typer.Argument(help="File path to look up (relative or absolute).")] ,
|
|
171
|
+
project_root: Annotated[
|
|
172
|
+
Path,
|
|
173
|
+
typer.Option("--project-root", "-p", exists=True, file_okay=False, resolve_path=True),
|
|
174
|
+
] = Path("."),
|
|
175
|
+
) -> None:
|
|
176
|
+
_emit(_why_did_this_change(file=file, project_root=project_root))
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
@failed_app.callback(invoke_without_command=True)
|
|
180
|
+
def failed_cmd(
|
|
181
|
+
area: Annotated[str, typer.Argument(help="Substring match against the area string.")] ,
|
|
182
|
+
project_root: Annotated[
|
|
183
|
+
Path,
|
|
184
|
+
typer.Option("--project-root", "-p", exists=True, file_okay=False, resolve_path=True),
|
|
185
|
+
] = Path("."),
|
|
186
|
+
) -> None:
|
|
187
|
+
_emit(_what_failed_last_time(area=area, project_root=project_root))
|
|
188
|
+
|
|
189
|
+
|
|
190
|
+
@adapt_app.callback(invoke_without_command=True)
|
|
191
|
+
def adapt_plan_cmd(
|
|
192
|
+
capabilities: Annotated[
|
|
193
|
+
list[str],
|
|
194
|
+
typer.Option(
|
|
195
|
+
"--cap", "-c",
|
|
196
|
+
help="Repeat for each capability the agent advertises (e.g. -c apply -c shell).",
|
|
197
|
+
),
|
|
198
|
+
] = [],
|
|
199
|
+
file: Annotated[
|
|
200
|
+
Path | None,
|
|
201
|
+
typer.Option(
|
|
202
|
+
"--file", "-f",
|
|
203
|
+
help="Read the agent_plan/v1 JSON from this file. Without --file, reads from stdin.",
|
|
204
|
+
),
|
|
205
|
+
] = None,
|
|
206
|
+
) -> None:
|
|
207
|
+
plan_text = _read_stdin_or_file(file)
|
|
208
|
+
plan = json.loads(plan_text)
|
|
209
|
+
_emit(_adapt_plan(plan, agent_capabilities=list(capabilities)))
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@policy_app.callback(invoke_without_command=True)
|
|
213
|
+
def policy_cmd(
|
|
214
|
+
project_root: Annotated[
|
|
215
|
+
Path,
|
|
216
|
+
typer.Argument(exists=True, file_okay=False, dir_okay=True, resolve_path=True),
|
|
217
|
+
] = Path("."),
|
|
218
|
+
) -> None:
|
|
219
|
+
policy = _load_policy(project_root)
|
|
220
|
+
_emit(policy)
|
|
221
|
+
|
|
222
|
+
|
|
223
|
+
# Public registry — cli.py imports this and registers each.
|
|
224
|
+
COPILOTS_VERBS: list[tuple[str, "typer.Typer", str]] = [
|
|
225
|
+
("explain-repo", explain_app, "Codex #6 — humane operational orientation of any repo."),
|
|
226
|
+
("score-patch", score_app, "Codex #3 — patch risk scorer (diff via stdin or --file)."),
|
|
227
|
+
("select-tests", tests_app, "Codex #7 — minimum + full-confidence test sets per intent."),
|
|
228
|
+
("rollback-plan", rollback_app, "Codex #11 — structured undo plan for a set of changed files."),
|
|
229
|
+
("compose-tools", compose_app, "Codex #9 — tool-use planner: keyword → ordered MCP tool sequence."),
|
|
230
|
+
("why-did-this-change", why_app, "Codex #5 — lineage + plan events that touched a file."),
|
|
231
|
+
("what-failed-last-time", failed_app, "Codex #5 — failed/rolled-back plan events matching an area."),
|
|
232
|
+
("adapt-plan", adapt_app, "Codex #8 — capability-aware card filtering (plan via stdin or --file)."),
|
|
233
|
+
("load-policy", policy_app, "Codex #10 — read [tool.forge.agent] policy from pyproject.toml."),
|
|
234
|
+
]
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
"""Tier a4 — `forge whoami` orchestration command.
|
|
2
|
+
|
|
3
|
+
Resolves the current Forge authentication state and prints (or returns
|
|
4
|
+
as JSON) the email, plan, source (env vs credentials.toml), and verify
|
|
5
|
+
result. Pairs with `forge login`: after a successful login, `whoami`
|
|
6
|
+
confirms the credential file is being read and the verify endpoint
|
|
7
|
+
agrees with what's there.
|
|
8
|
+
|
|
9
|
+
Why a dedicated verb (and MCP tool):
|
|
10
|
+
* Agents need to ASK "am I authenticated and what's my plan?" without
|
|
11
|
+
burning a real tool call. Today an agent that hits "subscription
|
|
12
|
+
required" has no cheap follow-up — `whoami` is that follow-up.
|
|
13
|
+
* Humans running into MCP gate failures need a one-liner that says
|
|
14
|
+
exactly which key the gate read and where it came from.
|
|
15
|
+
* `--json` makes it scriptable in CI / shell wrappers.
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from __future__ import annotations
|
|
19
|
+
|
|
20
|
+
import json as _json
|
|
21
|
+
import os
|
|
22
|
+
from pathlib import Path
|
|
23
|
+
from typing import Annotated
|
|
24
|
+
|
|
25
|
+
import typer
|
|
26
|
+
|
|
27
|
+
from ..a0_qk_constants.auth_constants import API_KEY_ENV
|
|
28
|
+
from ..a1_at_functions.forge_auth import (
|
|
29
|
+
read_api_key_from_credentials_file,
|
|
30
|
+
read_api_key_from_env,
|
|
31
|
+
)
|
|
32
|
+
from ..a2_mo_composites.forge_auth_client import ForgeAuthClient
|
|
33
|
+
|
|
34
|
+
CREDENTIALS_FILE = Path("~/.atomadic-forge/credentials.toml").expanduser()
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def _resolve_key(env: dict[str, str], creds_path: Path) -> tuple[str | None, str]:
|
|
38
|
+
"""Return (api_key, source) using the same resolution order the MCP gate uses.
|
|
39
|
+
|
|
40
|
+
source ∈ {"env", "credentials_file", "missing"}.
|
|
41
|
+
"""
|
|
42
|
+
env_key = read_api_key_from_env(env)
|
|
43
|
+
if env_key:
|
|
44
|
+
return env_key, "env"
|
|
45
|
+
file_key = read_api_key_from_credentials_file(creds_path)
|
|
46
|
+
if file_key:
|
|
47
|
+
return file_key, "credentials_file"
|
|
48
|
+
return None, "missing"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
app = typer.Typer(
|
|
52
|
+
no_args_is_help=False,
|
|
53
|
+
help="Show the current Forge authentication state — email, plan, source.",
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@app.callback(invoke_without_command=True)
|
|
58
|
+
def whoami_cmd(
|
|
59
|
+
json_out: Annotated[
|
|
60
|
+
bool,
|
|
61
|
+
typer.Option(
|
|
62
|
+
"--json",
|
|
63
|
+
help="Emit the result as JSON for scripted consumers.",
|
|
64
|
+
),
|
|
65
|
+
] = False,
|
|
66
|
+
no_verify: Annotated[
|
|
67
|
+
bool,
|
|
68
|
+
typer.Option(
|
|
69
|
+
"--no-verify",
|
|
70
|
+
help="Skip the network verify roundtrip; just report the key shape "
|
|
71
|
+
"and source (useful when the verify endpoint is offline).",
|
|
72
|
+
),
|
|
73
|
+
] = False,
|
|
74
|
+
) -> None:
|
|
75
|
+
"""Resolve and print the current Forge auth state."""
|
|
76
|
+
env_dict = dict(os.environ)
|
|
77
|
+
api_key, source = _resolve_key(env_dict, CREDENTIALS_FILE)
|
|
78
|
+
|
|
79
|
+
if api_key is None:
|
|
80
|
+
result: dict = {
|
|
81
|
+
"ok": False,
|
|
82
|
+
"source": "missing",
|
|
83
|
+
"email": "",
|
|
84
|
+
"plan": "",
|
|
85
|
+
"reason": (
|
|
86
|
+
"No Forge subscription key configured. Run "
|
|
87
|
+
"`forge login` to capture one, or export "
|
|
88
|
+
f"{API_KEY_ENV}=fk_live_… in the environment."
|
|
89
|
+
),
|
|
90
|
+
"credentials_path": str(CREDENTIALS_FILE),
|
|
91
|
+
}
|
|
92
|
+
if json_out:
|
|
93
|
+
typer.echo(_json.dumps(result, indent=2))
|
|
94
|
+
else:
|
|
95
|
+
typer.echo("")
|
|
96
|
+
typer.secho(" ✗ Not logged in.", fg="red")
|
|
97
|
+
typer.echo("")
|
|
98
|
+
typer.echo(" Run `forge login` to capture a key, or export")
|
|
99
|
+
typer.echo(f" {API_KEY_ENV}=fk_live_…")
|
|
100
|
+
typer.echo(f" Credentials path: {CREDENTIALS_FILE}")
|
|
101
|
+
raise typer.Exit(code=1)
|
|
102
|
+
|
|
103
|
+
# We have a key. Mask it for display (show first 11 chars of fk_live_xxx).
|
|
104
|
+
masked = api_key[:11] + ("…" if len(api_key) > 11 else "")
|
|
105
|
+
|
|
106
|
+
email = ""
|
|
107
|
+
plan = ""
|
|
108
|
+
verify_ok = False
|
|
109
|
+
verify_reason = "(verification skipped via --no-verify)"
|
|
110
|
+
|
|
111
|
+
if not no_verify:
|
|
112
|
+
client = ForgeAuthClient()
|
|
113
|
+
try:
|
|
114
|
+
verify = client.verify(api_key)
|
|
115
|
+
verify_ok = bool(verify.get("ok"))
|
|
116
|
+
email = str(verify.get("email", "") or "")
|
|
117
|
+
plan = str(verify.get("plan", "") or "")
|
|
118
|
+
verify_reason = str(verify.get("reason", "") or "")
|
|
119
|
+
except Exception as exc: # noqa: BLE001 — show offline status to the user
|
|
120
|
+
verify_reason = f"verify endpoint unreachable: {exc!r}"
|
|
121
|
+
|
|
122
|
+
result = {
|
|
123
|
+
"ok": verify_ok or no_verify,
|
|
124
|
+
"source": source,
|
|
125
|
+
"key_prefix": masked,
|
|
126
|
+
"email": email,
|
|
127
|
+
"plan": plan,
|
|
128
|
+
"verify_ok": verify_ok,
|
|
129
|
+
"verify_reason": verify_reason,
|
|
130
|
+
"credentials_path": str(CREDENTIALS_FILE),
|
|
131
|
+
"env_var": API_KEY_ENV,
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if json_out:
|
|
135
|
+
typer.echo(_json.dumps(result, indent=2))
|
|
136
|
+
if not result["ok"]:
|
|
137
|
+
raise typer.Exit(code=1)
|
|
138
|
+
return
|
|
139
|
+
|
|
140
|
+
typer.echo("")
|
|
141
|
+
if result["ok"]:
|
|
142
|
+
typer.secho(
|
|
143
|
+
f" ✓ Logged in as {email or '(unknown email)'}"
|
|
144
|
+
f"{f' · plan: {plan}' if plan else ''}",
|
|
145
|
+
fg="green",
|
|
146
|
+
)
|
|
147
|
+
else:
|
|
148
|
+
typer.secho(f" ✗ Auth failed: {verify_reason}", fg="red")
|
|
149
|
+
|
|
150
|
+
typer.echo(f" key: {masked}")
|
|
151
|
+
typer.echo(f" source: {source}")
|
|
152
|
+
if source == "credentials_file":
|
|
153
|
+
typer.echo(f" file: {CREDENTIALS_FILE}")
|
|
154
|
+
elif source == "env":
|
|
155
|
+
typer.echo(f" env: {API_KEY_ENV}")
|
|
156
|
+
typer.echo("")
|
|
157
|
+
|
|
158
|
+
if not result["ok"]:
|
|
159
|
+
raise typer.Exit(code=1)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: atomadic-forge
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.5
|
|
4
4
|
Summary: Atomadic Forge — absorb, enforce, emerge. Polyglot (Python + JavaScript/TypeScript) architecture guardian for AI-generated code.
|
|
5
5
|
Author: Atomadic
|
|
6
6
|
License-Expression: BUSL-1.1
|
|
@@ -185,7 +185,9 @@ src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/tests/conftest.py
|
|
|
185
185
|
src/atomadic_forge/a3_og_features/demo_packages/mixed_py_js/tests/test_mixed.py
|
|
186
186
|
src/atomadic_forge/a4_sy_orchestration/__init__.py
|
|
187
187
|
src/atomadic_forge/a4_sy_orchestration/cli.py
|
|
188
|
+
src/atomadic_forge/a4_sy_orchestration/copilots_cmd.py
|
|
188
189
|
src/atomadic_forge/a4_sy_orchestration/login_cmd.py
|
|
190
|
+
src/atomadic_forge/a4_sy_orchestration/whoami_cmd.py
|
|
189
191
|
src/atomadic_forge/commands/__init__.py
|
|
190
192
|
src/atomadic_forge/commands/_registry.py
|
|
191
193
|
src/atomadic_forge/commands/audit.py
|
|
@@ -263,5 +265,6 @@ tests/test_synergy.py
|
|
|
263
265
|
tests/test_test_runner.py
|
|
264
266
|
tests/test_tier_init_rebuild.py
|
|
265
267
|
tests/test_vscode_extension_manifest.py
|
|
268
|
+
tests/test_whoami_cmd.py
|
|
266
269
|
tests/test_wire_certify.py
|
|
267
270
|
tests/test_wire_suggest_repairs.py
|