asecli 0.8.2__tar.gz → 0.8.3__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.
- {asecli-0.8.2 → asecli-0.8.3}/.github/workflows/ci.yml +2 -11
- {asecli-0.8.2 → asecli-0.8.3}/.github/workflows/publish.yml +3 -12
- {asecli-0.8.2 → asecli-0.8.3}/AGENTS.md +7 -0
- {asecli-0.8.2 → asecli-0.8.3}/PKG-INFO +8 -8
- {asecli-0.8.2 → asecli-0.8.3}/README.md +7 -7
- asecli-0.8.3/docs/adversarial-audits/2026-09-14-132814-audit-report.md +94 -0
- asecli-0.8.3/docs/adversarial-audits/2026-09-14-132814-optimization-plan.md +56 -0
- {asecli-0.8.2 → asecli-0.8.3}/pyproject.toml +1 -1
- {asecli-0.8.2 → asecli-0.8.3}/skills/asecli/SKILL.md +3 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/__init__.py +1 -1
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/contracts.py +3 -0
- asecli-0.8.3/tests/test_cross_cli_workflow.py +39 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_governance.py +1 -1
- asecli-0.8.3/tests/test_smoke.py +4 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/check_ci_governance.py +1 -0
- asecli-0.8.3/tools/independent_wheel_smoke.py +90 -0
- {asecli-0.8.2 → asecli-0.8.3}/uv.lock +2 -2
- asecli-0.8.2/.github/workflows/cross-cli.yml +0 -123
- asecli-0.8.2/tests/test_cross_cli_workflow.py +0 -38
- asecli-0.8.2/tests/test_smoke.py +0 -4
- {asecli-0.8.2 → asecli-0.8.3}/.gitignore +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/.project-architect.json +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/LICENSE +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/SECURITY.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/00-governance/audit-supplement.json +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/00-governance/change-register.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/00-governance/delivery-protocol.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/00-governance/project-charter.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/00-governance/supply-chain-policy.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/00-governance/timeline.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/00-governance/traceability.csv +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/01-architecture/assumption-experiments.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/01-architecture/module-map.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/01-architecture/project-architecture-and-requirements.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/01-architecture/technical-route.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/03-quality/bug-register.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/03-quality/regression-catalog.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/03-quality/test-strategy.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/04-delivery/project-plan-task-charter.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/04-delivery/roadmap.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-014104-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-014104-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-145343-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-145343-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-193521-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-193521-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-203438-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-01-203438-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-02-121155-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-02-121155-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-02-175509-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-02-175509-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-04-122304-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-04-122304-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-05-142617-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-05-142617-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-05-160945-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-05-160945-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-05-213523-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-05-213523-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-10-193631-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-10-193631-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-14-123640-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-14-123640-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-14-124947-audit-report.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/adversarial-audits/2026-09-14-124947-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/first-principles/2026-08-31-231401-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/first-principles/2026-09-01-190656-optimization-plan.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/docs/proposals/2026-09-07-shadergraph-to-ase-requirements.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/scripts/install.ps1 +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/scripts/install.sh +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/skills/asecli/references/conversion-publication-receipt.v1.schema.json +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/skills/asecli/references/conversion-workflow.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/skills/asecli/references/layout-standard.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/skills/asecli/references/master-output-settings-standard.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/skills/asecli/references/material-property-standard.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/__init__.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_editor_port_contract.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_editor_primitives.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_editor_spec_grammar.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_editor_spec_io.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_editor_spec_validation.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_gui_handoff_store.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_gui_project.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_gui_resource_store.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/_gui_resource_upgrade.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/editor_create.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/editor_spec.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/graph_geometry.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/graph_geometry_parser.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/graph_inspect.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/gui_handoff.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/gui_presentation.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/gui_provider_detection.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/gui_runtime_probe.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/gui_support.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/gui_support_resource.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/mcp_client.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/recompile.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/render_settings.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resource_text.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.authoring.part00.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.authoring.part01.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.authoring.store.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.condition.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.hydration.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.part00.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.part01.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.reconciliation.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/asecli_material_gui.transaction.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/editor_create.part00.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/editor_create.part01.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/editor_create.part02.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/editor_create.part03.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/editor_create.part04.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/resources/wire_route.transaction.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/bridge/wire_route.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/checks/__init__.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/checks/checksum.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/checks/local_vars.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/checks/usage.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/checks/validate.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/__init__.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/commands.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/commentary_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/contract.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/contract_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/conversion_output.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/create_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/custom_gui_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/export_sg_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/graph_review_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/gui_provider.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/gui_support_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/io.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/layout_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/main.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/migrate_package_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/recompile_metadata.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/skill_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/cli/usage_command.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/contracts/editor-graph-spec.v3.schema.json +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/contracts/sgcli.native.v3.schema.json +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/__init__.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/comment_bounds.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/comment_layout.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/comment_metrics.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/comment_purpose.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/commentary.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/compiled_metadata.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/compiled_properties.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/custom_gui.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/custom_gui_versions.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/fishbone_placement.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/fishbone_topology.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/graph_ops.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/graph_review.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/island_layout.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/layout.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/layout_audit.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/layout_audit_geometry.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/layout_audit_repeated.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/layout_graph.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/local_vars.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/material_gui_condition.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/material_gui_protocol.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/material_gui_spec.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/meticulous_layout.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/model.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/property_presentation.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/reuse_plan.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/wire_geometry.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/core/wire_router.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/export_sg.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/schema/__init__.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/schema/data/observed.json +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/schema/data/schemas.json +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/schema_validation.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/__init__.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/alpha_modulate.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/binding.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/conversion_report.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/custom_expression.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/decoder.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/evidence.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/model.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/nodes.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/pass_blend.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/reconciliation.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/report_semantics.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/sources.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/surface_matching.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/src/asecli/sg_export/surface_semantics.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/TEST.md +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/__init__.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/conftest.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/editor_create_v3_fixture.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/fixtures/HLIT.shader +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/fixtures/asecli_material_gui_v0_2_0.cs.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/fixtures/step-antialiasing.function.txt +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_adversarial_hardening.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_audit_fixes.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_bridge_contract.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_bridge_recompile.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_build_reproducibility.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_cli_contract.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_commentary.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_contract_schema.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_conversion_report_semantics.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_core_contract.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_create.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_create_constant_presentation.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_custom_gui.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_custom_gui_cli.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_editor_create_bridge.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_editor_create_cli.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_editor_create_e2e.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_editor_create_spec.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_editor_create_spec_v3.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_editor_render_settings.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_export_property_visibility.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_export_sg.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_graph_review.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_graph_safety.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_gui_handoff.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_gui_native_extension.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_gui_support.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_gui_support_cli_contract.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_gui_upgrade.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_install_scripts.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_island_layout.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_layout.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_layout_governance.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_layout_local_var_policy.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_material_gui_e2e.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_mcp_security.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_migrate_package.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_mutate.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_pass_blend.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_perf.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_property_presentation.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_roundtrip.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_schema_add.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_schema_samples.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_sg_export_sources.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_skill_install.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_supply_chain.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_surface_semantics.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_surface_semantics_integration.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_usage_audit.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tests/test_wire_route_bridge.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/build_schema.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/check_document_governance.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/check_packed_executor_loc.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/check_regression_catalog.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/check_release_candidate.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/compare_build_artifacts.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/generate_sbom.py +0 -0
- {asecli-0.8.2 → asecli-0.8.3}/tools/supply_chain_check.py +0 -0
|
@@ -82,6 +82,8 @@ jobs:
|
|
|
82
82
|
- run: uv venv .artifact-venv --python 3.12
|
|
83
83
|
- run: uv pip install --python .artifact-venv/bin/python "dist/asecli-$ASECLI_VERSION-py3-none-any.whl"
|
|
84
84
|
- run: .artifact-venv/bin/asecli parse tests/fixtures/step-antialiasing.function.txt
|
|
85
|
+
- name: Verify standalone wheel JSON contract
|
|
86
|
+
run: .artifact-venv/bin/python tools/independent_wheel_smoke.py
|
|
85
87
|
- name: Smoke test packaged GUI installer
|
|
86
88
|
run: |
|
|
87
89
|
test_project="$RUNNER_TEMP/asecli-gui-smoke"
|
|
@@ -93,14 +95,3 @@ jobs:
|
|
|
93
95
|
name: asecli-candidate-${{ github.sha }}
|
|
94
96
|
path: dist/
|
|
95
97
|
if-no-files-found: error
|
|
96
|
-
|
|
97
|
-
cross-cli:
|
|
98
|
-
needs: package
|
|
99
|
-
uses: ./.github/workflows/cross-cli.yml
|
|
100
|
-
with:
|
|
101
|
-
sgcli_ref: ${{ vars.SGCLI_CANDIDATE_SHA }}
|
|
102
|
-
asecli_artifact_name: asecli-candidate-${{ github.sha }}
|
|
103
|
-
secrets:
|
|
104
|
-
sgcli_read_ssh_key: ${{ secrets.SGCLI_READ_SSH_KEY }}
|
|
105
|
-
permissions:
|
|
106
|
-
contents: read
|
|
@@ -76,6 +76,8 @@ jobs:
|
|
|
76
76
|
- run: uv venv .artifact-venv --python 3.12
|
|
77
77
|
- run: uv pip install --python .artifact-venv/bin/python "dist/asecli-${ASECLI_VERSION}-py3-none-any.whl"
|
|
78
78
|
- run: .artifact-venv/bin/asecli parse tests/fixtures/step-antialiasing.function.txt
|
|
79
|
+
- name: Verify standalone wheel JSON contract
|
|
80
|
+
run: .artifact-venv/bin/python tools/independent_wheel_smoke.py
|
|
79
81
|
- run: .artifact-venv/bin/asecli install-skill --skill-root "$RUNNER_TEMP/codex-skills"
|
|
80
82
|
- name: Smoke test packaged GUI installer
|
|
81
83
|
run: |
|
|
@@ -89,19 +91,8 @@ jobs:
|
|
|
89
91
|
path: dist/
|
|
90
92
|
if-no-files-found: error
|
|
91
93
|
|
|
92
|
-
cross-cli:
|
|
93
|
-
needs: package
|
|
94
|
-
uses: ./.github/workflows/cross-cli.yml
|
|
95
|
-
with:
|
|
96
|
-
sgcli_ref: ${{ vars.SGCLI_CANDIDATE_SHA }}
|
|
97
|
-
asecli_artifact_name: asecli-candidate-${{ github.sha }}
|
|
98
|
-
secrets:
|
|
99
|
-
sgcli_read_ssh_key: ${{ secrets.SGCLI_READ_SSH_KEY }}
|
|
100
|
-
permissions:
|
|
101
|
-
contents: read
|
|
102
|
-
|
|
103
94
|
publish:
|
|
104
|
-
needs:
|
|
95
|
+
needs: package
|
|
105
96
|
if: ${{ vars.ASECLI_PYPI_ENABLED == 'true' }}
|
|
106
97
|
runs-on: ubuntu-latest
|
|
107
98
|
environment:
|
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
# ASECLI 工程执行规则
|
|
2
2
|
|
|
3
|
+
## 单仓独立边界
|
|
4
|
+
|
|
5
|
+
- ASECLI 任务只修改本仓库;不得因转换、测试失败或发布而自动修改、提交、推送 SGCLI。对方缺能力时记录协议需求,由用户另行授权对方任务。
|
|
6
|
+
- 运行、构建、必需测试、发布和安装不得依赖对方源码、开发目录、可执行文件、候选分支或跨仓凭据。
|
|
7
|
+
- 允许携带版本化公开 JSON Schema 静态快照;摘要用于本包完整性,不要求等于对方当前 main。未知语义继续失败关闭。
|
|
8
|
+
- 跨产品验收属于另行授权的外部黑盒编排,不成为本仓发布前置,不回写对方。
|
|
9
|
+
|
|
3
10
|
## 默认采用快速路径
|
|
4
11
|
|
|
5
12
|
- 文档、注释、文案和不改变行为的配置修改,只检查相关 diff、格式与直接引用;不得启动 Unity/Tuanjie、截图、运行全量 pytest、发布治理或构建发布包。
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: asecli
|
|
3
|
-
Version: 0.8.
|
|
3
|
+
Version: 0.8.3
|
|
4
4
|
Summary: Agent-native CLI for reading, modifying, validating and compiling Amplify Shader Editor assets
|
|
5
5
|
Project-URL: Homepage, https://github.com/seeseeczl/ASECLI
|
|
6
6
|
Project-URL: Repository, https://github.com/seeseeczl/ASECLI
|
|
@@ -28,7 +28,7 @@ Description-Content-Type: text/markdown
|
|
|
28
28
|
|
|
29
29
|
AseCLI 是面向 AI Agent 的本地 CLI:离线读取、编辑和校验 ASE 节点图;通过运行中的 Unity/团结引擎与 MCP,让真实 ASE 创建节点、提供精排几何并重新生成 HLSL。Skill 提供跨 Agent 的操作规则,CLI 提供可验证的执行结果。
|
|
30
30
|
|
|
31
|
-
当前正式版:**[0.8.
|
|
31
|
+
当前正式版:**[0.8.3](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.3)** · [PyPI](https://pypi.org/project/asecli/0.8.3/) · [Agent 操作手册](skills/asecli/SKILL.md) · [SG 转换后整理流程](skills/asecli/references/conversion-workflow.md)
|
|
32
32
|
|
|
33
33
|
ASECLI 接收 SGCLI 生成的裸 `EditorGraphSpec v3`,并可把受支持的 ASE Shader 直接导出为 SGCLI 的裸 `sgcli.native.v3`。两个方向都只有“生产者 spec 原文件→消费者 `--spec`”;独立 report 与发布 receipt 都不进入创建输入,创建成功也不代表转换效果等价。
|
|
34
34
|
|
|
@@ -132,7 +132,7 @@ curl -fsSL https://raw.githubusercontent.com/seeseeczl/ASECLI/main/scripts/insta
|
|
|
132
132
|
uv tool uninstall asecli
|
|
133
133
|
```
|
|
134
134
|
|
|
135
|
-
当前正式版本为 `0.8.
|
|
135
|
+
当前正式版本为 `0.8.3`(独立 CI/发布流程与单工具 wheel 验证),可从 [PyPI](https://pypi.org/project/asecli/0.8.3/) 或 [GitHub Release](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.3) 安装。历史版本见 [GitHub Releases](https://github.com/seeseeczl/ASECLI/releases),`v0.8.0` 保留为回滚点。
|
|
136
136
|
|
|
137
137
|
已知限制:真实 MCP 下,属性+纹理 v2 和 Reciprocal 降级 v2 的 create、manifest、validate、独立 recompile 已通过;SGCLI SphereMask v3 spec 在重载时仍可能返回 `node missing after reload: Radius` 并回滚。本次不承诺该 recipe 端到端可用,也不改变 SGCLI v2 默认值契约。
|
|
138
138
|
|
|
@@ -162,7 +162,7 @@ asecli --help
|
|
|
162
162
|
|
|
163
163
|
```bash
|
|
164
164
|
shasum -a 256 -c SHA256SUMS
|
|
165
|
-
uv tool install /path/to/asecli-0.8.
|
|
165
|
+
uv tool install /path/to/asecli-0.8.3-py3-none-any.whl
|
|
166
166
|
asecli --help
|
|
167
167
|
```
|
|
168
168
|
|
|
@@ -207,7 +207,7 @@ sgcli sg create Assets/ConvertedNew.shadergraph \
|
|
|
207
207
|
|
|
208
208
|
`export-sg` 自动从源 Shader 向上识别 Unity/Tuanjie 工程;跨工程资源解析时显式传 `--target-project`。它强制生成 `<stem>.asecli-to-sgcli.spec.json`、`.report.json` 与 `.receipt.json`,同名即失败;receipt 只证明 spec/report 两份文件的提交状态与 SHA,不是中间交接包。命令不调用 SGCLI,也不生成 ASE 自有中间 JSON。未知节点、Master/Pass、外部属性或纹理 Importer 语义时只写规范报告,不写半成品 spec。反方向 `.asecli-to-sgcli.spec.json` 不能交给 ASECLI `create --spec`。
|
|
209
209
|
|
|
210
|
-
ASECLI 随 wheel
|
|
210
|
+
ASECLI 随 wheel 发布自己的 EditorGraphSpec v3 Schema,以及源自 SGCLI `0.3.5` 的固定 `sgcli.native.v3` JSON 快照。快照 SHA-256 标识本包完整性与精确协议修订,不依赖对方当前分支或安装版本。构建、测试、发布与安装只使用 ASECLI,不拉取或执行 SGCLI 源码,不要求同步发布。`MultiplySourceAlpha` 等扩展仍要求实际消费者和目标 URP 支持,导出成功不代表旧消费者兼容。跨产品端到端验收是独立黑盒流程,不是本仓发布前置;本仓任务不自动跨仓修改。
|
|
211
211
|
|
|
212
212
|
可用 `asecli contract editor-graph --version 3 --spec FILE` 在不连接 Editor 时执行权威 Schema/loader 并返回原文件 SHA。报告分开记录来源快照、发布前复核、生产者 Schema 与真实消费者读取状态。旧 `{graph,report}` wrapper 只允许按已登记形状显式迁移,且内层必须已经是 `sgcli.native.v3`;无版本 discriminator 的旧输入只报告 `legacy_format`,不得伪称已识别版本化 Schema:
|
|
213
213
|
|
|
@@ -340,9 +340,9 @@ asecli recompile Assets/Example.shader
|
|
|
340
340
|
除显式 `--help` 保留人类可读文本外,stdout 恒为单行严格 JSON,agent 可直接解析。`--version` 也返回 JSON:
|
|
341
341
|
|
|
342
342
|
```json
|
|
343
|
-
{"contract_version":1,"cli_version":"0.8.
|
|
344
|
-
{"contract_version":1,"cli_version":"0.8.
|
|
345
|
-
{"contract_version":1,"cli_version":"0.8.
|
|
343
|
+
{"contract_version":1,"cli_version":"0.8.3","command":"parse","ok":true,"data":{"node_count":7}}
|
|
344
|
+
{"contract_version":1,"cli_version":"0.8.3","command":"parse","ok":false,"error":{"code":"NOT_FOUND","message":"..."}}
|
|
345
|
+
{"contract_version":1,"cli_version":"0.8.3","command":"version","ok":true,"data":{"version":"0.8.3"}}
|
|
346
346
|
```
|
|
347
347
|
|
|
348
348
|
常见错误码:`PARSE_ERROR`、`NOT_FOUND`、`USAGE_ERROR`、`SCHEMA_UNAVAILABLE`、`SCHEMA_VERSION_MISMATCH`、`VALIDATION_ERROR`、`PROPERTY_PRESENTATION_ERROR`、`LAYOUT_ERROR`、`CHECKSUM_FORMAT_ERROR`、`GUI_SUPPORT_ERROR`、`CUSTOM_GUI_ERROR`、`COMMENT_GROUP_ERROR`、`GRAPH_REVIEW_ERROR`、`SEMANTIC_MISMATCH`、`SG_EXPORT_BLOCKED`、`EXTERNAL_REFERENCE`、`SKILL_INSTALL_CONFLICT`、`SKILL_INSTALL_ERROR`、`WRITE_CONFLICT`、`WRITE_PARTIAL`、`UNSAFE_PATH`、`WRITE_ERROR`、`BRIDGE_ERROR`、`INTERNAL`。
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
AseCLI 是面向 AI Agent 的本地 CLI:离线读取、编辑和校验 ASE 节点图;通过运行中的 Unity/团结引擎与 MCP,让真实 ASE 创建节点、提供精排几何并重新生成 HLSL。Skill 提供跨 Agent 的操作规则,CLI 提供可验证的执行结果。
|
|
6
6
|
|
|
7
|
-
当前正式版:**[0.8.
|
|
7
|
+
当前正式版:**[0.8.3](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.3)** · [PyPI](https://pypi.org/project/asecli/0.8.3/) · [Agent 操作手册](skills/asecli/SKILL.md) · [SG 转换后整理流程](skills/asecli/references/conversion-workflow.md)
|
|
8
8
|
|
|
9
9
|
ASECLI 接收 SGCLI 生成的裸 `EditorGraphSpec v3`,并可把受支持的 ASE Shader 直接导出为 SGCLI 的裸 `sgcli.native.v3`。两个方向都只有“生产者 spec 原文件→消费者 `--spec`”;独立 report 与发布 receipt 都不进入创建输入,创建成功也不代表转换效果等价。
|
|
10
10
|
|
|
@@ -108,7 +108,7 @@ curl -fsSL https://raw.githubusercontent.com/seeseeczl/ASECLI/main/scripts/insta
|
|
|
108
108
|
uv tool uninstall asecli
|
|
109
109
|
```
|
|
110
110
|
|
|
111
|
-
当前正式版本为 `0.8.
|
|
111
|
+
当前正式版本为 `0.8.3`(独立 CI/发布流程与单工具 wheel 验证),可从 [PyPI](https://pypi.org/project/asecli/0.8.3/) 或 [GitHub Release](https://github.com/seeseeczl/ASECLI/releases/tag/v0.8.3) 安装。历史版本见 [GitHub Releases](https://github.com/seeseeczl/ASECLI/releases),`v0.8.0` 保留为回滚点。
|
|
112
112
|
|
|
113
113
|
已知限制:真实 MCP 下,属性+纹理 v2 和 Reciprocal 降级 v2 的 create、manifest、validate、独立 recompile 已通过;SGCLI SphereMask v3 spec 在重载时仍可能返回 `node missing after reload: Radius` 并回滚。本次不承诺该 recipe 端到端可用,也不改变 SGCLI v2 默认值契约。
|
|
114
114
|
|
|
@@ -138,7 +138,7 @@ asecli --help
|
|
|
138
138
|
|
|
139
139
|
```bash
|
|
140
140
|
shasum -a 256 -c SHA256SUMS
|
|
141
|
-
uv tool install /path/to/asecli-0.8.
|
|
141
|
+
uv tool install /path/to/asecli-0.8.3-py3-none-any.whl
|
|
142
142
|
asecli --help
|
|
143
143
|
```
|
|
144
144
|
|
|
@@ -183,7 +183,7 @@ sgcli sg create Assets/ConvertedNew.shadergraph \
|
|
|
183
183
|
|
|
184
184
|
`export-sg` 自动从源 Shader 向上识别 Unity/Tuanjie 工程;跨工程资源解析时显式传 `--target-project`。它强制生成 `<stem>.asecli-to-sgcli.spec.json`、`.report.json` 与 `.receipt.json`,同名即失败;receipt 只证明 spec/report 两份文件的提交状态与 SHA,不是中间交接包。命令不调用 SGCLI,也不生成 ASE 自有中间 JSON。未知节点、Master/Pass、外部属性或纹理 Importer 语义时只写规范报告,不写半成品 spec。反方向 `.asecli-to-sgcli.spec.json` 不能交给 ASECLI `create --spec`。
|
|
185
185
|
|
|
186
|
-
ASECLI 随 wheel
|
|
186
|
+
ASECLI 随 wheel 发布自己的 EditorGraphSpec v3 Schema,以及源自 SGCLI `0.3.5` 的固定 `sgcli.native.v3` JSON 快照。快照 SHA-256 标识本包完整性与精确协议修订,不依赖对方当前分支或安装版本。构建、测试、发布与安装只使用 ASECLI,不拉取或执行 SGCLI 源码,不要求同步发布。`MultiplySourceAlpha` 等扩展仍要求实际消费者和目标 URP 支持,导出成功不代表旧消费者兼容。跨产品端到端验收是独立黑盒流程,不是本仓发布前置;本仓任务不自动跨仓修改。
|
|
187
187
|
|
|
188
188
|
可用 `asecli contract editor-graph --version 3 --spec FILE` 在不连接 Editor 时执行权威 Schema/loader 并返回原文件 SHA。报告分开记录来源快照、发布前复核、生产者 Schema 与真实消费者读取状态。旧 `{graph,report}` wrapper 只允许按已登记形状显式迁移,且内层必须已经是 `sgcli.native.v3`;无版本 discriminator 的旧输入只报告 `legacy_format`,不得伪称已识别版本化 Schema:
|
|
189
189
|
|
|
@@ -316,9 +316,9 @@ asecli recompile Assets/Example.shader
|
|
|
316
316
|
除显式 `--help` 保留人类可读文本外,stdout 恒为单行严格 JSON,agent 可直接解析。`--version` 也返回 JSON:
|
|
317
317
|
|
|
318
318
|
```json
|
|
319
|
-
{"contract_version":1,"cli_version":"0.8.
|
|
320
|
-
{"contract_version":1,"cli_version":"0.8.
|
|
321
|
-
{"contract_version":1,"cli_version":"0.8.
|
|
319
|
+
{"contract_version":1,"cli_version":"0.8.3","command":"parse","ok":true,"data":{"node_count":7}}
|
|
320
|
+
{"contract_version":1,"cli_version":"0.8.3","command":"parse","ok":false,"error":{"code":"NOT_FOUND","message":"..."}}
|
|
321
|
+
{"contract_version":1,"cli_version":"0.8.3","command":"version","ok":true,"data":{"version":"0.8.3"}}
|
|
322
322
|
```
|
|
323
323
|
|
|
324
324
|
常见错误码:`PARSE_ERROR`、`NOT_FOUND`、`USAGE_ERROR`、`SCHEMA_UNAVAILABLE`、`SCHEMA_VERSION_MISMATCH`、`VALIDATION_ERROR`、`PROPERTY_PRESENTATION_ERROR`、`LAYOUT_ERROR`、`CHECKSUM_FORMAT_ERROR`、`GUI_SUPPORT_ERROR`、`CUSTOM_GUI_ERROR`、`COMMENT_GROUP_ERROR`、`GRAPH_REVIEW_ERROR`、`SEMANTIC_MISMATCH`、`SG_EXPORT_BLOCKED`、`EXTERNAL_REFERENCE`、`SKILL_INSTALL_CONFLICT`、`SKILL_INSTALL_ERROR`、`WRITE_CONFLICT`、`WRITE_PARTIAL`、`UNSAFE_PATH`、`WRITE_ERROR`、`BRIDGE_ERROR`、`INTERNAL`。
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
# 对抗性审计报告:ASECLI / SGCLI 独立性与跨仓耦合
|
|
2
|
+
|
|
3
|
+
> 生成时间:2026-09-14 13:28:14(Asia/Shanghai)
|
|
4
|
+
> 落盘根目录:/Users/long/GitHub/ASECLI
|
|
5
|
+
> Skill:adversarial-audit
|
|
6
|
+
> 关联优化计划:2026-09-14-132814-optimization-plan.md
|
|
7
|
+
|
|
8
|
+
## 审计边界
|
|
9
|
+
|
|
10
|
+
- 用户要求:各自独立开发、构建、测试、发布、安装;可以按对方公开规范产出 JSON,不互相引用实现代码,不因一方任务默认跨仓修改。
|
|
11
|
+
- 只读检查两个仓库的源码、依赖、打包、工作流、契约、跨仓测试及技能。仅新增本报告与计划,不修改 SGCLI,不执行发布。
|
|
12
|
+
- 当前基线:ASECLI `89eb9ae22d94a8d056c7fd28b5923d7dd513ac69`;SGCLI `488776fe996d226d8900dbe69e0547737c9986b4`。本轮开始时既有修复已进入新的 HEAD;此前对旧候选 Schema 不一致的观察不能当作当前两仓仍失配的证据。
|
|
13
|
+
- 方法:静态调用/依赖追踪、工作流依赖图与失败条件检查。没有运行两仓全量测试、隔离安装或远端 CI;不将静态未发现视为任意动态环境下的绝对证明。
|
|
14
|
+
|
|
15
|
+
## 威胁与失败模型
|
|
16
|
+
|
|
17
|
+
- 资产:独立 CLI 运行、可重复发布、JSON 兼容性、仓库写入边界。
|
|
18
|
+
- 对方仓库可能暂不可访问、存在未提交改动、接口加性升级或主分支变化。
|
|
19
|
+
- 任一方应能离线验证本地固定协议,而不要求安装/获取对方实现。
|
|
20
|
+
- 不支持的语义必须拒绝并生成诊断,不通过跨仓自动修复或弱化验证掩盖。
|
|
21
|
+
- 最贵失败:自身代码无变化却无法发布;为解锁发布误改对方;混装测试漏掉真实运行依赖。
|
|
22
|
+
|
|
23
|
+
## Findings 汇总
|
|
24
|
+
|
|
25
|
+
| ID | 严重度 | 标题 | 证据等级 | 任务 |
|
|
26
|
+
| --- | --- | --- | --- | --- |
|
|
27
|
+
| AA-COUP-001 | P1 | 默认 CI / ASECLI 发布依赖对方源码与跨仓权限 | 已验证(静态) | AA-OPT-001 |
|
|
28
|
+
| AA-COUP-002 | P1 | 两端候选 Schema 字节相等被当作发布兼容要求 | 已验证(静态) | AA-OPT-002 |
|
|
29
|
+
| AA-COUP-003 | P2 | 集成测试代码绑定兄弟仓库与双方工作树状态 | 已验证(静态) | AA-OPT-003 |
|
|
30
|
+
| AA-COUP-004 | P2 | 双 wheel 混装不足以证明单工具运行独立性 | 已验证(覆盖缺口) | AA-OPT-004 |
|
|
31
|
+
|
|
32
|
+
## Findings 详情
|
|
33
|
+
|
|
34
|
+
### [P1] AA-COUP-001 — 将跨仓检查从单仓必需发布路径分离
|
|
35
|
+
|
|
36
|
+
- 证据:ASECLI `.github/workflows/publish.yml:103-104` 的 publish 需要 `[package, cross-cli]`;cross-cli 从对方仓库取得代码、构建 wheel、执行 SGCLI/scripts 内的校验实现,并要求对方 commit 与 SSH secret。ASECLI `.github/workflows/ci.yml:97` 默认接入相同检查。
|
|
37
|
+
- SGCLI `.github/workflows/ci.yml:103-108` 在 main / tag CI 接入跨仓检查,使用 ASECLI 浮动 `main`;`.github/workflows/cross-cli.yml:36-38` checkout 对方。这里只证明 SGCLI 默认 CI 被绑定,未发现同等的 SGCLI PyPI publish job,不扩大为该发布机制已验证。
|
|
38
|
+
- 触发:对方仓库/权限不可用,或对方 main 变化导致矩阵不通过。
|
|
39
|
+
- 影响:ASECLI 正式发布被阻断;SGCLI 同一提交的 CI 可受对方 main 影响,违反独立维护要求。
|
|
40
|
+
- 两仓 `tests/test_cross_cli_workflow.py` 还强制检查这种关联存在;ASECLI 测试第 18 行直接要求 publish 的跨仓 needs。仅删 workflow 引用会导致本地测试失败,需在本仓同时更新对应测试。
|
|
41
|
+
- 修复方向:单仓发布依赖自身检查、固定协议夹具和独立 wheel smoke;可选跨产品黑盒测试移出单仓必需发布路径,最好独立测试工程管理。分别在每个仓库执行,不自动联动。
|
|
42
|
+
- 关联:AA-OPT-001。
|
|
43
|
+
|
|
44
|
+
### [P1] AA-COUP-002 — 区分协议快照完整性与跨版本兼容性
|
|
45
|
+
|
|
46
|
+
- 证据:SGCLI `scripts/cross_cli_wheels.py:74-105` 读取两包四份 Schema 并直接比较 `consumer_raw == producer_raw`;`scripts/check_cross_cli_contracts.py:370-398` 将相等性纳入 ok。两仓 README 明确要求同步双方候选快照。
|
|
47
|
+
- 触发:对方只改 Schema 排版、说明或添加兼容字段,生产者仍产生被目标支持的 JSON,但字节摘要不同。
|
|
48
|
+
- 影响:语义兼容也要求同步更新/发布;Schema 名称保持 v3 时又增添新能力,会进一步造成版本标签不能充分表达能力集合。
|
|
49
|
+
- 修复方向:本包固定 Schema 的自完整性 SHA 校验保留;不要要求始终等于对方当前分支。以明确协议修订/能力集合和正负 JSON 夹具验证支持范围。新能力不能因单方发布就声明所有旧消费者可用。
|
|
50
|
+
- 注意:随包携带静态 JSON Schema 是允许的协议关联,不是运行代码依赖,不应删除。
|
|
51
|
+
- 关联:AA-OPT-002。
|
|
52
|
+
|
|
53
|
+
### [P2] AA-COUP-003 — 集成工具仍读取另一仓库内部结构
|
|
54
|
+
|
|
55
|
+
- 证据:SGCLI `scripts/check_cross_cli_contracts.py:52` 读取兄弟仓库源码 Schema;第 344 行默认 `../ASECLI`,第 370-377、425-428 行依赖双方仓库身份和干净工作树;`scripts/e2e_sgcli_to_ase.py:34` 默认使用 `../ASECLI/.venv/bin/asecli`。
|
|
56
|
+
- 触发:只克隆一个仓库、另一个仓库目录不同,或另一个任务有未提交布局改动。
|
|
57
|
+
- 影响:集成验证依赖对方开发目录,不符合“工具仓库之间不保留实现关联”的强独立目标。当前脚本以读取/执行为主,未据此认定会自动编辑另一仓源码。
|
|
58
|
+
- 修复方向:两个工具仓库各保留自身协议测试;跨产品场景搬到单独、显式运行的黑盒测试工程,只接受已发布包/可执行文件和 JSON,不读取对方 src 或 git 状态。不要为通过测试自动 stash/commit 对方。
|
|
59
|
+
- 关联:AA-OPT-003。
|
|
60
|
+
|
|
61
|
+
### [P2] AA-COUP-004 — 增加仅安装自身的运行独立性反例
|
|
62
|
+
|
|
63
|
+
- 证据:SGCLI `scripts/cross_cli_wheels.py:46-67` 把两个 wheel 安装到同一个 venv;这类测试即使通过,也不能排除未来代码隐式使用对方包。
|
|
64
|
+
- 边界:两仓现有 package job 已有单 wheel smoke,这是有效局部证据;缺口在完整的独立导出/校验/失败路径与跨仓调用禁止验证,不是“完全没有独立测试”。
|
|
65
|
+
- 触发:后续新增对方 import、PATH 子进程调用或开发目录读取,但混装测试依然通过。
|
|
66
|
+
- 修复方向:分别在只安装自身 wheel、无兄弟目录、对方不在 PATH 的隔离环境验证本工具导出与 JSON 校验;加静态禁止互相 import/路径引用检查。验证非法或不支持 JSON 仍失败关闭。
|
|
67
|
+
- 关联:AA-OPT-004。
|
|
68
|
+
|
|
69
|
+
## 当前没有发现的运行代码耦合
|
|
70
|
+
|
|
71
|
+
- 两边 `pyproject.toml` 的运行 `dependencies=[]`,wheel 配置只打包自身代码与自身携带的静态数据。
|
|
72
|
+
- 检查两边 src Python,未发现互相 import、子进程启动对方 CLI、动态导入对方或对方开发目录路径引用。
|
|
73
|
+
- 两边 contracts.py 从各自包资源加载 Schema,`package`/`version` 字符串是元数据,不是安装依赖。未发现互相链接的 tracked symlink/submodule。
|
|
74
|
+
- ASECLI 生成 JSON,SGCLI 自己读取并验证;转换报告规则分别实现。相似规则/重复校验不等于共享可执行模块。
|
|
75
|
+
- SGCLI 资源证据重查需要 JSON 所指向的源/目标图片和 meta 可访问,这是资源可移植性限制,不是必须安装 ASECLI。不得为了独立性直接删除证据校验。
|
|
76
|
+
- MultiplySourceAlpha 还依赖目标工程的对应 URP 能力,这是引擎能力依赖,不是 CLI 互相依赖。
|
|
77
|
+
|
|
78
|
+
## 技能与操作边界
|
|
79
|
+
|
|
80
|
+
- 两端 authoring 技能已经写明 CLI 不调用对方;联合 shader-conversion 技能描述先后调用两个独立 CLI,这属于用户级编排,不等于 CLI 内部调用。
|
|
81
|
+
- SGCLI 的 install-skill 分发联合转换/等价技能,但不分发 ASECLI 实现或 ASECLI authoring skill;没有据此认定代码耦合。
|
|
82
|
+
- 当前资料包含两边配套升级、同步候选的历史流程;尚缺清楚的单仓维修边界。遵循用户本轮新要求:后续一仓任务不能默认改另一仓,发现对方缺能力只输出协议需求/诊断,另行授权对方任务。
|
|
83
|
+
- 本轮只提出在各自 AGENTS/技能中补充此规则的任务,不跨仓落盘规则、不更新全局记忆。
|
|
84
|
+
|
|
85
|
+
## 测试与观测缺口
|
|
86
|
+
|
|
87
|
+
- 本次未重新执行独立 wheel 安装、远端 CI、Unity 或渲染。
|
|
88
|
+
- 后续应记录本工具版本、支持的协议修订与能力、生产校验和消费者验收阶段,不以两仓同时升级为完成信号。
|
|
89
|
+
|
|
90
|
+
## 残留风险与总评
|
|
91
|
+
|
|
92
|
+
结论:运行代码层目前未发现互相依赖;开发测试与发布流程仍明显耦合,阻塞“完全独立维护/发布”目标。JSON 协议必须有约定,但不要求实现共享或发布锁步。不得用删除语义校验、放宽未知字段、伪造报告的方式解耦。
|
|
93
|
+
|
|
94
|
+
实施顺序:先在 ASECLI 单仓整改并验证独立发布;SGCLI 的整改留给其独立任务。本报告不执行任何整改、提交或发布。
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# 对抗性审计优化计划:ASECLI / SGCLI 各自独立
|
|
2
|
+
|
|
3
|
+
> 生成时间:2026-09-14 13:28:14(Asia/Shanghai)
|
|
4
|
+
> 落盘根目录:/Users/long/GitHub/ASECLI
|
|
5
|
+
> 关联报告:2026-09-14-132814-audit-report.md
|
|
6
|
+
|
|
7
|
+
## 1. 执行摘要
|
|
8
|
+
|
|
9
|
+
P0=0、P1=2、P2=2、P3=0。运行代码未发现互相依赖,独立维护/发布目标尚不通过。保留公开 JSON 协议、严格验证和失败关闭,移除强制跨仓发布与源码目录关联。
|
|
10
|
+
|
|
11
|
+
本轮仅审计。后续严格分两次执行:ASECLI 任务只修改 ASECLI;SGCLI 任务只修改 SGCLI。任何迁移到第三方集成测试工程也需另行确定目标和授权,不在本轮创建。
|
|
12
|
+
|
|
13
|
+
## 2. 修复与加固任务
|
|
14
|
+
|
|
15
|
+
| 任务 | 优先级 | 来源 | 内容 | 验收标准 | 依赖 | 风险/回滚 |
|
|
16
|
+
| --- | --- | --- | --- | --- | --- | --- |
|
|
17
|
+
| AA-OPT-001 | P1 | AA-COUP-001 | 各仓各自移除默认 CI/发布对另一仓 checkout/build 的必需依赖;同步本仓 workflow 回归 | 无对方源码、凭据和候选 SHA 时,自身测试/打包/发布路径正常;不删除本仓语义门禁 | 分仓授权 | 恢复本仓 workflow,不操作对方 |
|
|
18
|
+
| AA-OPT-002 | P1 | AA-COUP-002 | 本地固定协议修订及能力集;自完整性摘要与跨版本兼容分开 | 目标 Schema 兼容排版/描述变化不迫使双方同时发布;未知能力仍拒绝;协议声明对应夹具 | 无需对方代码 | 保留旧协议支持与不可变快照 |
|
|
19
|
+
| AA-OPT-003 | P2 | AA-COUP-003 | 移出兄弟仓库源码、虚拟环境和 git 状态相关脚本;跨产品测试另行管理 | 单仓克隆可开发;任何本仓必需命令不访问 ../另一仓;外部黑盒测试仅依赖发布接口 | 先列迁移范围,分别授权 | 保留可追溯历史,不删除用户资产 |
|
|
20
|
+
| AA-OPT-004 | P2 | AA-COUP-004 | 仅自身 wheel 的隔离导出、消费校验和负向回归 | 环境无对方模块、命令、源码,全部本仓相关路径可运行;新增耦合被门禁抓到 | 无 | 不以混装测试替代隔离证明 |
|
|
21
|
+
| AA-OPT-005 | P2 | 用户新边界 | 在各自仓库规则/技能明确“单仓任务不跨仓修改” | 对方缺能力时生成接口问题说明,停止于本仓边界;任何跨仓写入另行授权 | 各仓单独执行 | 保留转换编排能力,不禁止只读协议查阅 |
|
|
22
|
+
|
|
23
|
+
## 3. 测试补强任务
|
|
24
|
+
|
|
25
|
+
- AA-TEST-001:自身 wheel 安装在独立 venv,PATH 无另一 CLI,执行版本、导出、Schema 校验、失败报告;检查未导入另一包。
|
|
26
|
+
- AA-TEST-002:冻结协议正负 JSON 夹具,检查节点/资源/混合/报告语义;协议扩展不自动意味着旧消费者支持。
|
|
27
|
+
- AA-TEST-003:CI 静态检查不再要求另一仓 checkout、credential、branch、SHA、wheel 或脚本;对方全部不可用时本仓必要门禁仍可通过。
|
|
28
|
+
- AA-TEST-004:跨仓目录读写/互相 import/调用负例能被独立性门禁识别;集成测试不得掩盖本工具缺依赖。
|
|
29
|
+
|
|
30
|
+
## 4. 观测与运维任务
|
|
31
|
+
|
|
32
|
+
- AA-OBS-001:发布说明列出支持的协议修订、能力限制,不承诺另一 CLI 已同步升级。
|
|
33
|
+
- AA-OBS-002:可选外部兼容矩阵记录两边发布版本与 JSON SHA;结果不替代自身门禁,不回写两仓。
|
|
34
|
+
- AA-OBS-003:任务结束列明实际写入的单仓范围,确认另一仓未被该任务修改。
|
|
35
|
+
|
|
36
|
+
## 5. 发布门禁
|
|
37
|
+
|
|
38
|
+
- [ ] 本仓必需检查不执行另一仓代码、不要求另一仓权限或可用性。
|
|
39
|
+
- [ ] 只安装本工具即可执行相关导出/校验。
|
|
40
|
+
- [ ] 固定 JSON 规范和语义负向测试仍严格有效。
|
|
41
|
+
- [ ] 能独立构建、安装、回滚;报告已区分离线与 Editor/渲染证据。
|
|
42
|
+
- [ ] 没有修改另一仓库;对方任务独立安排。
|
|
43
|
+
|
|
44
|
+
## 6. 未映射项
|
|
45
|
+
|
|
46
|
+
无。静态 JSON Schema、规则实现及名称中的对方标识允许保留;它们是格式适配,不应为“无关联代码”而删除协议校验。联合工作流技能是否移至独立分发位置可另行讨论,本轮不新增运行依赖或架构项目。
|
|
47
|
+
|
|
48
|
+
## 7. ASECLI 单仓整改回执
|
|
49
|
+
|
|
50
|
+
- 已移除 ASECLI CI / publish 的 cross-cli job,publish 仍依赖自身 verify→package 的完整链路;删除本仓 `.github/workflows/cross-cli.yml`(Git 可恢复),不再 checkout 对方、使用对方 SSH secret/候选 SHA 或运行对方脚本。没有修改 GitHub 远程变量、Secret 或 SGCLI。
|
|
51
|
+
- 改为自身固定 Schema/语义正负回归及独立 wheel smoke;保留本包快照 SHA 校验,不读取另一仓实时 Schema。README/contracts 注释明确版本只是快照来源,不是运行依赖。
|
|
52
|
+
- 新增 `tools/independent_wheel_smoke.py`:仅安装 ASECLI wheel、检查 SGCLI 模块不可用,子进程 PATH 仅当前 venv,清除 PYTHONPATH,在临时工程运行版本、契约、实际 export-sg、非法 spec 拒绝及 CustomEditor 失败报告检查。CI 和 publish 的 package job 均运行该脚本。
|
|
53
|
+
- 本仓 AGENTS、ASECLI Skill 和已安装 `.agents/skills/asecli/SKILL.md` 同步单仓边界;不更新 SGCLI Skill、不修改对方仓库。跨仓静态回归改为禁止运行源码互相 import/固定开发目录和 CI 跨仓引用。
|
|
54
|
+
- 验证:相关测试 64 passed;CI governance 与 regression catalog 通过;独立 wheel 实测返回 `standalone_wheel=true`、`consumer_executed=false`;git diff --check 通过。隔离产物位于 `/tmp/asecli-independent-wheel.T0VXC8`。
|
|
55
|
+
- 此隔离 wheel 沿用当前工作树版本 0.8.2,仅用于候选测试,不是新版本正式发布,也没有替换本机 CLI。未启动 Editor,未提交/推送/发布。本轮移除的跨仓 YAML 是唯一删除的配置文件,可由 Git 历史恢复。
|
|
56
|
+
- 完成范围:AA-OPT-001/002/004/005 的 ASECLI 部分;AA-OPT-003 在 ASECLI 中的对方源码执行入口已移除。SGCLI 自有 CI、脚本与规则保持原样,其任务仍待独立执行,不能声明两个仓库都已解耦。
|
|
@@ -11,6 +11,9 @@ description: Create, modify, validate, and strictly lay out Amplify Shader Edito
|
|
|
11
11
|
|
|
12
12
|
## 与 SGCLI 的双向 JSON 直连
|
|
13
13
|
|
|
14
|
+
- 单仓维护:ASECLI 修改、检查、发布、安装不自动修改 SGCLI;对方缺能力时报告协议需求,由用户另行授权对方任务。
|
|
15
|
+
- 两 CLI 无运行代码依赖。用随包固定的公开 JSON Schema 自行验证,快照摘要不要求跟随对方 main。用户显式编排的端到端转换不是 ASECLI 开发或发布的前置条件。
|
|
16
|
+
|
|
14
17
|
- SG→ASE:`sgcli convert Graph.shadergraph --out-dir ./out` 生成裸 `Graph.sgcli-to-asecli.spec.json`、独立 report 和发布 receipt;`asecli create Assets/Graph.shader --spec ./out/Graph.sgcli-to-asecli.spec.json` 只直接消费 spec 原文件。
|
|
15
18
|
- ASE→SG:`asecli export-sg Graph.shader --out-dir ./out` 生成裸 `Graph.asecli-to-sgcli.spec.json`(`sgcli.native.v3`)、独立 report 和发布 receipt;SGCLI `sg create --spec` 只直接消费 spec 原文件。
|
|
16
19
|
- 不生成 `asecli.ase-graph.*` 中间 JSON,不调用 SGCLI,不使用 wrapper、`.graph` 解包、jq、Agent 改写或一次性 translator。
|
|
@@ -11,6 +11,9 @@ from .schema_validation import validate_schema
|
|
|
11
11
|
|
|
12
12
|
EDITOR_GRAPH_V3 = "contracts/editor-graph-spec.v3.schema.json"
|
|
13
13
|
SGCLI_NATIVE_V3_SNAPSHOT = "contracts/sgcli.native.v3.schema.json"
|
|
14
|
+
# Provenance of the bundled JSON document, not a runtime dependency or a
|
|
15
|
+
# requirement to match another repository's current checkout. The SHA pins
|
|
16
|
+
# this exact supported protocol revision independently of CLI releases.
|
|
14
17
|
SGCLI_NATIVE_CONSUMER = {
|
|
15
18
|
"package": "sgcli",
|
|
16
19
|
"version": "0.3.5",
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
"""Independent delivery must not require another CLI implementation."""
|
|
2
|
+
import ast
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
ROOT = Path(__file__).resolve().parents[1]
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_workflows_are_self_contained():
|
|
9
|
+
for path in (ROOT / '.github/workflows').glob('*.yml'):
|
|
10
|
+
text = path.read_text()
|
|
11
|
+
for forbidden in ('seeseeczl/SGCLI', 'SGCLI_CANDIDATE_SHA', 'SGCLI_READ_SSH_KEY',
|
|
12
|
+
'cross-cli', 'sgcli_ref', 'sgcli-wheel'):
|
|
13
|
+
assert forbidden not in text, (path, forbidden)
|
|
14
|
+
assert 'tools/independent_wheel_smoke.py' in text
|
|
15
|
+
publish = (ROOT / '.github/workflows/publish.yml').read_text()
|
|
16
|
+
assert ' publish:\n needs: package' in publish
|
|
17
|
+
assert 'name: asecli-candidate-${{ github.sha }}' in publish
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def foreign_imports(source):
|
|
21
|
+
tree = ast.parse(source)
|
|
22
|
+
return [name for node in ast.walk(tree)
|
|
23
|
+
for name in ([n.name for n in node.names] if isinstance(node, ast.Import)
|
|
24
|
+
else [node.module or ''] if isinstance(node, ast.ImportFrom) else [])
|
|
25
|
+
if name == 'sgcli' or name.startswith('sgcli.')]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def test_no_runtime_foreign_import_or_checkout_path():
|
|
29
|
+
for path in (ROOT / 'src/asecli').rglob('*.py'):
|
|
30
|
+
source = path.read_text()
|
|
31
|
+
assert not foreign_imports(source), path
|
|
32
|
+
for marker in ('GitHub/SGCLI', '../SGCLI', 'import_module("sgcli', "import_module('sgcli"):
|
|
33
|
+
assert marker not in source, (path, marker)
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def test_foreign_import_guard_detects_negative_examples():
|
|
37
|
+
assert foreign_imports('import sgcli as helper')
|
|
38
|
+
assert foreign_imports('from sgcli.contracts import native_contract')
|
|
39
|
+
assert not foreign_imports('from asecli.contracts import validate_sgcli_native_spec')
|
|
@@ -109,7 +109,7 @@ def test_publish_workflow_keeps_all_gates_before_oidc_publish():
|
|
|
109
109
|
)
|
|
110
110
|
for marker in required:
|
|
111
111
|
assert marker in workflow
|
|
112
|
-
assert workflow.index("needs:
|
|
112
|
+
assert workflow.index(" publish:\n needs: package") < workflow.index("id-token: write")
|
|
113
113
|
|
|
114
114
|
|
|
115
115
|
def test_governance_markdown_cells_preserve_escaped_pipes():
|
|
@@ -187,6 +187,7 @@ def main() -> int:
|
|
|
187
187
|
"tools/supply_chain_check.py", "shasum -a 256 -c SHA256SUMS",
|
|
188
188
|
"vars.ASECLI_PYPI_ENABLED == 'true'",
|
|
189
189
|
"uv publish dist/*.whl dist/*.tar.gz",
|
|
190
|
+
"tools/independent_wheel_smoke.py",
|
|
190
191
|
)
|
|
191
192
|
for marker in release_markers:
|
|
192
193
|
if marker not in publish:
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""Run with a venv containing ONLY the ASECLI wheel, outside both source trees."""
|
|
2
|
+
import hashlib
|
|
3
|
+
import importlib.util
|
|
4
|
+
import json
|
|
5
|
+
import os
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
import shutil
|
|
8
|
+
import subprocess
|
|
9
|
+
import sys
|
|
10
|
+
import tempfile
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def run(cli, root, *args, ok=True):
|
|
14
|
+
env = dict(os.environ, PATH=str(cli.parent))
|
|
15
|
+
env.pop('PYTHONPATH', None)
|
|
16
|
+
env.pop('PYTHONHOME', None)
|
|
17
|
+
process = subprocess.run([str(cli), *args], cwd=root, env=env,
|
|
18
|
+
capture_output=True, text=True, timeout=30)
|
|
19
|
+
value = json.loads(process.stdout)
|
|
20
|
+
assert value['ok'] is ok, value
|
|
21
|
+
assert process.returncode == (0 if ok else 2), process.stderr
|
|
22
|
+
return value.get('data') if ok else value['error']
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def shader_fixture():
|
|
26
|
+
from asecli.schema import schema_for
|
|
27
|
+
from asecli.export_sg import URP_UNLIT_GUID
|
|
28
|
+
scalar = ['Node', 'AmplifyShaderEditor.RangedFloatNode', '10', '-400,0', 'Float',
|
|
29
|
+
'False', *schema_for('AmplifyShaderEditor.RangedFloatNode')['fields']]
|
|
30
|
+
master = [
|
|
31
|
+
'Node', 'AmplifyShaderEditor.TemplateMultiPassMasterNode', '1', '0,0', 'Float', 'False',
|
|
32
|
+
'True', '-1', '2', 'UnityEditor.ShaderGraphUnlitGUI', '0', '1', 'Export Test',
|
|
33
|
+
URP_UNLIT_GUID, 'True', 'Forward', 'UniversalMaterialType=Unlit', 'RenderType=Opaque',
|
|
34
|
+
'Standard', '3', 'Surface', '0', '0', ' Blend', '0', '0', 'Two Sided', '1', '0',
|
|
35
|
+
'Forward Only', '0', '0', 'Cast Shadows', '1', '0', ' Use Shadow Threshold', '0', '0',
|
|
36
|
+
'Receive Shadows', '1', '0', 'GPU Instancing', '1', '0', 'LOD CrossFade', '0', '0',
|
|
37
|
+
'Built-in Fog', '1', '0', 'Extra Pre Pass', '0', '0', 'Tessellation', '0', '0',
|
|
38
|
+
]
|
|
39
|
+
return ('Shader "Independent/Test"\n{\nProperties\n{\n}\n'
|
|
40
|
+
'SubShader { Pass { Cull Back } }\n}\n/*ASEBEGIN\nVersion=19109\n'
|
|
41
|
+
+ ';'.join(scalar) + '\n' + ';'.join(master)
|
|
42
|
+
+ '\nWireConnection;1;2;10;0\nASEEND*/\n//CHKSM=TEST\n')
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def main():
|
|
46
|
+
assert importlib.util.find_spec('sgcli') is None, 'SGCLI must not be installed'
|
|
47
|
+
cli = Path(sys.executable).parent / ('asecli.exe' if os.name == 'nt' else 'asecli')
|
|
48
|
+
assert cli.is_file(), 'run using an isolated wheel installation'
|
|
49
|
+
assert shutil.which('sgcli', path=str(cli.parent)) is None
|
|
50
|
+
import asecli
|
|
51
|
+
assert Path(asecli.__file__).resolve().is_relative_to(Path(sys.prefix).resolve()), 'not a wheel installation'
|
|
52
|
+
from asecli.contracts import validate_sgcli_native_spec
|
|
53
|
+
from asecli.schema_validation import SchemaValidationError
|
|
54
|
+
with tempfile.TemporaryDirectory(prefix='asecli-independent-') as temporary:
|
|
55
|
+
root = Path(temporary).resolve()
|
|
56
|
+
(root / 'Assets').mkdir()
|
|
57
|
+
(root / 'ProjectSettings').mkdir()
|
|
58
|
+
source = root / 'Assets/control.shader'
|
|
59
|
+
source.write_text(shader_fixture(), encoding='utf-8')
|
|
60
|
+
run(cli, root, '--version')
|
|
61
|
+
run(cli, root, 'contract', 'editor-graph', '--version', '3')
|
|
62
|
+
result = run(cli, root, 'export-sg', str(source), '--out-dir', str(root / 'out'))
|
|
63
|
+
spec_path = Path(result['spec_json'])
|
|
64
|
+
spec = json.loads(spec_path.read_text())
|
|
65
|
+
validate_sgcli_native_spec(spec)
|
|
66
|
+
report = json.loads(Path(result['report_json']).read_text())
|
|
67
|
+
receipt = json.loads(Path(result['receipt_json']).read_text())
|
|
68
|
+
assert report['target']['sha256'] == hashlib.sha256(spec_path.read_bytes()).hexdigest()
|
|
69
|
+
assert receipt['complete'] and report['evidence']['consumer_loaded'] == 'not_run'
|
|
70
|
+
spec['unexpected'] = True
|
|
71
|
+
try:
|
|
72
|
+
validate_sgcli_native_spec(spec)
|
|
73
|
+
except SchemaValidationError:
|
|
74
|
+
pass
|
|
75
|
+
else:
|
|
76
|
+
raise AssertionError('unknown spec field was accepted')
|
|
77
|
+
invalid = root / 'invalid.json'
|
|
78
|
+
invalid.write_text('{"version":999}', encoding='utf-8')
|
|
79
|
+
run(cli, root, 'contract', 'editor-graph', '--version', '3', '--spec', str(invalid), ok=False)
|
|
80
|
+
source.write_text(shader_fixture().replace('UnityEditor.ShaderGraphUnlitGUI', 'Unknown.GUI'))
|
|
81
|
+
error = run(cli, root, 'export-sg', str(source), '--out-dir', str(root / 'blocked'), ok=False)
|
|
82
|
+
assert error['code'] == 'SG_EXPORT_BLOCKED'
|
|
83
|
+
assert len(list((root / 'blocked').glob('*.report.json'))) == 1
|
|
84
|
+
assert not list((root / 'blocked').glob('*.spec.json'))
|
|
85
|
+
assert not list((root / 'blocked').glob('*.receipt.json'))
|
|
86
|
+
print(json.dumps({'ok': True, 'standalone_wheel': True, 'consumer_executed': False}))
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
if __name__ == '__main__':
|
|
90
|
+
main()
|
|
@@ -8,7 +8,7 @@ resolution-markers = [
|
|
|
8
8
|
|
|
9
9
|
[[package]]
|
|
10
10
|
name = "asecli"
|
|
11
|
-
version = "0.8.
|
|
11
|
+
version = "0.8.3"
|
|
12
12
|
source = { editable = "." }
|
|
13
13
|
|
|
14
14
|
[package.dev-dependencies]
|
|
@@ -50,7 +50,7 @@ name = "exceptiongroup"
|
|
|
50
50
|
version = "1.3.1"
|
|
51
51
|
source = { registry = "https://pypi.org/simple" }
|
|
52
52
|
dependencies = [
|
|
53
|
-
{ name = "typing-extensions", marker = "python_full_version < '3.
|
|
53
|
+
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
|
54
54
|
]
|
|
55
55
|
sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" }
|
|
56
56
|
wheels = [
|