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,103 @@
|
|
|
1
|
+
# Copyright 2026 graph-agents-cli contributors
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# https://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
"""graph-agents-cli infra commands — read-only prerequisite checks (nothing is installed)."""
|
|
15
|
+
|
|
16
|
+
from __future__ import annotations
|
|
17
|
+
|
|
18
|
+
import json
|
|
19
|
+
|
|
20
|
+
import click
|
|
21
|
+
|
|
22
|
+
from graph_agents_cli._click import LazyGroup
|
|
23
|
+
from graph_agents_cli._output import Console
|
|
24
|
+
from graph_agents_cli.deploy._config import load_settings
|
|
25
|
+
from graph_agents_cli.infra import checks as _checks
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
@click.group("infra", cls=LazyGroup)
|
|
29
|
+
def infra_group() -> None:
|
|
30
|
+
"""Check cluster and repository prerequisites (read-only).
|
|
31
|
+
|
|
32
|
+
\b
|
|
33
|
+
Subcommands:
|
|
34
|
+
check Report which prerequisites exist for the selected environment and mode
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
_STYLES = {
|
|
39
|
+
_checks.OK: "green",
|
|
40
|
+
_checks.MISSING: "red",
|
|
41
|
+
_checks.WARN: "yellow",
|
|
42
|
+
_checks.SKIP: "dim",
|
|
43
|
+
_checks.INFO: "cyan",
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
@infra_group.command("check")
|
|
48
|
+
@click.option(
|
|
49
|
+
"--env", "env", default=None, help="Environment to check the cluster for (dev, staging, prod)."
|
|
50
|
+
)
|
|
51
|
+
@click.option(
|
|
52
|
+
"--profile",
|
|
53
|
+
"profile",
|
|
54
|
+
type=click.Choice(_checks.PROFILES),
|
|
55
|
+
default=None,
|
|
56
|
+
help="Also verify the named profile (disconnected: no hosted dependency).",
|
|
57
|
+
)
|
|
58
|
+
@click.option("--json", "as_json", is_flag=True, help="Print the report as JSON.")
|
|
59
|
+
def cmd_infra_check(env: str | None, profile: str | None, as_json: bool) -> None:
|
|
60
|
+
"""Report which prerequisites exist for the selected environment and mode."""
|
|
61
|
+
settings = load_settings()
|
|
62
|
+
report = _checks.run_checks(settings, env, profile)
|
|
63
|
+
if as_json:
|
|
64
|
+
click.echo(json.dumps(report.to_dict(), indent=2))
|
|
65
|
+
else:
|
|
66
|
+
_print_table(report)
|
|
67
|
+
if not report.ok:
|
|
68
|
+
raise SystemExit(1)
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _print_table(report: _checks.Report) -> None:
|
|
72
|
+
from rich.table import Table
|
|
73
|
+
|
|
74
|
+
console = Console()
|
|
75
|
+
title = f"infra check: mode {report.mode}"
|
|
76
|
+
if report.env:
|
|
77
|
+
title += f", env {report.env}"
|
|
78
|
+
if report.profile:
|
|
79
|
+
title += f", profile {report.profile}"
|
|
80
|
+
table = Table(title=title, show_lines=False)
|
|
81
|
+
table.add_column("Check")
|
|
82
|
+
table.add_column("Status")
|
|
83
|
+
table.add_column("Required")
|
|
84
|
+
table.add_column("Detail")
|
|
85
|
+
for check in report.checks:
|
|
86
|
+
style = _STYLES.get(check.status, "")
|
|
87
|
+
table.add_row(
|
|
88
|
+
check.name,
|
|
89
|
+
f"[{style}]{check.status}[/{style}]",
|
|
90
|
+
"yes" if check.required else "no",
|
|
91
|
+
check.detail,
|
|
92
|
+
)
|
|
93
|
+
console.print(table)
|
|
94
|
+
hints = [c for c in report.checks if c.hint and c.status in (_checks.MISSING, _checks.WARN)]
|
|
95
|
+
if hints:
|
|
96
|
+
console.print("Hints:")
|
|
97
|
+
for check in hints:
|
|
98
|
+
console.print(f" - {check.name}: {check.hint}", highlight=False)
|
|
99
|
+
if report.ok:
|
|
100
|
+
console.print("All required prerequisites are present.", style="green")
|
|
101
|
+
else:
|
|
102
|
+
failed = ", ".join(c.name for c in report.checks if c.failed)
|
|
103
|
+
console.print(f"Missing required prerequisites: {failed}", style="red")
|
graph_agents_cli/main.py
ADDED
|
@@ -0,0 +1,591 @@
|
|
|
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
|
+
"""Root Click group for the 'graph-agents-cli' CLI.
|
|
17
|
+
|
|
18
|
+
Every command is registered lazily via `add_lazy_command`. The command
|
|
19
|
+
modules are imported only when the user invokes the command (or asks for
|
|
20
|
+
its specific --help). See `LazyGroup` in `_click.py`.
|
|
21
|
+
|
|
22
|
+
The startup path must import no agent framework, model SDK, or Kubernetes
|
|
23
|
+
client: `tests/test_startup_imports.py` enforces that (a fast, light startup).
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
from __future__ import annotations
|
|
27
|
+
|
|
28
|
+
import io
|
|
29
|
+
import logging
|
|
30
|
+
import os
|
|
31
|
+
import sys
|
|
32
|
+
import traceback
|
|
33
|
+
from pathlib import Path
|
|
34
|
+
from typing import TYPE_CHECKING, ClassVar
|
|
35
|
+
|
|
36
|
+
import click
|
|
37
|
+
|
|
38
|
+
from graph_agents_cli.__init__ import __version__
|
|
39
|
+
from graph_agents_cli._click import LazyGroup, patch_source_in_help
|
|
40
|
+
from graph_agents_cli._project import find_project_root, is_project_moved
|
|
41
|
+
from graph_agents_cli._runner import DISABLE_OVERRIDES_ENV
|
|
42
|
+
|
|
43
|
+
# Type-only: nothing under `extension.` may be imported at module scope. A run
|
|
44
|
+
# that bypasses overrides (GRAPH_AGENTS_CLI_DISABLE_OVERRIDES=1 — set for any
|
|
45
|
+
# command an extension re-enters) must not load extension discovery at all.
|
|
46
|
+
if TYPE_CHECKING:
|
|
47
|
+
from graph_agents_cli.extension._loader import ExtensionSet, ResolvedCommand
|
|
48
|
+
|
|
49
|
+
# Force utf-8 encoding and non-exception fallback for printing
|
|
50
|
+
if isinstance(sys.stdout, io.TextIOWrapper):
|
|
51
|
+
sys.stdout.reconfigure(encoding="utf-8", errors="replace")
|
|
52
|
+
if isinstance(sys.stderr, io.TextIOWrapper):
|
|
53
|
+
sys.stderr.reconfigure(encoding="utf-8", errors="replace")
|
|
54
|
+
|
|
55
|
+
NO_UPDATE_CHECK_ENV = "GRAPH_AGENTS_CLI_NO_UPDATE_CHECK"
|
|
56
|
+
# Set to 1 to see the traceback behind a one-line network/file/parse error.
|
|
57
|
+
DEBUG_ENV = "GRAPH_AGENTS_CLI_DEBUG"
|
|
58
|
+
|
|
59
|
+
# Exit codes: 0 ok, 1 refused or failed gate, 2 tool failure, 3 configuration error.
|
|
60
|
+
EXIT_TOOL_FAILURE = 2
|
|
61
|
+
EXIT_CONFIG_ERROR = 3
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def _print_is_project_moved_tip() -> None:
|
|
65
|
+
message = (
|
|
66
|
+
"\n💡 Tip: It looks like the project folder may have been moved or renamed."
|
|
67
|
+
" Try running `graph-agents-cli install --clean` to reset the environment, then"
|
|
68
|
+
" re-run your original command"
|
|
69
|
+
)
|
|
70
|
+
if is_project_moved():
|
|
71
|
+
from graph_agents_cli._output import Console
|
|
72
|
+
|
|
73
|
+
Console(stderr=True).print(message, style="cyan")
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class _MainGroup(LazyGroup):
|
|
77
|
+
"""Click group with lazy command loading and full-traceback exception handling."""
|
|
78
|
+
|
|
79
|
+
def __init__(self, *args, **kwargs):
|
|
80
|
+
super().__init__(*args, **kwargs)
|
|
81
|
+
self._extensions_applied = False
|
|
82
|
+
|
|
83
|
+
def list_commands(self, ctx):
|
|
84
|
+
self._apply_extensions()
|
|
85
|
+
return super().list_commands(ctx)
|
|
86
|
+
|
|
87
|
+
def get_command(self, ctx, cmd_name):
|
|
88
|
+
self._apply_extensions()
|
|
89
|
+
return super().get_command(ctx, cmd_name)
|
|
90
|
+
|
|
91
|
+
def _apply_extensions(self) -> None:
|
|
92
|
+
if self._extensions_applied:
|
|
93
|
+
return
|
|
94
|
+
self._extensions_applied = True
|
|
95
|
+
if os.environ.get(DISABLE_OVERRIDES_ENV) == "1":
|
|
96
|
+
return
|
|
97
|
+
|
|
98
|
+
from graph_agents_cli.extension._loader import load_extension_set
|
|
99
|
+
from graph_agents_cli.extension._paths import user_config_root
|
|
100
|
+
|
|
101
|
+
project_root = find_project_root(Path.cwd())
|
|
102
|
+
user_root = user_config_root()
|
|
103
|
+
extension_set = load_extension_set(project_root, user_root)
|
|
104
|
+
|
|
105
|
+
for inc in extension_set.incompatible:
|
|
106
|
+
if inc.error_on_incompatible:
|
|
107
|
+
logging.warning(
|
|
108
|
+
"graph-agents-cli: extension %r requires graph-agents-cli %s but running %s; "
|
|
109
|
+
"its commands will fail until you run `graph-agents-cli extension "
|
|
110
|
+
"update %s`, remove it, or pin a compatible CLI.",
|
|
111
|
+
inc.name,
|
|
112
|
+
inc.requires_agents_cli,
|
|
113
|
+
extension_set.running_version,
|
|
114
|
+
inc.name,
|
|
115
|
+
)
|
|
116
|
+
else:
|
|
117
|
+
logging.warning(
|
|
118
|
+
"graph-agents-cli: extension %r requires graph-agents-cli %s but running %s; "
|
|
119
|
+
"applying anyway (may misbehave).",
|
|
120
|
+
inc.name,
|
|
121
|
+
inc.requires_agents_cli,
|
|
122
|
+
extension_set.running_version,
|
|
123
|
+
)
|
|
124
|
+
|
|
125
|
+
if not extension_set.commands:
|
|
126
|
+
return
|
|
127
|
+
|
|
128
|
+
applied: list[str] = []
|
|
129
|
+
for name, resolved in extension_set.commands.items():
|
|
130
|
+
if self._install(name, resolved):
|
|
131
|
+
applied.append(name)
|
|
132
|
+
applied.extend(self._mirror_onto_aliases(name, resolved, extension_set))
|
|
133
|
+
|
|
134
|
+
if applied:
|
|
135
|
+
|
|
136
|
+
def _detail(name: str) -> str:
|
|
137
|
+
r = extension_set.commands.get(name)
|
|
138
|
+
if r is None:
|
|
139
|
+
return name
|
|
140
|
+
state = " BLOCKED" if r.blocked_requires else ""
|
|
141
|
+
return f"{name} [{r.extension_name}/{r.scope}{state}]"
|
|
142
|
+
|
|
143
|
+
details = [_detail(n) for n in sorted(applied)]
|
|
144
|
+
# Logged at WARNING so the takeover is visible by default: auto-loaded
|
|
145
|
+
# project-scope extensions run with the same trust as the repo you're in.
|
|
146
|
+
logging.warning(
|
|
147
|
+
"graph-agents-cli: applying %d extension command(s): %s",
|
|
148
|
+
len(applied),
|
|
149
|
+
", ".join(details),
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
def _mirror_onto_aliases(
|
|
153
|
+
self, dotted: str, resolved: ResolvedCommand, extension_set: ExtensionSet
|
|
154
|
+
) -> list[str]:
|
|
155
|
+
"""Apply an override of `group.sub` to top-level aliases of the same command.
|
|
156
|
+
|
|
157
|
+
`create` and `scaffold create` are two registrations of one command
|
|
158
|
+
(identical `module:obj` target), so overriding the canonical
|
|
159
|
+
`scaffold.create` must also take over `create`.
|
|
160
|
+
"""
|
|
161
|
+
if "." not in dotted:
|
|
162
|
+
return []
|
|
163
|
+
group_name, sub_name = dotted.split(".", 1)
|
|
164
|
+
parent = self._load_builtin(group_name)
|
|
165
|
+
if not isinstance(parent, LazyGroup):
|
|
166
|
+
return []
|
|
167
|
+
entry = parent._lazy_commands.get(sub_name)
|
|
168
|
+
if entry is None:
|
|
169
|
+
return []
|
|
170
|
+
mirrored: list[str] = []
|
|
171
|
+
for alias, (target, _short_help) in self._lazy_commands.items():
|
|
172
|
+
if target != entry[0] or alias in extension_set.commands:
|
|
173
|
+
continue
|
|
174
|
+
if self._install(alias, resolved):
|
|
175
|
+
mirrored.append(alias)
|
|
176
|
+
return mirrored
|
|
177
|
+
|
|
178
|
+
def _builtin_names(self) -> set[str]:
|
|
179
|
+
return set(self._lazy_commands) | set(self.commands)
|
|
180
|
+
|
|
181
|
+
def _load_builtin(self, name: str):
|
|
182
|
+
import importlib
|
|
183
|
+
|
|
184
|
+
loaded = self.commands.get(name)
|
|
185
|
+
if loaded is not None:
|
|
186
|
+
return loaded
|
|
187
|
+
entry = self._lazy_commands.get(name)
|
|
188
|
+
if entry is None:
|
|
189
|
+
return None
|
|
190
|
+
module_path, attr = entry[0].split(":")
|
|
191
|
+
try:
|
|
192
|
+
return getattr(importlib.import_module(module_path), attr)
|
|
193
|
+
except Exception as e: # import failure shouldn't crash extension application
|
|
194
|
+
logging.warning("Could not load built-in %r for override check: %s", name, e)
|
|
195
|
+
return None
|
|
196
|
+
|
|
197
|
+
def _install(self, name: str, resolved: ResolvedCommand) -> bool:
|
|
198
|
+
"""Install one command; dotted names (group.sub) target a subcommand."""
|
|
199
|
+
if "." in name:
|
|
200
|
+
return self._install_subcommand(name, resolved)
|
|
201
|
+
return self._install_top_level(name, resolved)
|
|
202
|
+
|
|
203
|
+
def _synthesize(self, resolved: ResolvedCommand, *, leaf: str, display: str):
|
|
204
|
+
from graph_agents_cli.extension._overrides import (
|
|
205
|
+
make_blocked_command,
|
|
206
|
+
make_override_command,
|
|
207
|
+
)
|
|
208
|
+
|
|
209
|
+
if resolved.blocked_requires is not None:
|
|
210
|
+
return make_blocked_command(
|
|
211
|
+
extension_name=resolved.extension_name,
|
|
212
|
+
leaf_name=leaf,
|
|
213
|
+
display_path=display,
|
|
214
|
+
requires=resolved.blocked_requires,
|
|
215
|
+
running=__version__,
|
|
216
|
+
)
|
|
217
|
+
return make_override_command(
|
|
218
|
+
resolved.contribution,
|
|
219
|
+
extension_name=resolved.extension_name,
|
|
220
|
+
scope=resolved.scope,
|
|
221
|
+
leaf_name=leaf,
|
|
222
|
+
display_path=display,
|
|
223
|
+
extension_root=resolved.extension_root,
|
|
224
|
+
)
|
|
225
|
+
|
|
226
|
+
def _install_top_level(self, name: str, resolved: ResolvedCommand) -> bool:
|
|
227
|
+
is_builtin = name in self._builtin_names()
|
|
228
|
+
if resolved.contribution.kind == "add" and is_builtin:
|
|
229
|
+
logging.warning(
|
|
230
|
+
"Extension %r tried to add command %r, which is a built-in; "
|
|
231
|
+
"use commands.override instead. Skipping.",
|
|
232
|
+
resolved.extension_name,
|
|
233
|
+
name,
|
|
234
|
+
)
|
|
235
|
+
return False
|
|
236
|
+
if resolved.contribution.kind == "override" and not is_builtin:
|
|
237
|
+
logging.warning(
|
|
238
|
+
"Extension %r overrides unknown command %r; skipping.",
|
|
239
|
+
resolved.extension_name,
|
|
240
|
+
name,
|
|
241
|
+
)
|
|
242
|
+
return False
|
|
243
|
+
if is_builtin and isinstance(self._load_builtin(name), click.Group):
|
|
244
|
+
logging.warning(
|
|
245
|
+
"Extension %r cannot override command group %r; override a "
|
|
246
|
+
"subcommand instead (e.g. %s.<sub>). Skipping.",
|
|
247
|
+
resolved.extension_name,
|
|
248
|
+
name,
|
|
249
|
+
name,
|
|
250
|
+
)
|
|
251
|
+
return False
|
|
252
|
+
self._overrides[name] = self._synthesize(resolved, leaf=name, display=name)
|
|
253
|
+
return True
|
|
254
|
+
|
|
255
|
+
def _install_subcommand(self, dotted: str, resolved: ResolvedCommand) -> bool:
|
|
256
|
+
parts = dotted.split(".")
|
|
257
|
+
if len(parts) != 2:
|
|
258
|
+
logging.warning(
|
|
259
|
+
"Extension %r: only single-level subcommand overrides "
|
|
260
|
+
"(group.sub) are supported in v1; skipping %r.",
|
|
261
|
+
resolved.extension_name,
|
|
262
|
+
dotted,
|
|
263
|
+
)
|
|
264
|
+
return False
|
|
265
|
+
group_name, sub_name = parts
|
|
266
|
+
if group_name not in self._builtin_names():
|
|
267
|
+
logging.warning(
|
|
268
|
+
"Extension %r: parent command %r is not a built-in; skipping %r.",
|
|
269
|
+
resolved.extension_name,
|
|
270
|
+
group_name,
|
|
271
|
+
dotted,
|
|
272
|
+
)
|
|
273
|
+
return False
|
|
274
|
+
parent = self._load_builtin(group_name)
|
|
275
|
+
if not isinstance(parent, LazyGroup):
|
|
276
|
+
logging.warning(
|
|
277
|
+
"Extension %r: %r is not a command group; skipping %r.",
|
|
278
|
+
resolved.extension_name,
|
|
279
|
+
group_name,
|
|
280
|
+
dotted,
|
|
281
|
+
)
|
|
282
|
+
return False
|
|
283
|
+
sub_known = sub_name in parent._lazy_commands or sub_name in parent.commands
|
|
284
|
+
if resolved.contribution.kind == "override" and not sub_known:
|
|
285
|
+
logging.warning(
|
|
286
|
+
"Extension %r: %r has no subcommand %r; skipping.",
|
|
287
|
+
resolved.extension_name,
|
|
288
|
+
group_name,
|
|
289
|
+
sub_name,
|
|
290
|
+
)
|
|
291
|
+
return False
|
|
292
|
+
if resolved.contribution.kind == "add" and sub_known:
|
|
293
|
+
logging.warning(
|
|
294
|
+
"Extension %r: subcommand %r already exists; use override. Skipping.",
|
|
295
|
+
resolved.extension_name,
|
|
296
|
+
dotted,
|
|
297
|
+
)
|
|
298
|
+
return False
|
|
299
|
+
parent._overrides[sub_name] = self._synthesize(
|
|
300
|
+
resolved, leaf=sub_name, display=f"{group_name} {sub_name}"
|
|
301
|
+
)
|
|
302
|
+
return True
|
|
303
|
+
|
|
304
|
+
def invoke(self, ctx: click.Context) -> None:
|
|
305
|
+
try:
|
|
306
|
+
super().invoke(ctx)
|
|
307
|
+
except click.exceptions.Exit:
|
|
308
|
+
raise
|
|
309
|
+
except click.ClickException:
|
|
310
|
+
click.echo(f"graph-agents-cli v{__version__}", err=True)
|
|
311
|
+
_print_is_project_moved_tip()
|
|
312
|
+
raise
|
|
313
|
+
except click.Abort:
|
|
314
|
+
# A declined prompt (or Ctrl-C/EOF inside click.prompt/confirm) is
|
|
315
|
+
# a RuntimeError, not a ClickException: let Click's standalone
|
|
316
|
+
# handler print "Aborted!" and exit 1 instead of a traceback.
|
|
317
|
+
raise
|
|
318
|
+
except KeyboardInterrupt as exc:
|
|
319
|
+
from graph_agents_cli._output import Console
|
|
320
|
+
|
|
321
|
+
console = Console(stderr=True)
|
|
322
|
+
console.print(f"\ngraph-agents-cli v{__version__}", style="dim")
|
|
323
|
+
# A SIGTERM/SIGHUP turned into an interrupt (run/_signals.py) exits
|
|
324
|
+
# with 128 + its signal number, like a process the signal ended.
|
|
325
|
+
exit_code = getattr(exc, "exit_code", 130)
|
|
326
|
+
reason = "terminated by a signal" if exit_code != 130 else "cancelled by user"
|
|
327
|
+
console.print(f"Operation {reason}", style="yellow")
|
|
328
|
+
ctx.exit(exit_code)
|
|
329
|
+
except Exception as exc:
|
|
330
|
+
click.echo(f"graph-agents-cli v{__version__}", err=True)
|
|
331
|
+
_print_is_project_moved_tip()
|
|
332
|
+
known = _environment_error(exc)
|
|
333
|
+
if known is not None and os.environ.get(DEBUG_ENV) != "1":
|
|
334
|
+
# A network, file-system or parse problem is the user's to fix:
|
|
335
|
+
# one line, not a traceback (which DEBUG_ENV=1 still shows).
|
|
336
|
+
message, code = known
|
|
337
|
+
click.echo(f"Error: {message}", err=True)
|
|
338
|
+
click.echo(f" (set {DEBUG_ENV}=1 to see the traceback)", err=True)
|
|
339
|
+
ctx.exit(code)
|
|
340
|
+
# Anything else is a bug in the CLI: keep the traceback for the report.
|
|
341
|
+
traceback.print_exc()
|
|
342
|
+
ctx.exit(EXIT_TOOL_FAILURE)
|
|
343
|
+
|
|
344
|
+
def main(self, *args, **kwargs): # type: ignore[override]
|
|
345
|
+
_configure_logging()
|
|
346
|
+
return super().main(*args, **kwargs)
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
def _environment_error(exc: BaseException) -> tuple[str, int] | None:
|
|
350
|
+
"""``(one-line message, exit code)`` for an error the user's environment caused, else None.
|
|
351
|
+
|
|
352
|
+
Network failures and OS errors are tool failures (exit 2); unparseable YAML
|
|
353
|
+
or JSON is a configuration error (exit 3). Library-specific classes are
|
|
354
|
+
matched without importing the library, which keeps startup light.
|
|
355
|
+
"""
|
|
356
|
+
import json
|
|
357
|
+
|
|
358
|
+
import yaml
|
|
359
|
+
|
|
360
|
+
name = type(exc).__name__
|
|
361
|
+
first_line = (str(exc).strip().splitlines() or [""])[0][:300]
|
|
362
|
+
detail = f"{name}: {first_line}" if first_line else name
|
|
363
|
+
if isinstance(exc, yaml.YAMLError):
|
|
364
|
+
mark = getattr(exc, "problem_mark", None)
|
|
365
|
+
where = f" in {mark.name} (line {mark.line + 1})" if mark is not None else ""
|
|
366
|
+
problem = getattr(exc, "problem", None) or first_line
|
|
367
|
+
return f"invalid YAML{where}: {problem}", EXIT_CONFIG_ERROR
|
|
368
|
+
if isinstance(exc, json.JSONDecodeError):
|
|
369
|
+
return f"invalid JSON: {first_line}", EXIT_CONFIG_ERROR
|
|
370
|
+
modules = {cls.__module__.split(".")[0] for cls in type(exc).__mro__}
|
|
371
|
+
lowered = name.lower()
|
|
372
|
+
if (
|
|
373
|
+
isinstance(exc, ConnectionError)
|
|
374
|
+
or modules & {"httpx", "httpcore", "requests", "urllib3"}
|
|
375
|
+
or "connection" in lowered
|
|
376
|
+
):
|
|
377
|
+
return f"network error: {detail}", EXIT_TOOL_FAILURE
|
|
378
|
+
if isinstance(exc, TimeoutError) or "timeout" in lowered:
|
|
379
|
+
return f"timed out: {detail}", EXIT_TOOL_FAILURE
|
|
380
|
+
if isinstance(exc, OSError):
|
|
381
|
+
return detail, EXIT_TOOL_FAILURE
|
|
382
|
+
return None
|
|
383
|
+
|
|
384
|
+
|
|
385
|
+
class _CliLogHandler(logging.Handler):
|
|
386
|
+
"""Log records as ``Warning: ...`` / ``Error: ...`` on stderr (not ``WARNING:root:``)."""
|
|
387
|
+
|
|
388
|
+
_PREFIX: ClassVar[dict[int, str]] = {
|
|
389
|
+
logging.WARNING: "Warning: ",
|
|
390
|
+
logging.ERROR: "Error: ",
|
|
391
|
+
logging.CRITICAL: "Error: ",
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
def emit(self, record: logging.LogRecord) -> None:
|
|
395
|
+
try:
|
|
396
|
+
click.echo(self._PREFIX.get(record.levelno, "") + self.format(record), err=True)
|
|
397
|
+
except Exception:
|
|
398
|
+
self.handleError(record)
|
|
399
|
+
|
|
400
|
+
|
|
401
|
+
def _configure_logging() -> None:
|
|
402
|
+
"""Give the root logger a clean stderr handler unless something configured it already.
|
|
403
|
+
|
|
404
|
+
Without one, the first ``logging.warning`` falls back to ``basicConfig`` and
|
|
405
|
+
prints ``WARNING:root:...``. A ``--debug`` flag (``basicConfig(force=True)``)
|
|
406
|
+
or a test harness that installed its own handler wins.
|
|
407
|
+
"""
|
|
408
|
+
root = logging.getLogger()
|
|
409
|
+
if root.handlers:
|
|
410
|
+
return
|
|
411
|
+
handler = _CliLogHandler()
|
|
412
|
+
handler.setFormatter(logging.Formatter("%(message)s"))
|
|
413
|
+
root.addHandler(handler)
|
|
414
|
+
root.setLevel(logging.WARNING)
|
|
415
|
+
|
|
416
|
+
|
|
417
|
+
def _print_version(ctx: click.Context, _param: click.Parameter, value: bool) -> None:
|
|
418
|
+
"""``--version``: the build id, which tells apart builds that share a version.
|
|
419
|
+
|
|
420
|
+
A release build prints its version (``0.2.0``); any other build adds the
|
|
421
|
+
commit (``0.2.0+g1a2b3c4``, ``.dirty`` for uncommitted changes). Computed
|
|
422
|
+
only when asked: a source checkout reads git for it.
|
|
423
|
+
"""
|
|
424
|
+
if not value or ctx.resilient_parsing:
|
|
425
|
+
return
|
|
426
|
+
from graph_agents_cli._build import current_build
|
|
427
|
+
|
|
428
|
+
click.echo(f"graph-agents-cli, version {current_build().id}")
|
|
429
|
+
ctx.exit()
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
@click.group(cls=_MainGroup)
|
|
433
|
+
@click.option(
|
|
434
|
+
"--version",
|
|
435
|
+
is_flag=True,
|
|
436
|
+
expose_value=False,
|
|
437
|
+
is_eager=True,
|
|
438
|
+
callback=_print_version,
|
|
439
|
+
help="Show the version (with the commit, for a build that is not a release) and exit.",
|
|
440
|
+
)
|
|
441
|
+
def main():
|
|
442
|
+
"""Graph Agents CLI — LangGraph agents on Kubernetes.
|
|
443
|
+
|
|
444
|
+
Build, evaluate, and deploy LangGraph agents with a single unified CLI.
|
|
445
|
+
|
|
446
|
+
\b
|
|
447
|
+
Quick start:
|
|
448
|
+
graph-agents-cli setup Install skills to your coding agent
|
|
449
|
+
graph-agents-cli create my-agent Create a new agent project
|
|
450
|
+
graph-agents-cli playground Start the local playground
|
|
451
|
+
graph-agents-cli eval run Run the agent over the eval dataset and grade it
|
|
452
|
+
graph-agents-cli deploy --env dev Deploy to the current Kubernetes context
|
|
453
|
+
"""
|
|
454
|
+
# Update and skills-version checks are opt-out for disconnected installs.
|
|
455
|
+
if os.environ.get(NO_UPDATE_CHECK_ENV) == "1":
|
|
456
|
+
return
|
|
457
|
+
from graph_agents_cli._skills_check import check_skills_version
|
|
458
|
+
from graph_agents_cli.scaffold.utils.version import display_update_message
|
|
459
|
+
|
|
460
|
+
display_update_message()
|
|
461
|
+
check_skills_version()
|
|
462
|
+
|
|
463
|
+
|
|
464
|
+
# Setup commands
|
|
465
|
+
main.add_lazy_command(
|
|
466
|
+
"setup",
|
|
467
|
+
"graph_agents_cli.setup.cmd_setup:cmd_setup",
|
|
468
|
+
"Install graph-agents-cli and skills to detected coding agents.",
|
|
469
|
+
)
|
|
470
|
+
main.add_lazy_command(
|
|
471
|
+
"update",
|
|
472
|
+
"graph_agents_cli.setup.cmd_update:cmd_update",
|
|
473
|
+
"Force reinstall skills to all detected coding agents.",
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
# Preflight / login
|
|
477
|
+
main.add_lazy_command(
|
|
478
|
+
"login",
|
|
479
|
+
"graph_agents_cli.setup.cmd_auth:cmd_login",
|
|
480
|
+
"Check model provider keys, LangSmith, and kubeconfig; optionally write .env.",
|
|
481
|
+
)
|
|
482
|
+
|
|
483
|
+
main.add_lazy_command(
|
|
484
|
+
"auth",
|
|
485
|
+
"graph_agents_cli.setup.cmd_dev_token:auth_group",
|
|
486
|
+
"Local credentials for the project's auth policy (dev-only JWTs).",
|
|
487
|
+
)
|
|
488
|
+
|
|
489
|
+
# Scaffold command group + top-level `create` alias
|
|
490
|
+
main.add_lazy_command(
|
|
491
|
+
"scaffold",
|
|
492
|
+
"graph_agents_cli.scaffold.cmd_scaffold_group:scaffold_group",
|
|
493
|
+
"Scaffold, enhance, and upgrade agent projects.",
|
|
494
|
+
)
|
|
495
|
+
main.add_lazy_command(
|
|
496
|
+
"create",
|
|
497
|
+
"graph_agents_cli.scaffold.commands.create:create",
|
|
498
|
+
"Create a LangGraph agent project from a template.",
|
|
499
|
+
)
|
|
500
|
+
|
|
501
|
+
# Dev commands
|
|
502
|
+
main.add_lazy_command(
|
|
503
|
+
"playground",
|
|
504
|
+
"graph_agents_cli.dev.cmd_playground:cmd_playground",
|
|
505
|
+
"Start the application locally with reload and the dev chat page.",
|
|
506
|
+
)
|
|
507
|
+
main.add_lazy_command(
|
|
508
|
+
"run",
|
|
509
|
+
"graph_agents_cli.run.cmd_run:cmd_run",
|
|
510
|
+
"Run the agent with a single prompt (non-interactive).",
|
|
511
|
+
)
|
|
512
|
+
main.add_lazy_command(
|
|
513
|
+
"approvals",
|
|
514
|
+
"graph_agents_cli.run.cmd_approvals:approvals_group",
|
|
515
|
+
"List and decide the gated API calls agent runs are waiting on.",
|
|
516
|
+
)
|
|
517
|
+
main.add_lazy_command(
|
|
518
|
+
"lint",
|
|
519
|
+
"graph_agents_cli.dev.cmd_lint:cmd_lint",
|
|
520
|
+
"Run code quality checks and the API-policy check.",
|
|
521
|
+
)
|
|
522
|
+
main.add_lazy_command(
|
|
523
|
+
"api",
|
|
524
|
+
"graph_agents_cli.api.cmd_api:api_group",
|
|
525
|
+
"Declare and change the outbound APIs tools may call (api-policy.yaml).",
|
|
526
|
+
)
|
|
527
|
+
main.add_lazy_command(
|
|
528
|
+
"peer",
|
|
529
|
+
"graph_agents_cli.peer.cmd_peer:peer_group",
|
|
530
|
+
"Declare the other agents this agent asks, over A2A (its peers).",
|
|
531
|
+
)
|
|
532
|
+
main.add_lazy_command(
|
|
533
|
+
"system",
|
|
534
|
+
"graph_agents_cli.system.cmd_system:system_group",
|
|
535
|
+
"Check, wire and deploy agents that call each other, as one system.",
|
|
536
|
+
)
|
|
537
|
+
main.add_lazy_command(
|
|
538
|
+
"install",
|
|
539
|
+
"graph_agents_cli.dev.cmd_install:cmd_install",
|
|
540
|
+
"Install project dependencies.",
|
|
541
|
+
)
|
|
542
|
+
main.add_lazy_command(
|
|
543
|
+
"build",
|
|
544
|
+
"graph_agents_cli.dev.cmd_build:cmd_build",
|
|
545
|
+
"Build the agent container image.",
|
|
546
|
+
)
|
|
547
|
+
|
|
548
|
+
# Eval commands
|
|
549
|
+
main.add_lazy_command(
|
|
550
|
+
"eval",
|
|
551
|
+
"graph_agents_cli.eval.cmd_eval_group:eval_group",
|
|
552
|
+
"Evaluate agents and compare results.",
|
|
553
|
+
)
|
|
554
|
+
|
|
555
|
+
# Deploy, secrets, infra
|
|
556
|
+
main.add_lazy_command(
|
|
557
|
+
"deploy",
|
|
558
|
+
"graph_agents_cli.deploy.cmd_deploy:cmd_deploy",
|
|
559
|
+
"Deploy the agent to Kubernetes (mode depends on the project's CD setting).",
|
|
560
|
+
)
|
|
561
|
+
main.add_lazy_command(
|
|
562
|
+
"secrets",
|
|
563
|
+
"graph_agents_cli.secrets.cmd_secrets:secrets_group",
|
|
564
|
+
"Provision and inspect the application Secret per environment.",
|
|
565
|
+
)
|
|
566
|
+
main.add_lazy_command(
|
|
567
|
+
"infra",
|
|
568
|
+
"graph_agents_cli.infra.cmd_infra:infra_group",
|
|
569
|
+
"Check cluster and repository prerequisites (read-only).",
|
|
570
|
+
)
|
|
571
|
+
|
|
572
|
+
# Extension commands
|
|
573
|
+
main.add_lazy_command(
|
|
574
|
+
"extension",
|
|
575
|
+
"graph_agents_cli.extension.cmd_extension_group:extension_group",
|
|
576
|
+
"Manage graph-agents-cli extensions (experimental).",
|
|
577
|
+
)
|
|
578
|
+
|
|
579
|
+
# Info command
|
|
580
|
+
main.add_lazy_command(
|
|
581
|
+
"info",
|
|
582
|
+
"graph_agents_cli.info.cmd_info:cmd_info",
|
|
583
|
+
"Show project configuration, paths, and CLI version.",
|
|
584
|
+
)
|
|
585
|
+
|
|
586
|
+
# Patch the root group itself to show source file in --help.
|
|
587
|
+
patch_source_in_help(main)
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
if __name__ == "__main__":
|
|
591
|
+
main()
|