atomadic-forge 0.3.3__tar.gz → 0.3.4__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.4}/CHANGELOG.md +55 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/PKG-INFO +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/pyproject.toml +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/__init__.py +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a4_sy_orchestration/cli.py +7 -0
- atomadic_forge-0.3.4/src/atomadic_forge/a4_sy_orchestration/whoami_cmd.py +159 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge.egg-info/PKG-INFO +1 -1
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge.egg-info/SOURCES.txt +2 -0
- atomadic_forge-0.3.4/tests/test_whoami_cmd.py +126 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/ISSUE_TEMPLATE/bug_report.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/ISSUE_TEMPLATE/config.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/ISSUE_TEMPLATE/feature_request.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/actions/forge-action/README.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/actions/forge-action/action.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/dependabot.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/pull_request_template.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/workflows/ci.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/workflows/forge-self-certify.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/workflows/forge-studio-ci.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/.github/workflows/release.yml +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/ARCHITECTURE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/CONTRIBUTING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/LICENSE +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/MANIFEST.in +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/README.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/SECURITY.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/assets/Atomadic-Forge-01.png +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/01-getting-started.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/02-commands.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/03-tutorial.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/04-llm-loops.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/05-faq.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/AGENTS_GUIDE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/AIR_GAPPED.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/CI_CD.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/CODEX_WALKTHROUGH.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/COMMANDS.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/FIRST_10_MINUTES.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/FORMALIZATION.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/LANDSCAPE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/MARKET_POSITIONING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/MULTI_REPO.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/README.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/RECEIPT.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/RELEASE_CHECKLIST.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/RELEASE_MESSAGING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/ROADMAP.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/SHOWCASE.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/SIDECAR.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/STUDIO.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/WHY_NOW.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/INDEX.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/chat.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/commandsmith.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/config.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/demo.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/emergent-then-synergy.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/emergent.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/evolve-then-iterate.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/evolve.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/feature-then-emergent.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/iterate.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/synergy-then-emergent.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/commands/synergy.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/compliance/CMMC_AI_MAPPING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/compliance/CS-1.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/compliance/EU_AI_ACT_ANNEX_IV.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/compliance/FDA_PCCP_MAPPING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/compliance/SR_11-7_MAPPING.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/tutorials/01-quickstart.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/tutorials/02-your-first-package.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/tutorials/03-the-five-tier-law.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/tutorials/04-plug-in-llms.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/tutorials/05-multi-repo-absorb.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/docs/tutorials/06-javascript-quickstart.md +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/setup.cfg +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/__main__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/agent_plan_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/auth_constants.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/commandsmith_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/config_defaults.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/emergent_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/error_codes.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/forge_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/gen_language.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/lang_extensions.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/policy_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/receipt_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/roi_constants.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/semantic_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/sidecar_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/synergy_types.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/tier_names.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/agent_context_pack.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/agent_memory.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/agent_plan_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/agent_summary.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/body_extractor.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/card_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/certify_checks.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/chat_context.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/cherry_pick.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/classify_tier.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/commandsmith_discover.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/commandsmith_render.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/compiler_feedback.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/compliance_checker.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/config_io.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/cs1_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/doc_synthesizer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/emergent_compose.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/emergent_rank.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/emergent_signature_extract.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/emergent_synthesize.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/enforce_planner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/error_hints.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/evolution_log.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/forge_auth.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/forge_feedback.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/generation_quality.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/import_repair.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/import_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/js_parser.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/lineage_chain.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/lineage_reader.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/llm_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/local_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/lsp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/manifest_diff.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/mcp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/patch_scorer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/plan_adapter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/policy_loader.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/preflight_change.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/progress_reporter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/provider_detect.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/provider_resolver.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/receipt_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/recipes.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/repo_explainer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/roi_calculator.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/rollback_planner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/sbom_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/scaffold_js.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/scaffold_pyproject.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/scaffold_starter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/scout_walk.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/sidecar_parser.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/sidecar_validator.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/stub_detector.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/synergy_detect.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/synergy_render.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/synergy_surface_extract.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/test_runner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/test_selector.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/tier_init_rebuild.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/tool_composer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/transcript_log.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/wire_check.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a2_mo_composites/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a2_mo_composites/forge_auth_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a2_mo_composites/lineage_chain_store.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a2_mo_composites/manifest_store.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a2_mo_composites/plan_store.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a2_mo_composites/receipt_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/commandsmith_feature.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/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.4}/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.4}/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.4}/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.4}/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.4}/src/atomadic_forge/a3_og_features/demo_runner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/emergent_feature.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/emergent_pipeline_integration.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/forge_enforce.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/forge_evolve.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/forge_loop.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/forge_pipeline.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/forge_plan_apply.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/lsp_server.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/mcp_server.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/setup_wizard.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a3_og_features/synergy_feature.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a4_sy_orchestration/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a4_sy_orchestration/login_cmd.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/__init__.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/_registry.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/audit.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/chat.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/commandsmith.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/config_cmd.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/demo.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/emergent.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/emergent_then_synergy.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/evolve.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/evolve_then_iterate.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/feature_then_emergent.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/iterate.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/synergy.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/commands/synergy_then_emergent.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge.egg-info/dependency_links.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge.egg-info/entry_points.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge.egg-info/requires.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge.egg-info/top_level.txt +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_aaaa_nexus_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_agent_plan.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_agent_summary.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_audit_verb.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_badge_worker.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_body_extractor_repairs.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_card_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_certify_operational_axis.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_chat.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_classify_tier.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_cli_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_codex_5_complete.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_codex_6_enforce_polyglot.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_commandsmith.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_compiler_feedback.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_compliance_checker.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_config.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_copilots_copilot.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_cs1_renderer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_demo.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_emergent_compose.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_emergent_signature_extract.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_error_codes.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_error_hints.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_evolve_js.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_forge_action.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_forge_auth_a1.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_forge_auth_a2.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_forge_enforce.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_generation_quality.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_ignore_and_docs.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_import_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_iterate_evolve.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_js_certify.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_js_parser.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_js_recon.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_js_wire.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_lineage_chain.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_local_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_lsp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_manifest_diff.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_mcp_protocol.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_ollama_client.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_pipeline.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_plan_apply.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_pre_audit_smoke.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_precommit_hooks.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_progress_reporter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_receipt_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_receipt_schema.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_receipt_signer.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_roi_calculator.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_sbom_emitter.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_scaffold.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_sidecar.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_sidecar_validate.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_stagnation.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_stub_detector.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_synergy.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_test_runner.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_tier_init_rebuild.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_vscode_extension_manifest.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_wire_certify.py +0 -0
- {atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/tests/test_wire_suggest_repairs.py +0 -0
|
@@ -1,5 +1,60 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.3.4 — `forge whoami` for agents and humans
|
|
4
|
+
|
|
5
|
+
Adds the agent-empowerment QOL win that 0.3.3 was missing: when the
|
|
6
|
+
MCP gate refuses with `subscription required`, agents (and humans)
|
|
7
|
+
need a cheap way to ask **"who is the gate seeing me as, and from
|
|
8
|
+
which source?"** without burning a real tool call. `forge whoami` is
|
|
9
|
+
that command.
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **`forge whoami`** new top-level CLI verb (and `--json` for scripted
|
|
14
|
+
consumers). Returns:
|
|
15
|
+
```json
|
|
16
|
+
{
|
|
17
|
+
"ok": true,
|
|
18
|
+
"source": "credentials_file" | "env" | "missing",
|
|
19
|
+
"key_prefix": "fk_live_b3502…",
|
|
20
|
+
"email": "tom@example.com",
|
|
21
|
+
"plan": "pro",
|
|
22
|
+
"verify_ok": true,
|
|
23
|
+
"verify_reason": "",
|
|
24
|
+
"credentials_path": "~/.atomadic-forge/credentials.toml",
|
|
25
|
+
"env_var": "FORGE_API_KEY"
|
|
26
|
+
}
|
|
27
|
+
```
|
|
28
|
+
Resolution order matches the MCP gate exactly (env → credentials.toml).
|
|
29
|
+
`--no-verify` skips the network roundtrip for offline triage.
|
|
30
|
+
- **6 new unit tests** for whoami covering missing-key, env-key,
|
|
31
|
+
credentials-file-key, env-wins-over-file, --no-verify, and
|
|
32
|
+
verify-rejection.
|
|
33
|
+
|
|
34
|
+
### Why this matters for agents
|
|
35
|
+
|
|
36
|
+
Before 0.3.4, an agent that hit `MCP error -32001: Forge subscription
|
|
37
|
+
required` had two options: ask the human to restart the MCP, or fail.
|
|
38
|
+
With 0.3.4 the agent can call `forge whoami --json` (via Bash) and
|
|
39
|
+
get a structured answer it can act on:
|
|
40
|
+
|
|
41
|
+
* `source == "missing"` → tell the user to run `forge login`
|
|
42
|
+
* `source == "credentials_file"` + `verify_ok == false` → key is
|
|
43
|
+
revoked or stale; `forge login` again
|
|
44
|
+
* `source == "env"` + `verify_ok == false` → CI env var is wrong
|
|
45
|
+
* everything green → restart the MCP host (the running subprocess
|
|
46
|
+
needs a respawn to see the new env)
|
|
47
|
+
|
|
48
|
+
This closes the loop for the auth experience — the agent can diagnose
|
|
49
|
+
its own failure mode.
|
|
50
|
+
|
|
51
|
+
### Tests
|
|
52
|
+
|
|
53
|
+
902 passing, 2 skipped. `forge wire src/atomadic_forge` PASS,
|
|
54
|
+
`forge certify .` holds at **100/100**.
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
3
58
|
## 0.3.3 — MCP gate reads credentials.toml + actionable error message
|
|
4
59
|
|
|
5
60
|
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.4
|
|
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.4"
|
|
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"
|
|
@@ -65,6 +65,7 @@ from ..a3_og_features.forge_pipeline import (
|
|
|
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
67
|
from .login_cmd import app as _login_app
|
|
68
|
+
from .whoami_cmd import app as _whoami_app
|
|
68
69
|
|
|
69
70
|
# Suppress SyntaxWarnings from third-party code in seed/forged directories.
|
|
70
71
|
warnings.filterwarnings("ignore", category=SyntaxWarning)
|
|
@@ -1153,6 +1154,12 @@ app.add_typer(mcp_app, name="mcp",
|
|
|
1153
1154
|
app.add_typer(_login_app, name="login",
|
|
1154
1155
|
help="Capture a Forge subscription key (required by `forge mcp serve`).")
|
|
1155
1156
|
|
|
1157
|
+
# Lane C W6 — `forge whoami` resolves the current auth state without
|
|
1158
|
+
# burning a real tool call. Pairs with `forge login` so agents can
|
|
1159
|
+
# verify what the gate is reading and where it came from.
|
|
1160
|
+
app.add_typer(_whoami_app, name="whoami",
|
|
1161
|
+
help="Show the current Forge auth state — email, plan, source.")
|
|
1162
|
+
|
|
1156
1163
|
|
|
1157
1164
|
def _check_optional_dep(module: str) -> str:
|
|
1158
1165
|
try:
|
|
@@ -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.4
|
|
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
|
|
@@ -186,6 +186,7 @@ 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
188
|
src/atomadic_forge/a4_sy_orchestration/login_cmd.py
|
|
189
|
+
src/atomadic_forge/a4_sy_orchestration/whoami_cmd.py
|
|
189
190
|
src/atomadic_forge/commands/__init__.py
|
|
190
191
|
src/atomadic_forge/commands/_registry.py
|
|
191
192
|
src/atomadic_forge/commands/audit.py
|
|
@@ -263,5 +264,6 @@ tests/test_synergy.py
|
|
|
263
264
|
tests/test_test_runner.py
|
|
264
265
|
tests/test_tier_init_rebuild.py
|
|
265
266
|
tests/test_vscode_extension_manifest.py
|
|
267
|
+
tests/test_whoami_cmd.py
|
|
266
268
|
tests/test_wire_certify.py
|
|
267
269
|
tests/test_wire_suggest_repairs.py
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
"""Tests for `forge whoami` (Tier a4).
|
|
2
|
+
|
|
3
|
+
Covers the four states: missing-key, env-key, credentials-file-key,
|
|
4
|
+
and verify-failure. Uses CliRunner so the test mirrors what an agent
|
|
5
|
+
or shell user would see, not just internal state.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import json
|
|
11
|
+
|
|
12
|
+
import pytest
|
|
13
|
+
from typer.testing import CliRunner
|
|
14
|
+
|
|
15
|
+
from atomadic_forge.a4_sy_orchestration import whoami_cmd
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
@pytest.fixture()
|
|
19
|
+
def runner():
|
|
20
|
+
return CliRunner()
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture()
|
|
24
|
+
def fake_creds(tmp_path, monkeypatch):
|
|
25
|
+
"""Point CREDENTIALS_FILE at a tmp path and ensure env is empty."""
|
|
26
|
+
creds = tmp_path / "credentials.toml"
|
|
27
|
+
monkeypatch.setattr(whoami_cmd, "CREDENTIALS_FILE", creds)
|
|
28
|
+
monkeypatch.delenv("FORGE_API_KEY", raising=False)
|
|
29
|
+
return creds
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class _StubClient:
|
|
33
|
+
"""Stand-in for ForgeAuthClient — returns whatever `verify` is patched to."""
|
|
34
|
+
|
|
35
|
+
def __init__(self, result: dict):
|
|
36
|
+
self._result = result
|
|
37
|
+
|
|
38
|
+
def verify(self, _api_key: str) -> dict:
|
|
39
|
+
return self._result
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def test_whoami_missing_key_exits_1(runner, fake_creds):
|
|
43
|
+
out = runner.invoke(whoami_cmd.app, [])
|
|
44
|
+
assert out.exit_code == 1
|
|
45
|
+
assert "Not logged in" in out.output
|
|
46
|
+
assert "forge login" in out.output
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_whoami_missing_key_json(runner, fake_creds):
|
|
50
|
+
out = runner.invoke(whoami_cmd.app, ["--json"])
|
|
51
|
+
assert out.exit_code == 1
|
|
52
|
+
body = json.loads(out.output)
|
|
53
|
+
assert body["ok"] is False
|
|
54
|
+
assert body["source"] == "missing"
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def test_whoami_reads_credentials_file_when_no_env(
|
|
58
|
+
runner, fake_creds, monkeypatch,
|
|
59
|
+
):
|
|
60
|
+
fake_creds.write_text(
|
|
61
|
+
'[forge_auth]\napi_key = "fk_live_abcdef123"\n', encoding="utf-8",
|
|
62
|
+
)
|
|
63
|
+
monkeypatch.setattr(
|
|
64
|
+
whoami_cmd, "ForgeAuthClient",
|
|
65
|
+
lambda: _StubClient({"ok": True, "email": "tom@example.com", "plan": "pro"}),
|
|
66
|
+
)
|
|
67
|
+
out = runner.invoke(whoami_cmd.app, ["--json"])
|
|
68
|
+
assert out.exit_code == 0
|
|
69
|
+
body = json.loads(out.output)
|
|
70
|
+
assert body["ok"] is True
|
|
71
|
+
assert body["source"] == "credentials_file"
|
|
72
|
+
assert body["email"] == "tom@example.com"
|
|
73
|
+
assert body["plan"] == "pro"
|
|
74
|
+
assert body["key_prefix"].startswith("fk_live_")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
def test_whoami_prefers_env_over_credentials_file(
|
|
78
|
+
runner, fake_creds, monkeypatch,
|
|
79
|
+
):
|
|
80
|
+
"""Env wins over credentials file (CI / explicit override behavior)."""
|
|
81
|
+
fake_creds.write_text(
|
|
82
|
+
'[forge_auth]\napi_key = "fk_live_FILEKEY999"\n', encoding="utf-8",
|
|
83
|
+
)
|
|
84
|
+
monkeypatch.setenv("FORGE_API_KEY", "fk_live_ENVKEY777")
|
|
85
|
+
monkeypatch.setattr(
|
|
86
|
+
whoami_cmd, "ForgeAuthClient",
|
|
87
|
+
lambda: _StubClient({"ok": True, "email": "ci@example.com", "plan": "ci"}),
|
|
88
|
+
)
|
|
89
|
+
out = runner.invoke(whoami_cmd.app, ["--json"])
|
|
90
|
+
assert out.exit_code == 0
|
|
91
|
+
body = json.loads(out.output)
|
|
92
|
+
assert body["source"] == "env"
|
|
93
|
+
assert body["key_prefix"].startswith("fk_live_ENV")
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
def test_whoami_no_verify_skips_network(runner, fake_creds, monkeypatch):
|
|
97
|
+
fake_creds.write_text(
|
|
98
|
+
'[forge_auth]\napi_key = "fk_live_offline"\n', encoding="utf-8",
|
|
99
|
+
)
|
|
100
|
+
# If verify were called, this would explode. --no-verify must skip it.
|
|
101
|
+
monkeypatch.setattr(
|
|
102
|
+
whoami_cmd, "ForgeAuthClient",
|
|
103
|
+
lambda: (_ for _ in ()).throw(RuntimeError("verify must not be called")),
|
|
104
|
+
)
|
|
105
|
+
out = runner.invoke(whoami_cmd.app, ["--no-verify", "--json"])
|
|
106
|
+
assert out.exit_code == 0
|
|
107
|
+
body = json.loads(out.output)
|
|
108
|
+
assert body["ok"] is True
|
|
109
|
+
assert body["verify_ok"] is False
|
|
110
|
+
assert "skipped" in body["verify_reason"]
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def test_whoami_verify_rejection_exits_1(runner, fake_creds, monkeypatch):
|
|
114
|
+
fake_creds.write_text(
|
|
115
|
+
'[forge_auth]\napi_key = "fk_live_revoked"\n', encoding="utf-8",
|
|
116
|
+
)
|
|
117
|
+
monkeypatch.setattr(
|
|
118
|
+
whoami_cmd, "ForgeAuthClient",
|
|
119
|
+
lambda: _StubClient({"ok": False, "reason": "key revoked", "email": "", "plan": ""}),
|
|
120
|
+
)
|
|
121
|
+
out = runner.invoke(whoami_cmd.app, ["--json"])
|
|
122
|
+
assert out.exit_code == 1
|
|
123
|
+
body = json.loads(out.output)
|
|
124
|
+
assert body["ok"] is False
|
|
125
|
+
assert body["verify_ok"] is False
|
|
126
|
+
assert "revoked" in body["verify_reason"]
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/auth_constants.py
RENAMED
|
File without changes
|
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/config_defaults.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/emergent_types.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/error_codes.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/forge_types.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/gen_language.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/lang_extensions.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/policy_schema.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/receipt_schema.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/roi_constants.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/semantic_types.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/sidecar_schema.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/synergy_types.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a0_qk_constants/tier_names.py
RENAMED
|
File without changes
|
{atomadic_forge-0.3.3 → atomadic_forge-0.3.4}/src/atomadic_forge/a1_at_functions/__init__.py
RENAMED
|
File without changes
|
|
File without changes
|