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,257 @@
|
|
|
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
|
+
|
|
15
|
+
"""The build that rendered a project, recorded in its manifest as ``cli_build``.
|
|
16
|
+
|
|
17
|
+
``cli_version`` cannot tell apart the builds made between two releases, so
|
|
18
|
+
``create`` also records::
|
|
19
|
+
|
|
20
|
+
cli_build:
|
|
21
|
+
id: 0.2.0+g1a2b3c4 # the build id (``graph-agents-cli --version``)
|
|
22
|
+
commit: 1a2b3c4... # its full commit; null when not built from git
|
|
23
|
+
template_digest: sha256:... # what it renders for the recorded settings; or null
|
|
24
|
+
|
|
25
|
+
``template_digest`` is a digest of the snapshot ``scaffold upgrade`` renders
|
|
26
|
+
from the manifest's settings (every file except the manifest itself). Two
|
|
27
|
+
builds with the same digest render the same project, so an upgrade between
|
|
28
|
+
them has nothing to do; a different digest means the templates changed and the
|
|
29
|
+
upgrade needs the recorded build as its baseline. It is null when ``create``
|
|
30
|
+
rendered more than that snapshot (a seed ``--api-policy``, a local or remote
|
|
31
|
+
template); the upgrade then relies on the build id alone.
|
|
32
|
+
|
|
33
|
+
``scaffold upgrade`` and ``scaffold enhance`` rewrite the block after a merge;
|
|
34
|
+
an in-folder re-render keeps it (it does not update the existing files).
|
|
35
|
+
"""
|
|
36
|
+
|
|
37
|
+
from __future__ import annotations
|
|
38
|
+
|
|
39
|
+
import hashlib
|
|
40
|
+
import logging
|
|
41
|
+
import os
|
|
42
|
+
import pathlib
|
|
43
|
+
import re
|
|
44
|
+
from collections.abc import Mapping
|
|
45
|
+
from dataclasses import dataclass
|
|
46
|
+
from typing import Any
|
|
47
|
+
|
|
48
|
+
import yaml
|
|
49
|
+
|
|
50
|
+
from graph_agents_cli import _build
|
|
51
|
+
|
|
52
|
+
from .keyedit import EditError, YamlText
|
|
53
|
+
|
|
54
|
+
MANIFEST_FILENAME = "graph-agents-cli-manifest.yaml"
|
|
55
|
+
MANIFEST_KEY = "cli_build"
|
|
56
|
+
DIGEST_PREFIX = "sha256:"
|
|
57
|
+
_DIGEST_RE = re.compile(r"sha256:[0-9a-f]{64}")
|
|
58
|
+
_COMMIT_RE = re.compile(r"[0-9a-f]{40}([0-9a-f]{24})?")
|
|
59
|
+
# Never part of a render; skipped so a stray cache cannot change a digest.
|
|
60
|
+
_SKIPPED_DIRS = frozenset({".git", "__pycache__", ".venv", ".ruff_cache", ".pytest_cache"})
|
|
61
|
+
RECORD_COMMENT = (
|
|
62
|
+
"The build that rendered this project and a digest of it; `scaffold upgrade` reads both"
|
|
63
|
+
)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
@dataclass(frozen=True)
|
|
67
|
+
class BuildRecord:
|
|
68
|
+
"""The ``cli_build`` block of a manifest."""
|
|
69
|
+
|
|
70
|
+
id: str
|
|
71
|
+
commit: str | None = None
|
|
72
|
+
template_digest: str | None = None
|
|
73
|
+
|
|
74
|
+
@classmethod
|
|
75
|
+
def of(cls, build: _build.BuildInfo, template_digest: str | None) -> BuildRecord:
|
|
76
|
+
return cls(id=build.id, commit=build.commit, template_digest=template_digest)
|
|
77
|
+
|
|
78
|
+
@property
|
|
79
|
+
def dirty(self) -> bool:
|
|
80
|
+
"""Built from a tree with uncommitted changes: no commit reproduces it."""
|
|
81
|
+
return self.id.endswith(".dirty")
|
|
82
|
+
|
|
83
|
+
@property
|
|
84
|
+
def is_release(self) -> bool:
|
|
85
|
+
"""A release build: its id is the bare version and its commit is known."""
|
|
86
|
+
return self.commit is not None and "+" not in self.id
|
|
87
|
+
|
|
88
|
+
def same_build_as(self, build: _build.BuildInfo) -> bool:
|
|
89
|
+
"""True when this is exactly ``build``: the same id and commit, both without local changes."""
|
|
90
|
+
return (
|
|
91
|
+
self.id == build.id
|
|
92
|
+
and self.commit is not None
|
|
93
|
+
and self.commit == build.commit
|
|
94
|
+
and not self.dirty
|
|
95
|
+
and not build.dirty
|
|
96
|
+
)
|
|
97
|
+
|
|
98
|
+
def as_manifest(self) -> dict[str, Any]:
|
|
99
|
+
return {"id": self.id, "commit": self.commit, "template_digest": self.template_digest}
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def running_build() -> _build.BuildInfo:
|
|
103
|
+
"""The running build, with the version the scaffold engine records.
|
|
104
|
+
|
|
105
|
+
``cli_version`` comes from ``version.get_current_version`` (tests change
|
|
106
|
+
it); the commit facts from :func:`graph_agents_cli._build.current_build`.
|
|
107
|
+
"""
|
|
108
|
+
from . import version as version_module
|
|
109
|
+
|
|
110
|
+
facts = _build.current_build()
|
|
111
|
+
return _build.BuildInfo(
|
|
112
|
+
version=version_module.get_current_version(),
|
|
113
|
+
commit=facts.commit,
|
|
114
|
+
dirty=facts.dirty,
|
|
115
|
+
release=facts.release,
|
|
116
|
+
)
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
class MalformedRecordError(ValueError):
|
|
120
|
+
"""``cli_build`` is present but not a valid record."""
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
def parse_build_record(raw: Any) -> BuildRecord | None:
|
|
124
|
+
"""The record in a manifest's ``cli_build`` value; None when absent.
|
|
125
|
+
|
|
126
|
+
Raises :class:`MalformedRecordError` for a value that is not a valid record,
|
|
127
|
+
so a hand-edited block is reported instead of being trusted.
|
|
128
|
+
"""
|
|
129
|
+
if raw is None:
|
|
130
|
+
return None
|
|
131
|
+
if not isinstance(raw, Mapping):
|
|
132
|
+
raise MalformedRecordError(f"{MANIFEST_KEY} is not a mapping")
|
|
133
|
+
build_id = raw.get("id")
|
|
134
|
+
if not isinstance(build_id, str) or not build_id.strip() or any(c.isspace() for c in build_id):
|
|
135
|
+
raise MalformedRecordError(f"{MANIFEST_KEY}.id is not a build id")
|
|
136
|
+
commit = raw.get("commit")
|
|
137
|
+
if commit is not None and (not isinstance(commit, str) or not _COMMIT_RE.fullmatch(commit)):
|
|
138
|
+
raise MalformedRecordError(f"{MANIFEST_KEY}.commit is not a full git commit")
|
|
139
|
+
digest = raw.get("template_digest")
|
|
140
|
+
if digest is not None and (not isinstance(digest, str) or not _DIGEST_RE.fullmatch(digest)):
|
|
141
|
+
raise MalformedRecordError(f"{MANIFEST_KEY}.template_digest is not a sha256 digest")
|
|
142
|
+
return BuildRecord(id=build_id, commit=commit, template_digest=digest)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def recorded_build_for(config: Any) -> BuildRecord | None:
|
|
146
|
+
"""The build a project's manifest records, when it belongs to its ``cli_version``.
|
|
147
|
+
|
|
148
|
+
``config`` is a ``ProjectConfig``. A record of another version than
|
|
149
|
+
``cli_version`` (the version was edited by hand, or the block copied from
|
|
150
|
+
another project) cannot describe the project: :class:`MalformedRecordError`
|
|
151
|
+
says so, and the caller falls back to the version.
|
|
152
|
+
"""
|
|
153
|
+
record = parse_build_record(config.cli_build)
|
|
154
|
+
if record is not None and record.id.split("+", 1)[0] != config.cli_version:
|
|
155
|
+
raise MalformedRecordError(
|
|
156
|
+
f"{MANIFEST_KEY}.id {record.id!r} is not a build of cli_version {config.cli_version!r}"
|
|
157
|
+
)
|
|
158
|
+
return record
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
def read_manifest_data(project_dir: pathlib.Path) -> dict[str, Any]:
|
|
162
|
+
"""The project's manifest as a mapping ({} when missing or unreadable)."""
|
|
163
|
+
try:
|
|
164
|
+
with open(project_dir / MANIFEST_FILENAME, encoding="utf-8") as f:
|
|
165
|
+
data = yaml.safe_load(f)
|
|
166
|
+
except (OSError, yaml.YAMLError):
|
|
167
|
+
return {}
|
|
168
|
+
return data if isinstance(data, dict) else {}
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
def read_build_record(project_dir: pathlib.Path) -> BuildRecord | None:
|
|
172
|
+
"""The project's recorded build (None when absent; raises when malformed)."""
|
|
173
|
+
return parse_build_record(read_manifest_data(project_dir).get(MANIFEST_KEY))
|
|
174
|
+
|
|
175
|
+
|
|
176
|
+
def template_digest(tree: pathlib.Path) -> str:
|
|
177
|
+
"""A digest of every file of a rendered tree except its manifest.
|
|
178
|
+
|
|
179
|
+
Paths and contents both count (a renamed file changes it); caches and
|
|
180
|
+
``.git`` are skipped. Symbolic links count by their target.
|
|
181
|
+
"""
|
|
182
|
+
entries: list[tuple[str, bytes]] = []
|
|
183
|
+
for dirpath, dirnames, filenames in os.walk(tree):
|
|
184
|
+
dirnames[:] = sorted(d for d in dirnames if d not in _SKIPPED_DIRS)
|
|
185
|
+
for name in filenames:
|
|
186
|
+
path = pathlib.Path(dirpath) / name
|
|
187
|
+
relative = path.relative_to(tree).as_posix()
|
|
188
|
+
if relative == MANIFEST_FILENAME:
|
|
189
|
+
continue
|
|
190
|
+
if path.is_symlink():
|
|
191
|
+
content = b"link:" + os.readlink(path).encode("utf-8", "surrogateescape")
|
|
192
|
+
elif path.is_file():
|
|
193
|
+
content = hashlib.sha256(path.read_bytes()).digest()
|
|
194
|
+
else:
|
|
195
|
+
continue
|
|
196
|
+
entries.append((relative, content))
|
|
197
|
+
digest = hashlib.sha256()
|
|
198
|
+
for relative, content in sorted(entries):
|
|
199
|
+
digest.update(relative.encode("utf-8", "surrogateescape") + b"\0")
|
|
200
|
+
digest.update(content + b"\0")
|
|
201
|
+
return DIGEST_PREFIX + digest.hexdigest()
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def write_build_record(project_dir: pathlib.Path, record: BuildRecord | None) -> None:
|
|
205
|
+
"""Set (or, with None, remove) ``cli_build`` in the project's manifest.
|
|
206
|
+
|
|
207
|
+
The text is edited in place, keeping comments and key order; a manifest the
|
|
208
|
+
edit cannot handle safely is rewritten through the YAML library instead. A
|
|
209
|
+
manifest that cannot be read or written is logged and skipped (callers
|
|
210
|
+
record the build as a side effect of work that already succeeded).
|
|
211
|
+
"""
|
|
212
|
+
path = project_dir / MANIFEST_FILENAME
|
|
213
|
+
try:
|
|
214
|
+
text = path.read_text(encoding="utf-8")
|
|
215
|
+
except OSError as e:
|
|
216
|
+
logging.warning("Could not read %s to record the CLI build: %s", path, e)
|
|
217
|
+
return
|
|
218
|
+
try:
|
|
219
|
+
editor = YamlText(text)
|
|
220
|
+
if record is None:
|
|
221
|
+
if MANIFEST_KEY not in editor.data:
|
|
222
|
+
return
|
|
223
|
+
editor.delete((MANIFEST_KEY,))
|
|
224
|
+
# The comment this module wrote above the block goes with it.
|
|
225
|
+
editor.text = editor.text.replace(f"# {RECORD_COMMENT}\n", "", 1)
|
|
226
|
+
else:
|
|
227
|
+
editor.set(
|
|
228
|
+
(MANIFEST_KEY,),
|
|
229
|
+
record.as_manifest(),
|
|
230
|
+
after="cli_version",
|
|
231
|
+
comment=RECORD_COMMENT,
|
|
232
|
+
block=True,
|
|
233
|
+
)
|
|
234
|
+
new_text = editor.text
|
|
235
|
+
except EditError as e:
|
|
236
|
+
logging.debug("Rewriting %s without its comments: %s", path, e)
|
|
237
|
+
try:
|
|
238
|
+
data = yaml.safe_load(text) or {}
|
|
239
|
+
except yaml.YAMLError as load_error:
|
|
240
|
+
logging.warning(
|
|
241
|
+
"%s is not valid YAML; the CLI build was not recorded: %s", path, load_error
|
|
242
|
+
)
|
|
243
|
+
return
|
|
244
|
+
if not isinstance(data, dict):
|
|
245
|
+
logging.warning("%s is not a mapping; the CLI build was not recorded", path)
|
|
246
|
+
return
|
|
247
|
+
if record is None:
|
|
248
|
+
data.pop(MANIFEST_KEY, None)
|
|
249
|
+
else:
|
|
250
|
+
data[MANIFEST_KEY] = record.as_manifest()
|
|
251
|
+
new_text = yaml.safe_dump(data, default_flow_style=False, sort_keys=False)
|
|
252
|
+
if new_text == text:
|
|
253
|
+
return
|
|
254
|
+
try:
|
|
255
|
+
path.write_text(new_text, encoding="utf-8")
|
|
256
|
+
except OSError as e:
|
|
257
|
+
logging.warning("Could not record the CLI build in %s: %s", path, e)
|
|
@@ -0,0 +1,184 @@
|
|
|
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
|
+
"""Shared Click options for ``create`` and ``scaffold enhance``."""
|
|
17
|
+
|
|
18
|
+
from collections.abc import Callable
|
|
19
|
+
from typing import Any
|
|
20
|
+
|
|
21
|
+
import click
|
|
22
|
+
|
|
23
|
+
from graph_agents_cli._defaults import (
|
|
24
|
+
AUTH_POLICIES,
|
|
25
|
+
CD_MODES,
|
|
26
|
+
CHECKPOINTERS,
|
|
27
|
+
DEFAULT_AGENT_GUIDANCE_FILENAME,
|
|
28
|
+
DEPLOYMENT_TARGETS,
|
|
29
|
+
LEGACY_AUTH_POLICY_ALIASES,
|
|
30
|
+
MODEL_PROVIDERS,
|
|
31
|
+
RUNTIMES,
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class AuthPolicyChoice(click.Choice):
|
|
36
|
+
"""``--auth-policy`` choices; a retired name is refused with a hint to its new name."""
|
|
37
|
+
|
|
38
|
+
def convert(self, value: Any, param: click.Parameter | None, ctx: click.Context | None) -> Any:
|
|
39
|
+
renamed = LEGACY_AUTH_POLICY_ALIASES.get(str(value).strip().lower())
|
|
40
|
+
if renamed:
|
|
41
|
+
self.fail(
|
|
42
|
+
f"'{value}' was renamed to '{renamed}'; use --auth-policy {renamed}.", param, ctx
|
|
43
|
+
)
|
|
44
|
+
return super().convert(value, param, ctx)
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _refuse_product_policy(ctx: click.Context, param: click.Parameter, value: Any) -> None:
|
|
48
|
+
"""``--product-policy`` is the retired name of ``--api-policy``."""
|
|
49
|
+
if value is not None:
|
|
50
|
+
raise click.UsageError(
|
|
51
|
+
"--product-policy was renamed to --api-policy, and the file format changed "
|
|
52
|
+
"(api-policy.yaml declares apis: <name>: ... with required allowed_methods).",
|
|
53
|
+
ctx=ctx,
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def shared_template_options(f: Callable) -> Callable:
|
|
58
|
+
"""Decorator adding the options shared by template-based commands."""
|
|
59
|
+
# Apply options in reverse order since decorators are applied bottom-up
|
|
60
|
+
f = click.option("--debug", is_flag=True, help="Enable debug logging")(f)
|
|
61
|
+
f = click.option(
|
|
62
|
+
"--skip-deps",
|
|
63
|
+
is_flag=True,
|
|
64
|
+
help="Skip base template dependency installation (used when reusing saved config)",
|
|
65
|
+
default=False,
|
|
66
|
+
hidden=True,
|
|
67
|
+
)(f)
|
|
68
|
+
f = click.option(
|
|
69
|
+
"-s",
|
|
70
|
+
"--skip-checks",
|
|
71
|
+
is_flag=True,
|
|
72
|
+
help="Skip preflight checks (uv on PATH)",
|
|
73
|
+
default=False,
|
|
74
|
+
)(f)
|
|
75
|
+
f = click.option(
|
|
76
|
+
"--auto-approve",
|
|
77
|
+
"--yes",
|
|
78
|
+
"-y",
|
|
79
|
+
is_flag=True,
|
|
80
|
+
default=False,
|
|
81
|
+
help="Non-interactive: skip prompts and use defaults",
|
|
82
|
+
)(f)
|
|
83
|
+
f = click.option(
|
|
84
|
+
"--interactive",
|
|
85
|
+
"-i",
|
|
86
|
+
is_flag=True,
|
|
87
|
+
default=False,
|
|
88
|
+
help="Enable interactive prompts for human use",
|
|
89
|
+
)(f)
|
|
90
|
+
f = click.option(
|
|
91
|
+
"--base-template",
|
|
92
|
+
"-bt",
|
|
93
|
+
help="Base template to use (overrides template default, only for remote templates)",
|
|
94
|
+
)(f)
|
|
95
|
+
f = click.option(
|
|
96
|
+
"--agent-guidance-filename",
|
|
97
|
+
default=DEFAULT_AGENT_GUIDANCE_FILENAME,
|
|
98
|
+
show_default=True,
|
|
99
|
+
help="Filename for agent guidance (e.g. AGENTS.md, CLAUDE.md, GEMINI.md)",
|
|
100
|
+
)(f)
|
|
101
|
+
f = click.option(
|
|
102
|
+
"--agent-directory",
|
|
103
|
+
"-dir",
|
|
104
|
+
help="Name of the agent directory (overrides template default)",
|
|
105
|
+
)(f)
|
|
106
|
+
f = click.option(
|
|
107
|
+
"--prototype",
|
|
108
|
+
"-p",
|
|
109
|
+
is_flag=True,
|
|
110
|
+
help=(
|
|
111
|
+
"Minimal project: deployment target defaults to 'none' unless given, "
|
|
112
|
+
"CD is forced to 'skip'"
|
|
113
|
+
),
|
|
114
|
+
default=False,
|
|
115
|
+
)(f)
|
|
116
|
+
f = click.option(
|
|
117
|
+
"--process",
|
|
118
|
+
"process",
|
|
119
|
+
help=(
|
|
120
|
+
"Governing process document (path or string) recorded as process: in the "
|
|
121
|
+
"manifest and rendered into the guidance file"
|
|
122
|
+
),
|
|
123
|
+
)(f)
|
|
124
|
+
f = click.option(
|
|
125
|
+
"--product-policy",
|
|
126
|
+
hidden=True,
|
|
127
|
+
expose_value=False,
|
|
128
|
+
is_eager=True,
|
|
129
|
+
callback=_refuse_product_policy,
|
|
130
|
+
help="Renamed to --api-policy",
|
|
131
|
+
)(f)
|
|
132
|
+
f = click.option(
|
|
133
|
+
"--api-policy",
|
|
134
|
+
"api_policy",
|
|
135
|
+
type=click.Path(exists=True, dir_okay=False, resolve_path=True),
|
|
136
|
+
help=(
|
|
137
|
+
"Seed api-policy.yaml (the outbound APIs tools may call, and how) from this file; "
|
|
138
|
+
"validated before the project is created"
|
|
139
|
+
),
|
|
140
|
+
)(f)
|
|
141
|
+
f = click.option(
|
|
142
|
+
"--auth-policy",
|
|
143
|
+
type=AuthPolicyChoice(list(AUTH_POLICIES)),
|
|
144
|
+
help=(
|
|
145
|
+
"Authentication policy (default: shared-bearer). jwt verifies per-user OIDC "
|
|
146
|
+
"tokens; custom is a fail-closed stub the project implements"
|
|
147
|
+
),
|
|
148
|
+
)(f)
|
|
149
|
+
f = click.option(
|
|
150
|
+
"--cd",
|
|
151
|
+
"cd",
|
|
152
|
+
type=click.Choice(list(CD_MODES)),
|
|
153
|
+
help="Continuous delivery mode (default: skip; requires --deployment-target kubernetes)",
|
|
154
|
+
)(f)
|
|
155
|
+
f = click.option(
|
|
156
|
+
"--registry",
|
|
157
|
+
help="Container registry <url/org> (default: ghcr.io/<git origin owner>)",
|
|
158
|
+
)(f)
|
|
159
|
+
f = click.option(
|
|
160
|
+
"--deployment-target",
|
|
161
|
+
"-d",
|
|
162
|
+
type=click.Choice(list(DEPLOYMENT_TARGETS)),
|
|
163
|
+
help="Deployment target (default: kubernetes)",
|
|
164
|
+
)(f)
|
|
165
|
+
f = click.option(
|
|
166
|
+
"--checkpointer",
|
|
167
|
+
type=click.Choice(list(CHECKPOINTERS)),
|
|
168
|
+
help="Deployed checkpointer (default: postgres for kubernetes, memory for none)",
|
|
169
|
+
)(f)
|
|
170
|
+
f = click.option(
|
|
171
|
+
"--model",
|
|
172
|
+
help="Model name (default: the provider's default model)",
|
|
173
|
+
)(f)
|
|
174
|
+
f = click.option(
|
|
175
|
+
"--model-provider",
|
|
176
|
+
type=click.Choice(list(MODEL_PROVIDERS)),
|
|
177
|
+
help="Model provider (default: openai; prompted in interactive mode)",
|
|
178
|
+
)(f)
|
|
179
|
+
f = click.option(
|
|
180
|
+
"--runtime",
|
|
181
|
+
type=click.Choice(list(RUNTIMES)),
|
|
182
|
+
help="Application runtime (default: fastapi)",
|
|
183
|
+
)(f)
|
|
184
|
+
return f
|
|
@@ -0,0 +1,83 @@
|
|
|
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
|
+
"""Shared filesystem helpers for copying project directories."""
|
|
17
|
+
|
|
18
|
+
import fnmatch
|
|
19
|
+
|
|
20
|
+
# Directories/files to exclude when copying a project tree (backups, local
|
|
21
|
+
# template copies, etc.).
|
|
22
|
+
STANDARD_IGNORE_PATTERNS = frozenset(
|
|
23
|
+
{
|
|
24
|
+
".git",
|
|
25
|
+
".venv",
|
|
26
|
+
"venv",
|
|
27
|
+
"__pycache__",
|
|
28
|
+
".pytest_cache",
|
|
29
|
+
".ruff_cache",
|
|
30
|
+
"node_modules",
|
|
31
|
+
".next",
|
|
32
|
+
"dist",
|
|
33
|
+
"build",
|
|
34
|
+
".DS_Store",
|
|
35
|
+
".vscode",
|
|
36
|
+
".idea",
|
|
37
|
+
"*.egg-info",
|
|
38
|
+
".mypy_cache",
|
|
39
|
+
".ty",
|
|
40
|
+
".coverage",
|
|
41
|
+
"htmlcov",
|
|
42
|
+
".tox",
|
|
43
|
+
".cache",
|
|
44
|
+
# The CLI's run state in a project (pid file, artifacts): rebuilt on demand.
|
|
45
|
+
".graph-agents-cli",
|
|
46
|
+
# `langgraph dev` local state.
|
|
47
|
+
".langgraph_api",
|
|
48
|
+
}
|
|
49
|
+
)
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def standard_ignore_patterns(dir: str, files: list[str]) -> list[str]:
|
|
53
|
+
"""Return the entries in ``files`` to skip when copying a project tree.
|
|
54
|
+
|
|
55
|
+
Matches the signature expected by ``shutil.copytree(ignore=...)``.
|
|
56
|
+
"""
|
|
57
|
+
return _matching(files, STANDARD_IGNORE_PATTERNS)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
# Credentials, dropped on top of the standard patterns when a tree is copied
|
|
61
|
+
# *into another project* rather than kept for its owner. Deliberately not part
|
|
62
|
+
# of the set above: `create_project_backup` is the undo for `enhance` and
|
|
63
|
+
# `upgrade`, both of which merge `.env` from the template, and a generated
|
|
64
|
+
# project gitignores it, so the backup holds the only copy the user has.
|
|
65
|
+
SECRET_IGNORE_PATTERNS = frozenset({".env", ".env.*"})
|
|
66
|
+
|
|
67
|
+
# `.env.*` would otherwise take the documentation along with the secret. These
|
|
68
|
+
# hold no values, and a source that ships one means it to be read.
|
|
69
|
+
ENV_TEMPLATE_NAMES = frozenset({".env.example", ".env.sample", ".env.template"})
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def source_ignore_patterns(dir: str, files: list[str]) -> set[str]:
|
|
73
|
+
"""Return the entries in ``files`` to skip when copying a source tree.
|
|
74
|
+
|
|
75
|
+
A source is published into somebody else's project (an extension being
|
|
76
|
+
vendored, say), so it leaves behind the standard junk and its credentials.
|
|
77
|
+
"""
|
|
78
|
+
patterns = STANDARD_IGNORE_PATTERNS | SECRET_IGNORE_PATTERNS
|
|
79
|
+
return set(_matching(files, patterns)) - ENV_TEMPLATE_NAMES
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _matching(files: list[str], patterns: frozenset[str]) -> list[str]:
|
|
83
|
+
return [f for f in files if any(fnmatch.fnmatch(f, p) for p in patterns)]
|