graph-agents-cli 0.3.1__py3-none-any.whl
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.
- graph_agents_cli/__init__.py +26 -0
- graph_agents_cli/_api_policy.py +2145 -0
- graph_agents_cli/_approvals.py +400 -0
- graph_agents_cli/_build.py +186 -0
- graph_agents_cli/_build_info.json +7 -0
- graph_agents_cli/_chat_client.py +462 -0
- graph_agents_cli/_click.py +157 -0
- graph_agents_cli/_defaults.py +139 -0
- graph_agents_cli/_experiments.py +64 -0
- graph_agents_cli/_http.py +192 -0
- graph_agents_cli/_output.py +83 -0
- graph_agents_cli/_project.py +462 -0
- graph_agents_cli/_remote.py +220 -0
- graph_agents_cli/_response_schema.py +264 -0
- graph_agents_cli/_runner.py +319 -0
- graph_agents_cli/_skills_check.py +274 -0
- graph_agents_cli/_tools.py +189 -0
- graph_agents_cli/_trust.py +66 -0
- graph_agents_cli/api/__init__.py +15 -0
- graph_agents_cli/api/_changes.py +506 -0
- graph_agents_cli/api/_files.py +658 -0
- graph_agents_cli/api/cmd_api.py +2480 -0
- graph_agents_cli/deploy/__init__.py +15 -0
- graph_agents_cli/deploy/_config.py +171 -0
- graph_agents_cli/deploy/_image.py +128 -0
- graph_agents_cli/deploy/_kube.py +286 -0
- graph_agents_cli/deploy/_modes.py +234 -0
- graph_agents_cli/deploy/_preflight.py +370 -0
- graph_agents_cli/deploy/_values.py +168 -0
- graph_agents_cli/deploy/cmd_deploy.py +1866 -0
- graph_agents_cli/deploy/gitops.py +562 -0
- graph_agents_cli/deploy/local_load.py +273 -0
- graph_agents_cli/dev/__init__.py +13 -0
- graph_agents_cli/dev/cmd_build.py +131 -0
- graph_agents_cli/dev/cmd_install.py +78 -0
- graph_agents_cli/dev/cmd_lint.py +119 -0
- graph_agents_cli/dev/cmd_playground.py +297 -0
- graph_agents_cli/dev/policy_check.py +1287 -0
- graph_agents_cli/eval/__init__.py +22 -0
- graph_agents_cli/eval/_client.py +670 -0
- graph_agents_cli/eval/_common.py +177 -0
- graph_agents_cli/eval/_judge.py +168 -0
- graph_agents_cli/eval/_judge_runner.py +238 -0
- graph_agents_cli/eval/_paths.py +212 -0
- graph_agents_cli/eval/checks.py +581 -0
- graph_agents_cli/eval/cmd_analyze.py +278 -0
- graph_agents_cli/eval/cmd_compare.py +284 -0
- graph_agents_cli/eval/cmd_eval_group.py +80 -0
- graph_agents_cli/eval/cmd_generate.py +558 -0
- graph_agents_cli/eval/cmd_grade.py +466 -0
- graph_agents_cli/eval/cmd_metric.py +156 -0
- graph_agents_cli/eval/cmd_run.py +370 -0
- graph_agents_cli/eval/cmd_submit.py +400 -0
- graph_agents_cli/eval/config.py +435 -0
- graph_agents_cli/eval/dataset.py +350 -0
- graph_agents_cli/eval/gate.py +420 -0
- graph_agents_cli/eval/transcript.py +192 -0
- graph_agents_cli/extension/__init__.py +13 -0
- graph_agents_cli/extension/_compat.py +86 -0
- graph_agents_cli/extension/_loader.py +293 -0
- graph_agents_cli/extension/_manifest.py +135 -0
- graph_agents_cli/extension/_overrides.py +195 -0
- graph_agents_cli/extension/_paths.py +91 -0
- graph_agents_cli/extension/_refs.py +193 -0
- graph_agents_cli/extension/_resolver.py +453 -0
- graph_agents_cli/extension/_schema.py +106 -0
- graph_agents_cli/extension/_spec.py +253 -0
- graph_agents_cli/extension/_sync.py +102 -0
- graph_agents_cli/extension/_trust.py +58 -0
- graph_agents_cli/extension/cmd_extension_add.py +259 -0
- graph_agents_cli/extension/cmd_extension_group.py +57 -0
- graph_agents_cli/extension/cmd_extension_list.py +56 -0
- graph_agents_cli/extension/cmd_extension_remove.py +61 -0
- graph_agents_cli/extension/cmd_extension_update.py +195 -0
- graph_agents_cli/info/__init__.py +13 -0
- graph_agents_cli/info/cmd_info.py +222 -0
- graph_agents_cli/infra/__init__.py +15 -0
- graph_agents_cli/infra/checks.py +1169 -0
- graph_agents_cli/infra/cmd_infra.py +103 -0
- graph_agents_cli/main.py +591 -0
- graph_agents_cli/peer/__init__.py +15 -0
- graph_agents_cli/peer/_generate.py +254 -0
- graph_agents_cli/peer/cmd_peer.py +1151 -0
- graph_agents_cli/run/__init__.py +13 -0
- graph_agents_cli/run/_local_server.py +1157 -0
- graph_agents_cli/run/_signals.py +141 -0
- graph_agents_cli/run/cmd_approvals.py +530 -0
- graph_agents_cli/run/cmd_run.py +1421 -0
- graph_agents_cli/scaffold/__init__.py +19 -0
- graph_agents_cli/scaffold/agents/README.md +24 -0
- graph_agents_cli/scaffold/agents/empty_py/.template/templateconfig.yaml +22 -0
- graph_agents_cli/scaffold/agents/langgraph/.env.example +292 -0
- graph_agents_cli/scaffold/agents/langgraph/.template/templateconfig.yaml +28 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile +59 -0
- graph_agents_cli/scaffold/agents/langgraph/Dockerfile.langgraph-server +59 -0
- graph_agents_cli/scaffold/agents/langgraph/README.md +571 -0
- graph_agents_cli/scaffold/agents/langgraph/api-policy.yaml +60 -0
- graph_agents_cli/scaffold/agents/langgraph/app/__init__.py +20 -0
- graph_agents_cli/scaffold/agents/langgraph/app/agent.py +174 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/__init__.py +15 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a.py +2162 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/a2a_client.py +1167 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/api_client.py +4220 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/approvals.py +1349 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/auth.py +1986 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/chat.py +2962 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/checkpointer.py +432 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/content.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/db.py +580 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/limits.py +203 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/metrics.py +231 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/middleware.py +361 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/model.py +611 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/playground.py +230 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/run_locks.py +459 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/structured.py +755 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/telemetry.py +681 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/threads.py +493 -0
- graph_agents_cli/scaffold/agents/langgraph/app/app_utils/token_exchange.py +959 -0
- graph_agents_cli/scaffold/agents/langgraph/app/fast_api_app.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/__init__.py +55 -0
- graph_agents_cli/scaffold/agents/langgraph/app/policies/custom.py +97 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/__init__.py +46 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/example_api.py +92 -0
- graph_agents_cli/scaffold/agents/langgraph/app/tools/weather.py +33 -0
- graph_agents_cli/scaffold/agents/langgraph/langgraph.json +14 -0
- graph_agents_cli/scaffold/agents/langgraph/pyproject.toml +78 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/conftest.py +376 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/datasets/basic-dataset.json +53 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/eval/eval_config.yaml +32 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/approval_graph.py +137 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_issuer.py +216 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/fake_openai.py +357 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_outcomes.py +569 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_a2a_relay.py +479 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_api_surface.py +812 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals.py +1367 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_approvals_server.py +794 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor.py +497 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_cross_actor_server.py +247 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_history_repair.py +278 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_model_apis.py +242 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_postgres.py +637 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_resilience_postgres.py +770 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_runtime_guardrails.py +854 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_e2e.py +340 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_server_runtime.py +989 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_answers.py +584 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_structured_server.py +222 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/integration/test_token_exchange_issuer.py +650 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/.results/.placeholder +0 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/README.md +22 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/conftest.py +21 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/load_test/load_test.py +81 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_client.py +824 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_a2a_scoping.py +724 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client.py +1214 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_client_hardening.py +716 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_api_policy_rpc.py +767 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_approval_ledger.py +1536 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_fake_model.py +115 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_jwt_policy.py +991 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_limits.py +310 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging.py +148 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_logging_hardening.py +271 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_policy.py +378 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_resilience.py +610 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_server_auth.py +702 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_structured.py +673 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_telemetry.py +404 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_thread_listing.py +255 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_threads.py +268 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_token_exchange.py +1320 -0
- graph_agents_cli/scaffold/agents/langgraph/tests/unit/test_untrusted_content.py +393 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-fastapi.lock +2084 -0
- graph_agents_cli/scaffold/agents/langgraph/uv-langgraph-server.lock +2106 -0
- graph_agents_cli/scaffold/agents/langgraph/{{cookiecutter.agent_guidance_filename}} +129 -0
- graph_agents_cli/scaffold/base_templates/_shared/graph-agents-cli-manifest.yaml +36 -0
- graph_agents_cli/scaffold/base_templates/python/.dockerignore +32 -0
- graph_agents_cli/scaffold/base_templates/python/.github/CODEOWNERS +30 -0
- graph_agents_cli/scaffold/base_templates/python/.github/agent.env +7 -0
- graph_agents_cli/scaffold/base_templates/python/.github/workflows/pr_checks.yaml +214 -0
- graph_agents_cli/scaffold/base_templates/python/.gitignore +209 -0
- graph_agents_cli/scaffold/base_templates/python/tests/unit/test_dummy.py +23 -0
- graph_agents_cli/scaffold/base_templates/python/{{cookiecutter.agent_guidance_filename}} +35 -0
- graph_agents_cli/scaffold/cmd_scaffold_group.py +49 -0
- graph_agents_cli/scaffold/commands/__init__.py +13 -0
- graph_agents_cli/scaffold/commands/create.py +1424 -0
- graph_agents_cli/scaffold/commands/enhance.py +1652 -0
- graph_agents_cli/scaffold/commands/upgrade.py +570 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/agent.env +12 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/promote-to-prod.yaml +371 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/.github/workflows/staging.yaml +450 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-dev.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-prod.yaml +41 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/argocd/application-staging.yaml +43 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/.helmignore +14 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/Chart.yaml +21 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/examples/networkpolicy.yaml +103 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/NOTES.txt +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/_helpers.tpl +189 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/certificate.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/configmap.yaml +10 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/deployment.yaml +199 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/hpa.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/httproute.yaml +30 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/ingress.yaml +39 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/networkpolicy.yaml +48 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/pdb.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/postgresql-secret.yaml +37 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/service.yaml +15 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/serviceaccount.yaml +13 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/templates/servicemonitor.yaml +42 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-dev.yaml +22 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-prod.yaml +45 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values-staging.yaml +29 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/deployment/helm/{{cookiecutter.project_name}}/values.yaml +396 -0
- graph_agents_cli/scaffold/deployment_targets/kubernetes/python/tests/integration/test_chart.py +269 -0
- graph_agents_cli/scaffold/deployment_targets/none/README.md +5 -0
- graph_agents_cli/scaffold/deployment_targets/none/python/README.md +6 -0
- graph_agents_cli/scaffold/utils/__init__.py +13 -0
- graph_agents_cli/scaffold/utils/backup.py +212 -0
- graph_agents_cli/scaffold/utils/build_record.py +257 -0
- graph_agents_cli/scaffold/utils/cli_options.py +184 -0
- graph_agents_cli/scaffold/utils/fs.py +83 -0
- graph_agents_cli/scaffold/utils/generate_locks.py +214 -0
- graph_agents_cli/scaffold/utils/generation_metadata.py +88 -0
- graph_agents_cli/scaffold/utils/keyedit.py +768 -0
- graph_agents_cli/scaffold/utils/keymerge.py +537 -0
- graph_agents_cli/scaffold/utils/language.py +138 -0
- graph_agents_cli/scaffold/utils/lock_utils.py +94 -0
- graph_agents_cli/scaffold/utils/logging.py +77 -0
- graph_agents_cli/scaffold/utils/manifest.py +292 -0
- graph_agents_cli/scaffold/utils/merge.py +970 -0
- graph_agents_cli/scaffold/utils/merge3.py +216 -0
- graph_agents_cli/scaffold/utils/openapi_seed.py +199 -0
- graph_agents_cli/scaffold/utils/remote_template.py +376 -0
- graph_agents_cli/scaffold/utils/template.py +1352 -0
- graph_agents_cli/scaffold/utils/upgrade.py +894 -0
- graph_agents_cli/scaffold/utils/version.py +438 -0
- graph_agents_cli/secrets/__init__.py +15 -0
- graph_agents_cli/secrets/_apply.py +954 -0
- graph_agents_cli/secrets/_required.py +188 -0
- graph_agents_cli/secrets/cmd_secrets.py +211 -0
- graph_agents_cli/setup/__init__.py +13 -0
- graph_agents_cli/setup/_antigravity.py +221 -0
- graph_agents_cli/setup/cmd_auth.py +1030 -0
- graph_agents_cli/setup/cmd_dev_token.py +513 -0
- graph_agents_cli/setup/cmd_setup.py +428 -0
- graph_agents_cli/setup/cmd_update.py +140 -0
- graph_agents_cli/skills/__init__.py +13 -0
- graph_agents_cli/skills/_bundle.py +65 -0
- graph_agents_cli/skills/data/README.md +19 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/SKILL.md +357 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/github-settings.md +113 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/gitops.md +137 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/kubernetes.md +315 -0
- graph_agents_cli/skills/data/graph-agents-cli-deploy/references/secrets.md +160 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/SKILL.md +303 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/dataset_schema.md +282 -0
- graph_agents_cli/skills/data/graph-agents-cli-eval/references/metrics-guide.md +143 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/SKILL.md +659 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langchain-models.md +124 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/langgraph.md +235 -0
- graph_agents_cli/skills/data/graph-agents-cli-langgraph-code/references/template-contract.md +477 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/SKILL.md +231 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/langsmith.md +46 -0
- graph_agents_cli/skills/data/graph-agents-cli-observability/references/otel.md +59 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/SKILL.md +414 -0
- graph_agents_cli/skills/data/graph-agents-cli-scaffold/references/flags.md +134 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/SKILL.md +478 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/brainstorming.md +118 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/commands.md +419 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/extension.md +156 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/internals.md +67 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/spec-template.md +56 -0
- graph_agents_cli/skills/data/graph-agents-cli-workflow/references/terminology.md +119 -0
- graph_agents_cli/system/__init__.py +15 -0
- graph_agents_cli/system/_apply.py +519 -0
- graph_agents_cli/system/_checks.py +1023 -0
- graph_agents_cli/system/_deploy.py +215 -0
- graph_agents_cli/system/_model.py +363 -0
- graph_agents_cli/system/_system.py +664 -0
- graph_agents_cli/system/_views.py +208 -0
- graph_agents_cli/system/cmd_system.py +423 -0
- graph_agents_cli-0.3.1.dist-info/METADATA +162 -0
- graph_agents_cli-0.3.1.dist-info/RECORD +291 -0
- graph_agents_cli-0.3.1.dist-info/WHEEL +4 -0
- graph_agents_cli-0.3.1.dist-info/entry_points.txt +2 -0
- graph_agents_cli-0.3.1.dist-info/licenses/LICENSE +201 -0
- graph_agents_cli-0.3.1.dist-info/licenses/NOTICE +19 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
# Copyright 2026 Google LLC
|
|
2
|
+
# Modifications Copyright 2026 graph-agents-cli contributors
|
|
3
|
+
#
|
|
4
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
# you may not use this file except in compliance with the License.
|
|
6
|
+
# You may obtain a copy of the License at
|
|
7
|
+
#
|
|
8
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
#
|
|
10
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
# See the License for the specific language governing permissions and
|
|
14
|
+
# limitations under the License.
|
|
15
|
+
|
|
16
|
+
"""Upgrade command for upgrading existing projects to newer graph-agents-cli builds.
|
|
17
|
+
|
|
18
|
+
The old snapshot of the three-way merge is rendered by the build that created
|
|
19
|
+
the project. Which build that is comes from the manifest: ``cli_version`` (a
|
|
20
|
+
release, fetched from its ``v<version>`` tag) and, since builds between two
|
|
21
|
+
releases share that version, ``cli_build`` (the build id, its commit and a
|
|
22
|
+
digest of what it renders; see ``scaffold.utils.build_record``). A project
|
|
23
|
+
whose manifest predates ``cli_build`` is compared by version only, and
|
|
24
|
+
``--baseline-ref`` names its build explicitly.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
import logging
|
|
28
|
+
import os
|
|
29
|
+
import pathlib
|
|
30
|
+
import tempfile
|
|
31
|
+
|
|
32
|
+
import click
|
|
33
|
+
from rich.markup import escape
|
|
34
|
+
|
|
35
|
+
from graph_agents_cli import _api_policy, _tools
|
|
36
|
+
from graph_agents_cli._output import Console
|
|
37
|
+
from graph_agents_cli._project import (
|
|
38
|
+
MANIFEST_FILENAME,
|
|
39
|
+
ManifestError,
|
|
40
|
+
NotInProjectError,
|
|
41
|
+
ProjectConfig,
|
|
42
|
+
find_project_config,
|
|
43
|
+
find_project_root,
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
from ..utils.backup import make_backup_pre_apply_hook
|
|
47
|
+
from ..utils.build_record import (
|
|
48
|
+
MANIFEST_KEY,
|
|
49
|
+
BuildRecord,
|
|
50
|
+
MalformedRecordError,
|
|
51
|
+
parse_build_record,
|
|
52
|
+
read_manifest_data,
|
|
53
|
+
recorded_build_for,
|
|
54
|
+
running_build,
|
|
55
|
+
template_digest,
|
|
56
|
+
write_build_record,
|
|
57
|
+
)
|
|
58
|
+
from ..utils.generation_metadata import metadata_to_cli_args
|
|
59
|
+
from ..utils.merge import is_fetchable_version, run_create_command, run_three_way_merge
|
|
60
|
+
from ..utils.upgrade import compare_all_files, update_cli_metadata
|
|
61
|
+
from ..utils.version import (
|
|
62
|
+
INSTALL_SPEC_ENV,
|
|
63
|
+
PACKAGE_NAME,
|
|
64
|
+
REPO_URL,
|
|
65
|
+
BaselineSource,
|
|
66
|
+
InstallSpecError,
|
|
67
|
+
commit_install_spec,
|
|
68
|
+
get_current_version,
|
|
69
|
+
pinned_install_spec,
|
|
70
|
+
pinned_spec_unavailable,
|
|
71
|
+
resolve_baseline_ref,
|
|
72
|
+
)
|
|
73
|
+
|
|
74
|
+
console = Console()
|
|
75
|
+
|
|
76
|
+
# The CLI-wide scheme: 0 ok, 1 refused or failed gate, 2 tool failure (uvx
|
|
77
|
+
# missing, or it could not fetch and run the prior build), 3 configuration
|
|
78
|
+
# error (the manifest's cli_version or cli_build, the install-spec override,
|
|
79
|
+
# a --baseline-ref that names no build or another version).
|
|
80
|
+
EXIT_TOOL_FAILURE = 2
|
|
81
|
+
_BASELINE_CURRENT_HINT = (
|
|
82
|
+
"Nothing was changed. `--baseline current` compares against the current templates "
|
|
83
|
+
"instead, but it cannot tell your edits from the template's own changes since then."
|
|
84
|
+
)
|
|
85
|
+
_BASELINE_REF_FORMS = (
|
|
86
|
+
f"a commit or tag of {REPO_URL}, <clone>@<commit> for a local clone, a path to a "
|
|
87
|
+
"checkout, or a full install spec (git+https://<mirror>@<commit>)"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class BaselineError(click.ClickException):
|
|
92
|
+
"""The build that created the project cannot be named or built as asked (exit 3)."""
|
|
93
|
+
|
|
94
|
+
exit_code = 3
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def _display_version_header(old_label: str, new_label: str, baseline_label: str | None) -> None:
|
|
98
|
+
"""Display the upgrade version header."""
|
|
99
|
+
console.print()
|
|
100
|
+
console.print(f"[bold blue]📦 Upgrading {escape(old_label)} → {escape(new_label)}[/bold blue]")
|
|
101
|
+
if baseline_label:
|
|
102
|
+
console.print(f"[dim]Baseline: {escape(baseline_label)}[/dim]")
|
|
103
|
+
console.print()
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def _build_label(version: str, build_id: str | None) -> str:
|
|
107
|
+
return f"{version} (build {build_id})" if build_id and build_id != version else version
|
|
108
|
+
|
|
109
|
+
|
|
110
|
+
def _snapshot_digest(cli_args: list[str], project_name: str) -> str:
|
|
111
|
+
"""The digest of what this build renders from the manifest's settings."""
|
|
112
|
+
with tempfile.TemporaryDirectory(prefix="gacli_upgrade_check_") as tmp:
|
|
113
|
+
out = pathlib.Path(tmp)
|
|
114
|
+
if not run_create_command(cli_args, out, project_name):
|
|
115
|
+
console.print(
|
|
116
|
+
"[bold red]Error:[/bold red] Could not render this CLI's templates to compare "
|
|
117
|
+
"with the project's build; nothing was changed (rerun with --debug)."
|
|
118
|
+
)
|
|
119
|
+
raise SystemExit(EXIT_TOOL_FAILURE)
|
|
120
|
+
return template_digest(out / project_name)
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def _print_unrecorded_build(metadata: ProjectConfig, version: str, current_id: str) -> None:
|
|
124
|
+
"""The same-version answer for a manifest without ``cli_build``: compared by version only."""
|
|
125
|
+
console.print(f"[bold green]✅[/bold green] Project is already at version {version}.")
|
|
126
|
+
console.print(
|
|
127
|
+
f"[dim] Compared by version only: {MANIFEST_FILENAME} records no build "
|
|
128
|
+
f"({MANIFEST_KEY}), so the project may come from an earlier {version} build whose "
|
|
129
|
+
f"templates differ from this one ({current_id}). To upgrade from the build that "
|
|
130
|
+
"created it, name that build:[/dim]"
|
|
131
|
+
)
|
|
132
|
+
console.print(
|
|
133
|
+
"[dim] graph-agents-cli scaffold upgrade --baseline-ref <ref> --dry-run[/dim]"
|
|
134
|
+
)
|
|
135
|
+
console.print(f"[dim] <ref>: {_BASELINE_REF_FORMS}.[/dim]")
|
|
136
|
+
if metadata.generated_at:
|
|
137
|
+
console.print(
|
|
138
|
+
"[dim] Not sure which commit? A first candidate is the newest one before the "
|
|
139
|
+
f"project was generated (generated_at {metadata.generated_at}):[/dim]"
|
|
140
|
+
)
|
|
141
|
+
console.print(
|
|
142
|
+
f"[dim] git -C <clone> log -1 --format=%H --before='{metadata.generated_at}'[/dim]"
|
|
143
|
+
)
|
|
144
|
+
console.print(
|
|
145
|
+
"[dim] The build may be older than that (a checkout behind its branch, or a "
|
|
146
|
+
"cached build). Check with --dry-run: with the right build, only files you "
|
|
147
|
+
"edited are listed under 'Will preserve' or as conflicts.[/dim]"
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# A named baseline whose snapshot differs from the project in more scaffolding
|
|
152
|
+
# files than this, where the new templates keep the baseline's content, is
|
|
153
|
+
# probably not the build that created the project.
|
|
154
|
+
_SUSPECT_MIN_FILES = 5
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def _warn_if_not_the_projects_build(
|
|
158
|
+
project_dir: pathlib.Path,
|
|
159
|
+
old_dir: pathlib.Path,
|
|
160
|
+
new_dir: pathlib.Path,
|
|
161
|
+
agent_directory: str,
|
|
162
|
+
) -> None:
|
|
163
|
+
"""Warn when a ``--baseline-ref`` build looks like the wrong one.
|
|
164
|
+
|
|
165
|
+
With the build that created the project, the scaffolding files listed as
|
|
166
|
+
"you modified, template unchanged" are the ones the developer edited. A
|
|
167
|
+
later build as the baseline puts most untouched files there instead (the
|
|
168
|
+
project still has the older content, and the baseline and the new templates
|
|
169
|
+
agree), and the upgrade would silently keep that older content.
|
|
170
|
+
"""
|
|
171
|
+
results = [
|
|
172
|
+
r
|
|
173
|
+
for r in compare_all_files(project_dir, old_dir, new_dir, agent_directory)
|
|
174
|
+
if r.category == "scaffolding"
|
|
175
|
+
]
|
|
176
|
+
kept = [r.path for r in results if r.preserve_type == "gacli_unchanged"]
|
|
177
|
+
compared = kept + [
|
|
178
|
+
r.path
|
|
179
|
+
for r in results
|
|
180
|
+
if r.action in ("auto_update", "conflict", "merge") or r.preserve_type == "already_current"
|
|
181
|
+
]
|
|
182
|
+
if len(kept) < _SUSPECT_MIN_FILES or len(kept) * 2 <= len(compared):
|
|
183
|
+
return
|
|
184
|
+
sample = ", ".join(kept[:4]) + (", ..." if len(kept) > 4 else "")
|
|
185
|
+
console.print(
|
|
186
|
+
f"[yellow]⚠️ {len(kept)} of {len(compared)} template files differ from this "
|
|
187
|
+
f"baseline where the new templates keep its content ({escape(sample)}), so they would "
|
|
188
|
+
"keep what they have now (listed as 'you modified, template unchanged'). With the "
|
|
189
|
+
"build that created the project, only files you edited are listed there: if you did "
|
|
190
|
+
"not edit these, the baseline is not that build (a later one?); try an earlier "
|
|
191
|
+
"commit.[/yellow]"
|
|
192
|
+
)
|
|
193
|
+
|
|
194
|
+
|
|
195
|
+
def _recorded_build_source(
|
|
196
|
+
recorded: BuildRecord | None, *, same_version: bool
|
|
197
|
+
) -> BaselineSource | None:
|
|
198
|
+
"""The baseline the recorded build implies; None means the ``cli_version`` release.
|
|
199
|
+
|
|
200
|
+
A release build and a build of unknown source (no commit) are rendered from
|
|
201
|
+
the version's release, except that an unknown build of the running version
|
|
202
|
+
cannot be told from it and is refused. Any other build is its commit in the
|
|
203
|
+
default repository; one with uncommitted changes has no commit that
|
|
204
|
+
reproduces it, and an install-spec override (a mirror) can only name
|
|
205
|
+
releases: both are refused with the ways out.
|
|
206
|
+
"""
|
|
207
|
+
if recorded is None or recorded.is_release:
|
|
208
|
+
return None
|
|
209
|
+
if recorded.commit is None:
|
|
210
|
+
if not same_version:
|
|
211
|
+
return None
|
|
212
|
+
raise BaselineError(
|
|
213
|
+
f"The project was rendered by build {recorded.id} of unknown source (no commit "
|
|
214
|
+
f"recorded) and its files differ from what this build renders. Name that build "
|
|
215
|
+
f"with --baseline-ref: {_BASELINE_REF_FORMS}. Nothing was changed."
|
|
216
|
+
)
|
|
217
|
+
if recorded.dirty:
|
|
218
|
+
raise BaselineError(
|
|
219
|
+
f"The project was rendered by build {recorded.id}, which had uncommitted changes: "
|
|
220
|
+
"no commit reproduces its templates, so an authentic baseline cannot be built. "
|
|
221
|
+
f"Name the closest build with --baseline-ref (the commit it was built on is "
|
|
222
|
+
f"{recorded.commit[:12]}). Nothing was changed."
|
|
223
|
+
)
|
|
224
|
+
if os.environ.get(INSTALL_SPEC_ENV, "").strip():
|
|
225
|
+
raise BaselineError(
|
|
226
|
+
f"The project was rendered by build {recorded.id} (commit {recorded.commit[:12]}), "
|
|
227
|
+
f"a build between releases, and {INSTALL_SPEC_ENV} is set: its {{version}} names "
|
|
228
|
+
"releases only, so it cannot fetch that commit. Name the build with "
|
|
229
|
+
f"--baseline-ref: git+https://<mirror>@{recorded.commit}, "
|
|
230
|
+
f"<clone>@{recorded.commit[:12]} or a checkout at that commit. Nothing was changed."
|
|
231
|
+
)
|
|
232
|
+
return BaselineSource(
|
|
233
|
+
spec=commit_install_spec(recorded.commit),
|
|
234
|
+
label=f"build {recorded.id}, commit {recorded.commit[:12]} of {REPO_URL}",
|
|
235
|
+
commit=recorded.commit,
|
|
236
|
+
)
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
def _release_source(version: str) -> BaselineSource:
|
|
240
|
+
"""The ``v<version>`` release as an explicit source (for a same-version upgrade)."""
|
|
241
|
+
if not is_fetchable_version(version):
|
|
242
|
+
raise ManifestError(
|
|
243
|
+
f"cli_version {version!r} in {MANIFEST_FILENAME} is not a released "
|
|
244
|
+
f"{PACKAGE_NAME} version, so its templates cannot be rebuilt.\n"
|
|
245
|
+
f" {_BASELINE_CURRENT_HINT}"
|
|
246
|
+
)
|
|
247
|
+
spec = pinned_install_spec(version)
|
|
248
|
+
if spec is None:
|
|
249
|
+
raise InstallSpecError(f"{pinned_spec_unavailable(version)}.\n {_BASELINE_CURRENT_HINT}")
|
|
250
|
+
return BaselineSource(spec=spec, label=f"the {version} release ({spec})")
|
|
251
|
+
|
|
252
|
+
|
|
253
|
+
@click.command()
|
|
254
|
+
@click.argument(
|
|
255
|
+
"project_path",
|
|
256
|
+
type=click.Path(exists=True, path_type=pathlib.Path),
|
|
257
|
+
default=".",
|
|
258
|
+
required=False,
|
|
259
|
+
)
|
|
260
|
+
@click.option(
|
|
261
|
+
"--dry-run",
|
|
262
|
+
"--dryrun",
|
|
263
|
+
is_flag=True,
|
|
264
|
+
help="Preview changes without applying them",
|
|
265
|
+
)
|
|
266
|
+
@click.option(
|
|
267
|
+
"--auto-approve",
|
|
268
|
+
"--yes",
|
|
269
|
+
"-y",
|
|
270
|
+
is_flag=True,
|
|
271
|
+
help="Auto-apply non-conflicting changes without prompts",
|
|
272
|
+
)
|
|
273
|
+
@click.option(
|
|
274
|
+
"--interactive",
|
|
275
|
+
"-i",
|
|
276
|
+
is_flag=True,
|
|
277
|
+
default=False,
|
|
278
|
+
help="Enable interactive prompts for human use",
|
|
279
|
+
)
|
|
280
|
+
@click.option(
|
|
281
|
+
"--baseline",
|
|
282
|
+
type=click.Choice(["authentic", "current"]),
|
|
283
|
+
default="authentic",
|
|
284
|
+
show_default=True,
|
|
285
|
+
help=(
|
|
286
|
+
"Which templates render the old snapshot: 'authentic' runs the exact build that "
|
|
287
|
+
"created the project through uvx and stops if it cannot; 'current' is an explicit "
|
|
288
|
+
"opt-in to compare against the current templates instead"
|
|
289
|
+
),
|
|
290
|
+
)
|
|
291
|
+
@click.option(
|
|
292
|
+
"--baseline-ref",
|
|
293
|
+
metavar="REF",
|
|
294
|
+
default=None,
|
|
295
|
+
help=(
|
|
296
|
+
"The build that created the project, when the manifest cannot name it (a project "
|
|
297
|
+
"from a build between releases, or a missing release tag): a commit or tag of the "
|
|
298
|
+
"repository, <clone>@<commit> for a local clone, a path to a checkout or wheel, "
|
|
299
|
+
"or a full install spec. Also upgrades a project of this same version."
|
|
300
|
+
),
|
|
301
|
+
)
|
|
302
|
+
@click.option(
|
|
303
|
+
"--debug",
|
|
304
|
+
is_flag=True,
|
|
305
|
+
help="Enable debug logging",
|
|
306
|
+
)
|
|
307
|
+
def upgrade(
|
|
308
|
+
project_path: pathlib.Path,
|
|
309
|
+
dry_run: bool,
|
|
310
|
+
auto_approve: bool,
|
|
311
|
+
interactive: bool,
|
|
312
|
+
baseline: str,
|
|
313
|
+
baseline_ref: str | None,
|
|
314
|
+
debug: bool,
|
|
315
|
+
) -> None:
|
|
316
|
+
"""Upgrade project to a newer graph-agents-cli version.
|
|
317
|
+
|
|
318
|
+
Applies a 3-way merge between the old template, the new template, and your
|
|
319
|
+
project: unmodified files are auto-updated, your customizations are preserved,
|
|
320
|
+
and conflicts are surfaced for manual resolution (with --interactive) or kept as-is.
|
|
321
|
+
|
|
322
|
+
The old template is regenerated by the exact CLI build that scaffolded the
|
|
323
|
+
project: its release, or the commit the manifest records for a build between
|
|
324
|
+
releases (--baseline-ref names it when the manifest cannot). If that build
|
|
325
|
+
cannot be fetched and run, the upgrade stops with no changes; pass --baseline
|
|
326
|
+
current to compare against the current templates instead (the summary is
|
|
327
|
+
labelled accordingly).
|
|
328
|
+
"""
|
|
329
|
+
if debug:
|
|
330
|
+
logging.basicConfig(level=logging.DEBUG, force=True)
|
|
331
|
+
console.print("[dim]Debug mode enabled[/dim]")
|
|
332
|
+
if baseline_ref is not None and baseline == "current":
|
|
333
|
+
raise click.UsageError(
|
|
334
|
+
"--baseline-ref names the build to compare against; it cannot be combined "
|
|
335
|
+
"with --baseline current."
|
|
336
|
+
)
|
|
337
|
+
|
|
338
|
+
project_dir = project_path.resolve()
|
|
339
|
+
project_root_dir = find_project_root(project_dir)
|
|
340
|
+
if project_root_dir is not None:
|
|
341
|
+
project_dir = project_root_dir
|
|
342
|
+
console.print(f"[dim]Resolved project root to: {project_dir}[/dim]")
|
|
343
|
+
|
|
344
|
+
metadata = find_project_config(project_dir)
|
|
345
|
+
if not metadata:
|
|
346
|
+
# A configuration error (exit 3), like every other command outside a project.
|
|
347
|
+
raise NotInProjectError(
|
|
348
|
+
f"No {MANIFEST_FILENAME} found in {project_dir} or its parents.\n"
|
|
349
|
+
" Run scaffold upgrade from a project graph-agents-cli created, or pass its path."
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
# The retired product API policy must be migrated first: an upgrade would
|
|
353
|
+
# otherwise re-render the project without it.
|
|
354
|
+
_api_policy.ensure_no_legacy_api_policy(project_dir)
|
|
355
|
+
|
|
356
|
+
language = metadata.language
|
|
357
|
+
|
|
358
|
+
old_version = metadata.cli_version
|
|
359
|
+
if not old_version:
|
|
360
|
+
raise ManifestError(
|
|
361
|
+
f"No cli_version found in {MANIFEST_FILENAME}.\n"
|
|
362
|
+
" It records the graph-agents-cli version that created the project, which "
|
|
363
|
+
"upgrade needs to rebuild that version's templates; set it (for example "
|
|
364
|
+
"cli_version: '0.1.0')."
|
|
365
|
+
)
|
|
366
|
+
|
|
367
|
+
new_version = get_current_version()
|
|
368
|
+
current = running_build()
|
|
369
|
+
try:
|
|
370
|
+
recorded = recorded_build_for(metadata)
|
|
371
|
+
except MalformedRecordError as e:
|
|
372
|
+
console.print(
|
|
373
|
+
f"[yellow]⚠️ {escape(str(e))} in {MANIFEST_FILENAME}; it is ignored.[/yellow]"
|
|
374
|
+
)
|
|
375
|
+
recorded = None
|
|
376
|
+
|
|
377
|
+
project_name = metadata.project_name or project_dir.name
|
|
378
|
+
agent_directory = metadata.agent_directory or "app"
|
|
379
|
+
# The new snapshot is rendered by this CLI from the manifest's settings.
|
|
380
|
+
cli_args = metadata_to_cli_args(metadata)
|
|
381
|
+
|
|
382
|
+
source: BaselineSource | None = None
|
|
383
|
+
if baseline_ref is not None:
|
|
384
|
+
source = resolve_baseline_ref(baseline_ref)
|
|
385
|
+
elif old_version == new_version:
|
|
386
|
+
if baseline == "current":
|
|
387
|
+
raise click.UsageError(
|
|
388
|
+
"--baseline current renders the old snapshot with this CLI's own templates, "
|
|
389
|
+
f"so for a project at this version ({new_version}) it can change nothing. Name "
|
|
390
|
+
"the build that created the project with --baseline-ref instead."
|
|
391
|
+
)
|
|
392
|
+
if recorded is None:
|
|
393
|
+
_print_unrecorded_build(metadata, new_version, current.id)
|
|
394
|
+
return
|
|
395
|
+
if recorded.same_build_as(current):
|
|
396
|
+
console.print(
|
|
397
|
+
f"[bold green]✅[/bold green] Project is already at version {new_version} "
|
|
398
|
+
f"(build {current.id})"
|
|
399
|
+
)
|
|
400
|
+
return
|
|
401
|
+
new_digest = _snapshot_digest(cli_args, project_name)
|
|
402
|
+
if recorded.template_digest is not None and recorded.template_digest == new_digest:
|
|
403
|
+
console.print(
|
|
404
|
+
f"[bold green]✅[/bold green] Project is already at version {new_version}: "
|
|
405
|
+
f"build {recorded.id} renders the same files for its settings as this build "
|
|
406
|
+
f"({current.id})"
|
|
407
|
+
)
|
|
408
|
+
return
|
|
409
|
+
source = _recorded_build_source(recorded, same_version=True) or _release_source(old_version)
|
|
410
|
+
elif baseline == "authentic":
|
|
411
|
+
source = _recorded_build_source(recorded, same_version=False)
|
|
412
|
+
|
|
413
|
+
if baseline == "authentic":
|
|
414
|
+
if source is None:
|
|
415
|
+
# The cli_version release. Checked up front: without a release to
|
|
416
|
+
# fetch, a usable install spec or uvx the authentic baseline cannot
|
|
417
|
+
# be built, and the merge would stop anyway, after generating nothing.
|
|
418
|
+
if not is_fetchable_version(old_version):
|
|
419
|
+
raise ManifestError(
|
|
420
|
+
f"cli_version {old_version!r} in {MANIFEST_FILENAME} is not a released "
|
|
421
|
+
f"{PACKAGE_NAME} version, so its templates cannot be rebuilt.\n"
|
|
422
|
+
f" {_BASELINE_CURRENT_HINT}"
|
|
423
|
+
)
|
|
424
|
+
if pinned_install_spec(old_version) is None:
|
|
425
|
+
raise InstallSpecError(
|
|
426
|
+
f"{pinned_spec_unavailable(old_version)}.\n {_BASELINE_CURRENT_HINT}"
|
|
427
|
+
)
|
|
428
|
+
try:
|
|
429
|
+
_tools.require_tool("uvx")
|
|
430
|
+
except _tools.ToolNotFoundError as e:
|
|
431
|
+
console.print(f"[bold red]Error:[/bold red] {e.message}")
|
|
432
|
+
console.print(
|
|
433
|
+
f"[dim]The authentic {old_version} baseline needs uvx. Install uv, or re-run "
|
|
434
|
+
"with --baseline current to compare against the current templates.[/dim]"
|
|
435
|
+
)
|
|
436
|
+
raise SystemExit(EXIT_TOOL_FAILURE) from e
|
|
437
|
+
else:
|
|
438
|
+
logging.warning(
|
|
439
|
+
"--baseline current: the %s snapshot will be rendered with the current "
|
|
440
|
+
"templates, not by %s@%s.",
|
|
441
|
+
old_version,
|
|
442
|
+
PACKAGE_NAME,
|
|
443
|
+
old_version,
|
|
444
|
+
)
|
|
445
|
+
console.print(
|
|
446
|
+
"[yellow]⚠️ --baseline current: comparing against the current templates instead "
|
|
447
|
+
f"of {PACKAGE_NAME}@{old_version}. Deletions and updates between the two versions "
|
|
448
|
+
"may be misclassified; review the result.[/yellow]"
|
|
449
|
+
)
|
|
450
|
+
|
|
451
|
+
baseline_label = source.label if source is not None else None
|
|
452
|
+
if baseline == "authentic" and source is None:
|
|
453
|
+
baseline_label = f"the {old_version} release"
|
|
454
|
+
_display_version_header(
|
|
455
|
+
_build_label(old_version, recorded.id if recorded else None),
|
|
456
|
+
_build_label(new_version, current.id),
|
|
457
|
+
baseline_label if baseline == "authentic" else None,
|
|
458
|
+
)
|
|
459
|
+
|
|
460
|
+
# The old snapshot is rendered by the CLI that scaffolded the project, which
|
|
461
|
+
# may spell some values differently; the new one by this CLI.
|
|
462
|
+
old_args = metadata_to_cli_args(
|
|
463
|
+
metadata, cli_version=old_version if baseline == "authentic" else None
|
|
464
|
+
)
|
|
465
|
+
|
|
466
|
+
backup_hook = make_backup_pre_apply_hook(
|
|
467
|
+
console=console,
|
|
468
|
+
auto_approve=auto_approve,
|
|
469
|
+
interactive=interactive,
|
|
470
|
+
)
|
|
471
|
+
|
|
472
|
+
digests: dict[str, str] = {}
|
|
473
|
+
|
|
474
|
+
def _check_snapshots(old_dir: pathlib.Path, new_dir: pathlib.Path) -> None:
|
|
475
|
+
"""Refuse a baseline that is not the project's build; keep the new digest."""
|
|
476
|
+
digests["new"] = template_digest(new_dir)
|
|
477
|
+
if baseline != "authentic":
|
|
478
|
+
return
|
|
479
|
+
rendered = read_manifest_data(old_dir)
|
|
480
|
+
rendered_version = str(rendered.get("cli_version") or "")
|
|
481
|
+
if rendered_version and rendered_version != old_version:
|
|
482
|
+
raise BaselineError(
|
|
483
|
+
f"The baseline ({baseline_label}) is {PACKAGE_NAME} {rendered_version}, but "
|
|
484
|
+
f"{MANIFEST_FILENAME} records {old_version}: it is not the build that created "
|
|
485
|
+
"this project. Nothing was changed."
|
|
486
|
+
)
|
|
487
|
+
try:
|
|
488
|
+
rendered_record = parse_build_record(rendered.get(MANIFEST_KEY))
|
|
489
|
+
except MalformedRecordError:
|
|
490
|
+
rendered_record = None
|
|
491
|
+
if (
|
|
492
|
+
recorded is not None
|
|
493
|
+
and recorded.commit is not None
|
|
494
|
+
and rendered_record is not None
|
|
495
|
+
and rendered_record.commit is not None
|
|
496
|
+
and rendered_record.commit != recorded.commit
|
|
497
|
+
):
|
|
498
|
+
message = (
|
|
499
|
+
f"The baseline ({baseline_label}) is build {rendered_record.id}, but the "
|
|
500
|
+
f"project records build {recorded.id}."
|
|
501
|
+
)
|
|
502
|
+
if baseline_ref is None:
|
|
503
|
+
raise BaselineError(
|
|
504
|
+
f"{message} Nothing was changed; name the project's build with --baseline-ref."
|
|
505
|
+
)
|
|
506
|
+
console.print(
|
|
507
|
+
f"[yellow]⚠️ {escape(message)} Using it, as --baseline-ref asks.[/yellow]"
|
|
508
|
+
)
|
|
509
|
+
if baseline_ref is None:
|
|
510
|
+
return
|
|
511
|
+
if template_digest(old_dir) == digests["new"]:
|
|
512
|
+
console.print(
|
|
513
|
+
f"[yellow]⚠️ The baseline ({escape(baseline_label or '')}) renders the same "
|
|
514
|
+
f"files as this build ({current.id}) for this project's settings, so nothing "
|
|
515
|
+
"can be upgraded from it. If it is not the build that created the project, "
|
|
516
|
+
"name that build instead.[/yellow]"
|
|
517
|
+
)
|
|
518
|
+
_warn_if_not_the_projects_build(project_dir, old_dir, new_dir, agent_directory)
|
|
519
|
+
|
|
520
|
+
def _record_new_build(proj_dir: pathlib.Path, lang: str) -> None:
|
|
521
|
+
# The manifest is rewritten (without its comments) only when the version changes.
|
|
522
|
+
if old_version != new_version:
|
|
523
|
+
update_cli_metadata(proj_dir, {}, cli_version=new_version)
|
|
524
|
+
write_build_record(proj_dir, BuildRecord.of(current, digests.get("new")))
|
|
525
|
+
|
|
526
|
+
success = run_three_way_merge(
|
|
527
|
+
project_dir=project_dir,
|
|
528
|
+
project_name=project_name,
|
|
529
|
+
agent_directory=agent_directory,
|
|
530
|
+
language=language,
|
|
531
|
+
old_args=old_args,
|
|
532
|
+
new_args=cli_args,
|
|
533
|
+
old_version=old_version,
|
|
534
|
+
baseline=baseline, # type: ignore[arg-type]
|
|
535
|
+
old_source=source if baseline == "authentic" else None,
|
|
536
|
+
auto_approve=auto_approve,
|
|
537
|
+
dry_run=dry_run,
|
|
538
|
+
interactive=interactive,
|
|
539
|
+
operation_label="upgrade",
|
|
540
|
+
pre_apply_hook=backup_hook,
|
|
541
|
+
post_apply_hook=_record_new_build,
|
|
542
|
+
snapshot_check=_check_snapshots,
|
|
543
|
+
)
|
|
544
|
+
|
|
545
|
+
if not success:
|
|
546
|
+
what = baseline_label or f"{PACKAGE_NAME}@{old_version}"
|
|
547
|
+
console.print(
|
|
548
|
+
f"[bold red]Error:[/bold red] Could not build the baseline, {what} (the build "
|
|
549
|
+
"that scaffolded this project), so the upgrade diff cannot be computed "
|
|
550
|
+
"authentically."
|
|
551
|
+
)
|
|
552
|
+
if source is None:
|
|
553
|
+
where = (
|
|
554
|
+
f"that the v{old_version} tag exists, and retry; {INSTALL_SPEC_ENV} with "
|
|
555
|
+
"{version} can point at a mirror or a local clone that has it, and "
|
|
556
|
+
"--baseline-ref names the build directly (a clone: <clone>@<commit>)"
|
|
557
|
+
)
|
|
558
|
+
else:
|
|
559
|
+
where = (
|
|
560
|
+
"that the ref exists where it is looked up, and retry; a commit that is not "
|
|
561
|
+
"on the remote is named with --baseline-ref <clone>@<commit> (a local clone "
|
|
562
|
+
"that has it) or a path to a checkout at that commit"
|
|
563
|
+
)
|
|
564
|
+
console.print(
|
|
565
|
+
f"[dim]Your project was not modified. Check your network/proxy and {where}. "
|
|
566
|
+
"--baseline current compares against the current templates instead, but cannot "
|
|
567
|
+
f"tell your edits from the template's changes since {old_version}: files you did "
|
|
568
|
+
f"not edit keep their {old_version} content.[/dim]"
|
|
569
|
+
)
|
|
570
|
+
raise SystemExit(EXIT_TOOL_FAILURE)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# Project settings for the GitHub workflows (which are copied verbatim, not
|
|
2
|
+
# rendered). Read as data, never sourced by a shell: one NAME=VALUE per line,
|
|
3
|
+
# no quoting needed even when a value contains spaces; lines starting with #
|
|
4
|
+
# are comments. Only the names below are accepted (the workflows refuse any
|
|
5
|
+
# other, so this file cannot change how their steps run).
|
|
6
|
+
IMAGE_REPOSITORY={{cookiecutter.registry}}/{{cookiecutter.project_name}}
|
|
7
|
+
RELEASE_NAME={{cookiecutter.project_name}}
|
|
8
|
+
CHART_PATH=deployment/helm/{{cookiecutter.project_name}}
|
|
9
|
+
RUNTIME={{cookiecutter.runtime}}
|
|
10
|
+
CD={{cookiecutter.cd}}
|
|
11
|
+
# Where the workflows install graph-agents-cli from (uvx --from "$GRAPH_AGENTS_CLI_SPEC").
|
|
12
|
+
GRAPH_AGENTS_CLI_SPEC={{cookiecutter.cli_install_spec}}
|