buildai-cli 0.3.30__tar.gz → 0.3.32__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.
Files changed (45) hide show
  1. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/CLAUDE.md +4 -5
  2. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/PKG-INFO +1 -1
  3. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/database.py +0 -1
  4. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/dev.py +23 -5
  5. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/search.py +1 -2
  6. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/context.py +4 -3
  7. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/dev_context.py +24 -6
  8. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/ops_init.py +10 -11
  9. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/pyproject.toml +1 -1
  10. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/.gitignore +0 -0
  11. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/AGENTS.md +0 -0
  12. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/__init__.py +0 -0
  13. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/_has_core.py +0 -0
  14. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/__init__.py +0 -0
  15. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/api_proxy.py +0 -0
  16. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/assets_cli.py +0 -0
  17. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/auth_lite.py +0 -0
  18. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/clips.py +0 -0
  19. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/embed.py +0 -0
  20. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/external.py +0 -0
  21. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/inference.py +0 -0
  22. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/jobs.py +0 -0
  23. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/keys.py +0 -0
  24. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/medoid.py +0 -0
  25. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/operations.py +0 -0
  26. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/partners.py +0 -0
  27. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/permissions.py +1 -1
  28. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/projection.py +0 -0
  29. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/query.py +0 -0
  30. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/query_api.py +0 -0
  31. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/reports.py +0 -0
  32. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/schema.py +0 -0
  33. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/stats.py +0 -0
  34. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/sync/ddl.py +0 -0
  35. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/sync/models.py +0 -0
  36. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/commands/sync/queries.py +0 -0
  37. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/config.py +0 -0
  38. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/console.py +0 -0
  39. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/guard.py +0 -0
  40. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/main.py +0 -0
  41. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/nl_query/__init__.py +0 -0
  42. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/nl_query/dataset_tools.py +0 -0
  43. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/output.py +0 -0
  44. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/pagination.py +0 -0
  45. {buildai_cli-0.3.30 → buildai_cli-0.3.32}/cli/sdk_client.py +0 -0
@@ -19,7 +19,7 @@ buildai admin schema describe core.clips # Table details
19
19
  uv run buildai dev use local # Set this worktree's deployment profile
20
20
  uv run buildai dev current # Show resolved worktree target
21
21
  buildai admin --write database migrate all # Run migrations
22
- buildai admin database diff --from preview --to production # Migration delta
22
+ buildai admin database status # Migration status
23
23
  ```
24
24
 
25
25
  ## Guards
@@ -28,10 +28,9 @@ buildai admin database diff --from preview --to production # Migration delta
28
28
  - Writes require `--write` flag.
29
29
  - Production migrations prompt for confirmation.
30
30
  - Worktree app/runtime targeting comes from `uv run buildai dev use <profile>`.
31
- - `buildai admin --env` selects the explicit DB lane: `production`, `preview`, `dev`.
32
- - Do not confuse `--env preview` with the deployment profiles `local`, `preview`, or `staging`.
31
+ - `buildai admin --env` selects the explicit DB lane: `production`, `dev`.
33
32
 
34
33
  ## Reference
35
34
 
36
- CLI mode guide: `docs/how-to/choose-buildai-mode.md`
37
- Database roles: `docs/database-roles.md`
35
+ CLI mode guide: docs site Engineering section (run `make docs`)
36
+ Database roles: docs site Operations section (run `make docs`)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: buildai-cli
3
- Version: 0.3.30
3
+ Version: 0.3.32
4
4
  Summary: Build AI CLI (Typer)
5
5
  Requires-Python: >=3.11
6
6
  Requires-Dist: buildai-data
@@ -19,7 +19,6 @@ All database operations under one command group:
19
19
 
20
20
  import asyncio
21
21
  import json
22
- import os
23
22
  import subprocess
24
23
  from dataclasses import dataclass
25
24
  from pathlib import Path
@@ -170,7 +170,9 @@ def use(
170
170
 
171
171
  success(f"Saved worktree context to {context_path}")
172
172
  if preview_name and context.get("branch"):
173
- info(f"Saved preview alias `{preview_name}` for branch `{context['branch']}` in local git config.")
173
+ info(
174
+ f"Saved preview alias `{preview_name}` for branch `{context['branch']}` in local git config."
175
+ )
174
176
  info('Run `eval "$(uv run buildai dev env)"` in your shell to export it immediately.')
175
177
 
176
178
 
@@ -181,7 +183,9 @@ def claim_preview(
181
183
  "--name",
182
184
  help="Public preview alias to bind. Defaults to the saved preview_name or branch slug.",
183
185
  ),
184
- force: bool = typer.Option(False, "--force", help="Reassign an existing alias or branch binding."),
186
+ force: bool = typer.Option(
187
+ False, "--force", help="Reassign an existing alias or branch binding."
188
+ ),
185
189
  ) -> None:
186
190
  """Publish this worktree's preview alias binding into the external preview registry."""
187
191
  context = load_dev_context()
@@ -194,14 +198,28 @@ def claim_preview(
194
198
  error("Current worktree branch is unknown. Commit or check out the branch first.")
195
199
  raise typer.Exit(1)
196
200
 
197
- preview_name = (name or "").strip() or get_branch_preview_name(branch) or str(context.get("preview_env_id") or "").strip()
201
+ preview_name = (
202
+ (name or "").strip()
203
+ or get_branch_preview_name(branch)
204
+ or str(context.get("preview_env_id") or "").strip()
205
+ )
198
206
  if not preview_name:
199
- error("No preview alias available. Pass --name or save one with `uv run buildai dev use --preview-name ...`.")
207
+ error(
208
+ "No preview alias available. Pass --name or save one with `uv run buildai dev use --preview-name ...`."
209
+ )
200
210
  raise typer.Exit(1)
201
211
 
202
212
  repo_root = Path(__file__).resolve().parents[4]
203
213
  script = repo_root / "scripts" / "infra" / "preview_registry.py"
204
- cmd = [os.getenv("PYTHON", "python"), str(script), "bind", "--branch", branch, "--env-id", preview_name]
214
+ cmd = [
215
+ os.getenv("PYTHON", "python"),
216
+ str(script),
217
+ "bind",
218
+ "--branch",
219
+ branch,
220
+ "--env-id",
221
+ preview_name,
222
+ ]
205
223
  if force:
206
224
  cmd.append("--force")
207
225
 
@@ -102,8 +102,7 @@ def text(
102
102
  else:
103
103
  for i, hit in enumerate(hits, 1):
104
104
  console.print(
105
- f" {i}. score={hit.score:.4f} clip={hit.clip_id} "
106
- f"factory={hit.factory_id or '—'}"
105
+ f" {i}. score={hit.score:.4f} clip={hit.clip_id} factory={hit.factory_id or '—'}"
107
106
  )
108
107
 
109
108
 
@@ -22,9 +22,10 @@ from dataclasses import dataclass
22
22
  from typing import TYPE_CHECKING, AsyncGenerator
23
23
 
24
24
  import asyncpg
25
- from infra import Database, get_logger
26
25
  from infra.settings import Settings, get_settings
27
26
 
27
+ from infra import Database, get_logger
28
+
28
29
  if TYPE_CHECKING:
29
30
  from dal.context import Context
30
31
 
@@ -85,14 +86,14 @@ def resolve_admin_connection_config(
85
86
  deployment profile, then the production password fallback already used by
86
87
  privileged database commands.
87
88
  """
88
- from infra.deployment_profiles import deployment_profile_for_app_env, resolve_deployment_profile
89
+ from infra.deployment_profiles import resolve_deployment_profile
89
90
 
90
91
  admin_iam_user = settings.effective_alloydb_admin_iam_user
91
92
  admin_impersonate_sa = settings.effective_alloydb_admin_impersonate_sa
92
93
 
93
94
  if not admin_iam_user or not admin_impersonate_sa:
94
95
  try:
95
- profile_name = deployment_profile_for_app_env(settings.app_env.value)
96
+ profile_name = os.environ.get("BUILDAI_DEPLOYMENT_PROFILE", "production")
96
97
  profile = resolve_deployment_profile(profile_name)
97
98
  if profile.database_admin:
98
99
  admin_iam_user = admin_iam_user or profile.database_admin.iam_user
@@ -2,8 +2,10 @@
2
2
 
3
3
  from __future__ import annotations
4
4
 
5
+ import hashlib
5
6
  import json
6
7
  import os
8
+ import re
7
9
  import shlex
8
10
  import subprocess
9
11
  from datetime import datetime, timezone
@@ -12,10 +14,23 @@ from typing import Any
12
14
 
13
15
  from infra.deployment_profiles import (
14
16
  list_deployment_profiles,
15
- normalize_preview_env_id,
16
17
  resolve_deployment_profile,
17
18
  )
18
19
 
20
+ _PREVIEW_ENV_ID_MAX_LEN = 26
21
+
22
+
23
+ def _normalize_env_id(branch_name: str) -> str:
24
+ """Normalize a branch name into a DNS-safe env id (max 26 chars)."""
25
+ slug = re.sub(r"[^a-z0-9]+", "-", branch_name.lower()).strip("-")
26
+ if not slug:
27
+ slug = "preview"
28
+ if len(slug) <= _PREVIEW_ENV_ID_MAX_LEN:
29
+ return slug
30
+ digest = hashlib.sha256(branch_name.encode()).hexdigest()[:8]
31
+ return f"{slug[: _PREVIEW_ENV_ID_MAX_LEN - 1 - len(digest)]}-{digest}".rstrip("-")
32
+
33
+
19
34
  DEV_CONTEXT_DIRNAME = ".buildai"
20
35
  DEV_CONTEXT_FILENAME = "context.json"
21
36
  DEV_CONTEXT_SUMMARY_FILENAME = "context.md"
@@ -90,15 +105,19 @@ def get_branch_preview_name(branch: str | None, start_path: Path | None = None)
90
105
  return None
91
106
  cwd = (start_path or Path.cwd()).resolve()
92
107
  value = _git_output(["config", "--local", "--get", f"branch.{branch}.buildaiPreviewName"], cwd)
93
- return normalize_preview_env_id(value) if value else None
108
+ return _normalize_env_id(value) if value else None
94
109
 
95
110
 
96
- def set_branch_preview_name(branch: str | None, preview_name: str, start_path: Path | None = None) -> None:
111
+ def set_branch_preview_name(
112
+ branch: str | None,
113
+ preview_name: str,
114
+ start_path: Path | None = None,
115
+ ) -> None:
97
116
  """Persist one branch-local preview alias into local git config."""
98
117
  if not branch:
99
118
  raise RuntimeError("Cannot save preview alias without an active git branch.")
100
119
  cwd = (start_path or Path.cwd()).resolve()
101
- normalized = normalize_preview_env_id(preview_name)
120
+ normalized = _normalize_env_id(preview_name)
102
121
  subprocess.run(
103
122
  ["git", "config", "--local", f"branch.{branch}.buildaiPreviewName", normalized],
104
123
  cwd=str(cwd),
@@ -129,7 +148,7 @@ def _repo_metadata(start_path: Path | None = None) -> dict[str, Any]:
129
148
  cwd = (start_path or Path.cwd()).resolve()
130
149
  branch = _git_output(["branch", "--show-current"], cwd) if repo_root else None
131
150
  commit_sha = _git_output(["rev-parse", "HEAD"], cwd) if repo_root else None
132
- preview_env_id = normalize_preview_env_id(branch) if branch else None
151
+ preview_env_id = _normalize_env_id(branch) if branch else None
133
152
  return {
134
153
  "repo_root": str(repo_root) if repo_root else None,
135
154
  "worktree_path": str(cwd),
@@ -145,7 +164,6 @@ def _profile_defaults(profile: str, metadata: dict[str, Any]) -> dict[str, Any]:
145
164
  resolved = resolve_deployment_profile(
146
165
  profile,
147
166
  env_id=env_id,
148
- override_key=metadata.get("branch"),
149
167
  )
150
168
  return {
151
169
  "deployment_profile": resolved.name,
@@ -11,7 +11,7 @@ import os
11
11
  from enum import Enum
12
12
 
13
13
  import typer
14
- from infra.deployment_profiles import deployment_profile_for_app_env, resolve_deployment_profile
14
+ from infra.deployment_profiles import resolve_deployment_profile
15
15
 
16
16
  from cli.console import error, info, warning
17
17
 
@@ -59,11 +59,6 @@ def _apply_context_database_target(
59
59
  if isinstance(context, dict) and context.get("preview_env_id")
60
60
  else None
61
61
  ),
62
- override_key=(
63
- str(context.get("branch")).strip()
64
- if isinstance(context, dict) and context.get("branch")
65
- else None
66
- ),
67
62
  )
68
63
  database_target = resolved_profile.database_target.as_context_dict()
69
64
  runtime_target["region"] = resolved_profile.runtime_region
@@ -142,10 +137,11 @@ def init_ops_context(ctx: typer.Context):
142
137
 
143
138
  require_core("this command")
144
139
 
145
- from infra import init_observability
146
140
  from infra.auth import AuthError, get_effective_user_for_iam, validate_auth_config
147
141
  from infra.settings import Environment, ExecutionContext, Settings, get_settings
148
142
 
143
+ from infra import init_observability
144
+
149
145
  verbose = ctx.obj.get("_verbose", False)
150
146
  log_level = logging.DEBUG if verbose else logging.WARNING
151
147
  init_observability("cli", log_level=log_level, enable_json_logs=False)
@@ -161,8 +157,7 @@ def init_ops_context(ctx: typer.Context):
161
157
  app_env = Environment(_parse_env(env_flag))
162
158
  except ValueError:
163
159
  error(
164
- f"Invalid environment '{env_flag}'. "
165
- "Valid: development, preview, production, test."
160
+ f"Invalid environment '{env_flag}'. Valid: development, preview, production, test."
166
161
  )
167
162
  raise typer.Exit(1)
168
163
  else:
@@ -189,10 +184,14 @@ def init_ops_context(ctx: typer.Context):
189
184
  os.environ["BUILDAI_PREVIEW_ENV_ID"] = preview_env_id.strip()
190
185
  if env_flag is not None:
191
186
  deployment_profile = (
192
- "" if app_env == Environment.TEST else deployment_profile_for_app_env(app_env.value)
187
+ ""
188
+ if app_env == Environment.TEST
189
+ else "local"
190
+ if app_env == Environment.DEVELOPMENT
191
+ else "production"
193
192
  )
194
193
  elif deployment_profile is None and app_env != Environment.TEST:
195
- deployment_profile = deployment_profile_for_app_env(app_env.value)
194
+ deployment_profile = "local" if app_env == Environment.DEVELOPMENT else "production"
196
195
  if deployment_profile:
197
196
  os.environ["BUILDAI_DEPLOYMENT_PROFILE"] = deployment_profile
198
197
  _apply_context_database_target(workspace_context, deployment_profile=deployment_profile)
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "buildai-cli"
7
- version = "0.3.30"
7
+ version = "0.3.32"
8
8
  description = "Build AI CLI (Typer)"
9
9
  requires-python = ">=3.11"
10
10
  dependencies = [
File without changes
File without changes
@@ -5,13 +5,13 @@ from pathlib import Path
5
5
  from typing import Any
6
6
 
7
7
  import typer
8
- from infra import permissions as perm_mod
9
8
  from infra.settings import Settings
10
9
  from typing_extensions import Annotated
11
10
 
12
11
  from cli.config import resolve_cli_profile
13
12
  from cli.console import console, error, info, success, warning
14
13
  from cli.context import get_connection
14
+ from infra import permissions as perm_mod
15
15
 
16
16
  app = typer.Typer(name="permissions", help="Permission preflight checks", no_args_is_help=True)
17
17
 
File without changes
File without changes
File without changes
File without changes