keystone-cli 0.1.26__tar.gz → 0.1.27__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/PKG-INFO +1 -1
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/pyproject.toml +2 -2
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/auth/token_store.py +44 -1
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/commands/login.py +9 -1
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli.egg-info/PKG-INFO +1 -1
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli.egg-info/SOURCES.txt +1 -0
- keystone_cli-0.1.27/tests/test_config_env_mismatch.py +102 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/setup.cfg +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/__init__.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/__main__.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/_build_env.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/_stdio.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/_version.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/auth/__init__.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/auth/device_flow.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/commands/__init__.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/commands/agent.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/commands/dev.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/commands/kb.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/commands/tool_credentials.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/commands/workspace.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/devloop.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/platform_client.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/runner.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/scaffold.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/README.md.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/agent.yaml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/env.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/gitignore.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/pkg/__init__.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/pkg/graph.py.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/pyproject.toml.tmpl +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli.egg-info/dependency_links.txt +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli.egg-info/entry_points.txt +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli.egg-info/requires.txt +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli.egg-info/top_level.txt +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_agent.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_assistant_provenance_and_flags.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_auth.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_build_progress.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_ci_token.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_deploy.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_dev.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_doctor.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_encoding.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_init.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_invoke.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_login_command.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_offline.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_platform_client.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_publish.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_retire_delete.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_runs.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_status.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_stdio.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_threads.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_tool_credentials.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_traces.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_version.py +0 -0
- {keystone_cli-0.1.26 → keystone_cli-0.1.27}/tests/test_workspace.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: keystone-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.27
|
|
4
4
|
Summary: Keystone pro-code agent CLI — author, validate, and run agents locally, then deploy and invoke them on the Keystone platform.
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Requires-Dist: keystone-agent-sdk<0.11,>=0.10
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "keystone-cli"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.27"
|
|
8
8
|
description = "Keystone pro-code agent CLI — author, validate, and run agents locally, then deploy and invoke them on the Keystone platform."
|
|
9
9
|
requires-python = ">=3.12"
|
|
10
10
|
dependencies = [
|
|
@@ -45,7 +45,7 @@ where = ["src"]
|
|
|
45
45
|
keystone_cli = ["templates/*/*.tmpl", "templates/*/pkg/*.tmpl"]
|
|
46
46
|
|
|
47
47
|
[tool.ruff]
|
|
48
|
-
target-version = "0.1.
|
|
48
|
+
target-version = "0.1.27"
|
|
49
49
|
line-length = 120
|
|
50
50
|
|
|
51
51
|
[tool.ruff.lint]
|
|
@@ -9,6 +9,7 @@ from __future__ import annotations
|
|
|
9
9
|
|
|
10
10
|
import json
|
|
11
11
|
import os
|
|
12
|
+
import sys
|
|
12
13
|
from dataclasses import asdict, dataclass, fields
|
|
13
14
|
from pathlib import Path
|
|
14
15
|
|
|
@@ -85,6 +86,46 @@ class AuthConfig:
|
|
|
85
86
|
env: str = ""
|
|
86
87
|
|
|
87
88
|
|
|
89
|
+
def endpoint_env(cfg: AuthConfig) -> str | None:
|
|
90
|
+
"""Which env's BAKED endpoints this config carries (issuer or api_base match), or None.
|
|
91
|
+
|
|
92
|
+
None for an empty config and for custom endpoints (a deliberate ``--api-base`` / ``--issuer``
|
|
93
|
+
pointing somewhere no env bakes), so only a config that is recognisably ANOTHER env's is flagged.
|
|
94
|
+
"""
|
|
95
|
+
for env, (issuer, api_base, _agent) in _ENV_DEFAULTS.items():
|
|
96
|
+
if (cfg.issuer and cfg.issuer == issuer) or (cfg.api_base and cfg.api_base.rstrip("/") == api_base):
|
|
97
|
+
return env
|
|
98
|
+
return None
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def endpoints_belong_to_other_env(cfg: AuthConfig) -> str | None:
|
|
102
|
+
"""The OTHER env whose endpoints this config carries (vs. this package's ``BUILD_ENV``), else None.
|
|
103
|
+
|
|
104
|
+
FDP-3072: the ``env`` stamp alone is not proof. A config stamped ``env=prod`` can still hold the
|
|
105
|
+
dev issuer/api_base (seen 2026-09-30 after installing the prod package over a dev login): the
|
|
106
|
+
stamp matched, so ``login`` kept the cache and every command silently went to dev.
|
|
107
|
+
"""
|
|
108
|
+
env = endpoint_env(cfg)
|
|
109
|
+
return env if env is not None and env != BUILD_ENV else None
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
_warned_mismatch = False
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def _warn_if_other_env(cfg: AuthConfig) -> None:
|
|
116
|
+
"""One stderr line per process — a warning, never a block (custom endpoints are never flagged)."""
|
|
117
|
+
global _warned_mismatch
|
|
118
|
+
other = endpoints_belong_to_other_env(cfg)
|
|
119
|
+
if other is None or _warned_mismatch:
|
|
120
|
+
return
|
|
121
|
+
_warned_mismatch = True
|
|
122
|
+
print(
|
|
123
|
+
f"⚠ {config_path()} points at the {other} endpoints, but this is the {BUILD_ENV} CLI — "
|
|
124
|
+
f"commands would go to {other}. Run `keystone login` to reset it to {BUILD_ENV}.",
|
|
125
|
+
file=sys.stderr,
|
|
126
|
+
)
|
|
127
|
+
|
|
128
|
+
|
|
88
129
|
def config_path() -> Path:
|
|
89
130
|
"""Config file path. ``KEYSTONE_CONFIG`` overrides (tests); default ``~/.keystone/config.json``."""
|
|
90
131
|
override = os.environ.get("KEYSTONE_CONFIG")
|
|
@@ -100,7 +141,9 @@ def load() -> AuthConfig:
|
|
|
100
141
|
# turned a valid session into "not logged in".
|
|
101
142
|
data = json.loads(path.read_text(encoding="utf-8"))
|
|
102
143
|
known = {f.name for f in fields(AuthConfig)}
|
|
103
|
-
|
|
144
|
+
cfg = AuthConfig(**{k: v for k, v in data.items() if k in known})
|
|
145
|
+
_warn_if_other_env(cfg)
|
|
146
|
+
return cfg
|
|
104
147
|
|
|
105
148
|
|
|
106
149
|
def _ensure_private_dir(directory: Path) -> None:
|
|
@@ -61,7 +61,15 @@ def login(
|
|
|
61
61
|
# cached (no silent wrong-realm). Same env keeps the cache; flags still override.
|
|
62
62
|
cfg = ts.load()
|
|
63
63
|
same_env = (cfg.env == ts.BUILD_ENV) if cfg.env else (not cfg.issuer or cfg.issuer == ts.DEFAULT_ISSUER)
|
|
64
|
-
|
|
64
|
+
# FDP-3072: the stamp can match while the endpoints are another env's (env=prod holding dev URLs).
|
|
65
|
+
# Treat that as cross-env too, or the stale endpoints survive every login.
|
|
66
|
+
stale_env = ts.endpoints_belong_to_other_env(cfg)
|
|
67
|
+
if stale_env is not None:
|
|
68
|
+
typer.secho(
|
|
69
|
+
f" cached config pointed at the {stale_env} endpoints — resetting to the {ts.BUILD_ENV} defaults",
|
|
70
|
+
fg=typer.colors.YELLOW,
|
|
71
|
+
)
|
|
72
|
+
if not same_env or stale_env is not None:
|
|
65
73
|
cfg = ts.AuthConfig()
|
|
66
74
|
cfg.env = ts.BUILD_ENV
|
|
67
75
|
cfg.issuer = issuer or cfg.issuer or ts.DEFAULT_ISSUER
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: keystone-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.27
|
|
4
4
|
Summary: Keystone pro-code agent CLI — author, validate, and run agents locally, then deploy and invoke them on the Keystone platform.
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Requires-Dist: keystone-agent-sdk<0.11,>=0.10
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"""FDP-3072 — a config whose endpoints belong to ANOTHER env than the installed package.
|
|
2
|
+
|
|
3
|
+
Seen 2026-09-30: the prod package over a dev login left ``env=prod`` with the dev issuer and
|
|
4
|
+
api_base; ``keystone login`` kept them (the stamp matched) and every command went to dev, silently.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from __future__ import annotations
|
|
8
|
+
|
|
9
|
+
import json
|
|
10
|
+
|
|
11
|
+
import pytest
|
|
12
|
+
from typer.testing import CliRunner
|
|
13
|
+
|
|
14
|
+
from keystone_cli.__main__ import app
|
|
15
|
+
from keystone_cli.auth import token_store as ts
|
|
16
|
+
|
|
17
|
+
runner = CliRunner()
|
|
18
|
+
|
|
19
|
+
DEV_ISSUER, DEV_API, DEV_AGENT = ts._ENV_DEFAULTS["dev"]
|
|
20
|
+
PROD_ISSUER, PROD_API, PROD_AGENT = ts._ENV_DEFAULTS["prod"]
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@pytest.fixture(autouse=True)
|
|
24
|
+
def _prod_package(tmp_path, monkeypatch):
|
|
25
|
+
"""Pretend the installed package is the prod one, with a private config file."""
|
|
26
|
+
monkeypatch.setenv("KEYSTONE_CONFIG", str(tmp_path / "config.json"))
|
|
27
|
+
monkeypatch.setattr(ts, "BUILD_ENV", "prod")
|
|
28
|
+
monkeypatch.setattr(ts, "DEFAULT_ISSUER", PROD_ISSUER)
|
|
29
|
+
monkeypatch.setattr(ts, "DEFAULT_API_BASE", PROD_API)
|
|
30
|
+
monkeypatch.setattr(ts, "DEFAULT_AGENT_API_BASE", PROD_AGENT)
|
|
31
|
+
monkeypatch.setattr(ts, "_warned_mismatch", False)
|
|
32
|
+
monkeypatch.setattr("keystone_cli.commands.login.pc.get_me", lambda *_a, **_k: {})
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _write(tmp_path, **cfg) -> None:
|
|
36
|
+
(tmp_path / "config.json").write_text(json.dumps(cfg), encoding="utf-8")
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_endpoint_env_recognises_baked_hosts_only() -> None:
|
|
40
|
+
assert ts.endpoint_env(ts.AuthConfig(issuer=DEV_ISSUER, api_base=DEV_API)) == "dev"
|
|
41
|
+
assert ts.endpoint_env(ts.AuthConfig(api_base=PROD_API + "/")) == "prod"
|
|
42
|
+
assert ts.endpoint_env(ts.AuthConfig(api_base="http://localhost:8080")) is None # custom → never flagged
|
|
43
|
+
assert ts.endpoint_env(ts.AuthConfig()) is None
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
def test_load_warns_once_when_endpoints_are_another_envs(tmp_path, capsys) -> None:
|
|
47
|
+
_write(tmp_path, env="prod", issuer=DEV_ISSUER, api_base=DEV_API, agent_api_base=DEV_AGENT)
|
|
48
|
+
|
|
49
|
+
ts.load()
|
|
50
|
+
ts.load()
|
|
51
|
+
|
|
52
|
+
err = capsys.readouterr().err
|
|
53
|
+
assert err.count("points at the dev endpoints") == 1
|
|
54
|
+
assert "keystone login" in err
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@pytest.mark.parametrize(
|
|
58
|
+
"cfg",
|
|
59
|
+
[
|
|
60
|
+
{"env": "prod", "issuer": PROD_ISSUER, "api_base": PROD_API},
|
|
61
|
+
{"env": "prod", "issuer": "https://kc.local/realms/x", "api_base": "http://localhost:8080"},
|
|
62
|
+
],
|
|
63
|
+
)
|
|
64
|
+
def test_load_is_silent_for_matching_or_custom_endpoints(tmp_path, capsys, cfg) -> None:
|
|
65
|
+
_write(tmp_path, **cfg)
|
|
66
|
+
ts.load()
|
|
67
|
+
assert capsys.readouterr().err == ""
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_login_resets_a_prod_stamped_config_holding_dev_endpoints(tmp_path, monkeypatch) -> None:
|
|
71
|
+
_write(
|
|
72
|
+
tmp_path,
|
|
73
|
+
env="prod",
|
|
74
|
+
issuer=DEV_ISSUER,
|
|
75
|
+
api_base=DEV_API,
|
|
76
|
+
agent_api_base=DEV_AGENT,
|
|
77
|
+
workspace_id="dev-ws",
|
|
78
|
+
workspace_name="default-workspace",
|
|
79
|
+
)
|
|
80
|
+
monkeypatch.setattr(
|
|
81
|
+
"keystone_cli.commands.login.df.start_device_flow",
|
|
82
|
+
lambda *_a, **_k: {
|
|
83
|
+
"device_code": "dc",
|
|
84
|
+
"user_code": "WXYZ",
|
|
85
|
+
"verification_uri": "https://kc/device",
|
|
86
|
+
"interval": 1,
|
|
87
|
+
"expires_in": 600,
|
|
88
|
+
},
|
|
89
|
+
)
|
|
90
|
+
monkeypatch.setattr(
|
|
91
|
+
"keystone_cli.commands.login.df.poll_for_token",
|
|
92
|
+
lambda *_a, **_k: {"access_token": "at", "refresh_token": "rt", "expires_in": 300},
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
result = runner.invoke(app, ["login", "--no-browser", "--no-select-workspace"])
|
|
96
|
+
|
|
97
|
+
assert result.exit_code == 0, result.output
|
|
98
|
+
assert "pointed at the dev endpoints" in result.output
|
|
99
|
+
saved = json.loads((tmp_path / "config.json").read_text(encoding="utf-8"))
|
|
100
|
+
assert saved["env"] == "prod"
|
|
101
|
+
assert (saved["issuer"], saved["api_base"], saved["agent_api_base"]) == (PROD_ISSUER, PROD_API, PROD_AGENT)
|
|
102
|
+
assert saved["workspace_id"] == "" # the dev workspace must not survive into prod
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/agent.yaml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/pkg/__init__.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/blank/pyproject.toml.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/README.md.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/agent.yaml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/gitignore.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/guardrails/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/pkg/__init__.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/hitl/pyproject.toml.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/README.md.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/agent.yaml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/gitignore.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/kb-builder/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/pkg/__init__.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm/pyproject.toml.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/README.md.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/agent.yaml.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/env.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/llm-streaming/gitignore.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/README.md.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/agent.yaml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/gitignore.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/pkg/__init__.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory/pyproject.toml.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/README.md.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/env.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/memory-service/gitignore.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/README.md.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/agent.yaml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/gitignore.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/pkg/__init__.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/rag-qa/pyproject.toml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/agent.yaml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/pkg/__init__.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/skill/pyproject.toml.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/README.md.tmpl
RENAMED
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/agent.yaml.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/gitignore.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
{keystone_cli-0.1.26 → keystone_cli-0.1.27}/src/keystone_cli/templates/tool-agent/pkg/graph.py.tmpl
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|