levain-cli 0.1.11__tar.gz → 0.1.14__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.
- {levain_cli-0.1.11 → levain_cli-0.1.14}/PKG-INFO +2 -2
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/cli.py +85 -4
- {levain_cli-0.1.11 → levain_cli-0.1.14}/pyproject.toml +2 -2
- {levain_cli-0.1.11 → levain_cli-0.1.14}/.gitignore +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/LICENSE +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/README.md +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/__init__.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/__main__.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/_format.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/_java.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/auth.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/codegen.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/graph.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/integrations_check.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/known_recipes.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/mcp.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/models.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/parser.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/profile.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/py.typed +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/reducers.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/source_check.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/tlc.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/translate.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/user_input.py +0 -0
- {levain_cli-0.1.11 → levain_cli-0.1.14}/levain_recipe/validate.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: levain-cli
|
|
3
|
-
Version: 0.1.
|
|
3
|
+
Version: 0.1.14
|
|
4
4
|
Summary: Levain recipe toolchain: PlusCal validator, TLC model checking, and GraphState codegen for agent recipes
|
|
5
5
|
License-Expression: Apache-2.0
|
|
6
6
|
License-File: LICENSE
|
|
@@ -9,7 +9,7 @@ Requires-Dist: httpx==0.28.1
|
|
|
9
9
|
Requires-Dist: pydantic==2.13.4
|
|
10
10
|
Requires-Dist: tree-sitter-tlaplus==1.5.0
|
|
11
11
|
Requires-Dist: tree-sitter==0.26.0
|
|
12
|
-
Requires-Dist: typer==0.27.
|
|
12
|
+
Requires-Dist: typer==0.27.3
|
|
13
13
|
Provides-Extra: mcp
|
|
14
14
|
Requires-Dist: fastmcp==4.0.5; extra == 'mcp'
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
@@ -337,14 +337,28 @@ def git_credential_cmd(
|
|
|
337
337
|
raise typer.Exit(1)
|
|
338
338
|
scope, slug = repo
|
|
339
339
|
|
|
340
|
+
# A ``workspace-<slug>`` repo in a workspace org is an agent's
|
|
341
|
+
# durable workspace, minted on a dedicated route. An agent whose
|
|
342
|
+
# own slug carries the prefix shadows it, so the recipe route is
|
|
343
|
+
# tried first and the workspace route is the 404 fallback.
|
|
344
|
+
mint_paths = [f"{api_base()}/api/v1/{scope}/{slug}/git-credential"]
|
|
345
|
+
if scope == "agents" and slug.startswith("workspace-"):
|
|
346
|
+
mint_paths.append(
|
|
347
|
+
f"{api_base()}/api/v1/agents/"
|
|
348
|
+
f"{slug.removeprefix('workspace-')}/workspace/git-credential"
|
|
349
|
+
)
|
|
350
|
+
|
|
340
351
|
api = api_base()
|
|
341
352
|
try:
|
|
342
353
|
with _client() as client:
|
|
343
354
|
token = access_token(api, client)
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
355
|
+
for mint_path in mint_paths:
|
|
356
|
+
resp = client.post(
|
|
357
|
+
mint_path,
|
|
358
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
359
|
+
)
|
|
360
|
+
if resp.status_code != 404:
|
|
361
|
+
break
|
|
348
362
|
except AuthError as exc:
|
|
349
363
|
print(f"levain git-credential: {exc}", file=sys.stderr)
|
|
350
364
|
raise typer.Exit(1) from None
|
|
@@ -378,3 +392,70 @@ def _repo_from_git_path(path: str) -> tuple[str, str] | None:
|
|
|
378
392
|
else:
|
|
379
393
|
return None
|
|
380
394
|
return scope, repo.removesuffix(".git")
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
# ── Inbound webhooks ──────────────────────────────────────
|
|
398
|
+
|
|
399
|
+
|
|
400
|
+
webhook_app = typer.Typer(
|
|
401
|
+
name="webhook",
|
|
402
|
+
help="Manage an agent's inbound webhook.",
|
|
403
|
+
add_completion=False,
|
|
404
|
+
)
|
|
405
|
+
app.add_typer(webhook_app)
|
|
406
|
+
|
|
407
|
+
|
|
408
|
+
def _webhook_request(method: str, path: str) -> None:
|
|
409
|
+
from .auth import AuthError, access_token, api_base
|
|
410
|
+
|
|
411
|
+
api = api_base()
|
|
412
|
+
try:
|
|
413
|
+
with _client() as client:
|
|
414
|
+
token = access_token(api, client)
|
|
415
|
+
resp = client.request(
|
|
416
|
+
method,
|
|
417
|
+
f"{api}{path}",
|
|
418
|
+
headers={"Authorization": f"Bearer {token}"},
|
|
419
|
+
)
|
|
420
|
+
except AuthError as exc:
|
|
421
|
+
print(f"Error: {exc}", file=sys.stderr)
|
|
422
|
+
raise typer.Exit(1) from None
|
|
423
|
+
if resp.status_code >= 400:
|
|
424
|
+
try:
|
|
425
|
+
detail = resp.json().get("detail")
|
|
426
|
+
except ValueError:
|
|
427
|
+
detail = None
|
|
428
|
+
suffix = f" — {detail}" if detail else ""
|
|
429
|
+
print(f"Error: HTTP {resp.status_code}{suffix}", file=sys.stderr)
|
|
430
|
+
raise typer.Exit(1)
|
|
431
|
+
print(json.dumps(resp.json(), indent=2))
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
@webhook_app.command("create")
|
|
435
|
+
def webhook_create_cmd(
|
|
436
|
+
agent: Annotated[str, typer.Argument(help="Agent id or slug.")],
|
|
437
|
+
) -> None:
|
|
438
|
+
"""Create the agent's inbound webhook.
|
|
439
|
+
|
|
440
|
+
Prints the webhook once, including the URL with its embedded
|
|
441
|
+
secret — store it; it cannot be retrieved later. POST a JSON body
|
|
442
|
+
to the URL to dispatch a run of the agent, or include a top-level
|
|
443
|
+
``session_id`` to take a turn on an existing session.
|
|
444
|
+
"""
|
|
445
|
+
_webhook_request("POST", f"/api/v1/agents/{agent}/webhooks")
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
@webhook_app.command("rotate")
|
|
449
|
+
def webhook_rotate_cmd(
|
|
450
|
+
agent: Annotated[str, typer.Argument(help="Agent id or slug.")],
|
|
451
|
+
) -> None:
|
|
452
|
+
"""Rotate the webhook secret and print the fresh URL (shown once)."""
|
|
453
|
+
_webhook_request("POST", f"/api/v1/agents/{agent}/webhooks/rotate")
|
|
454
|
+
|
|
455
|
+
|
|
456
|
+
@webhook_app.command("delete")
|
|
457
|
+
def webhook_delete_cmd(
|
|
458
|
+
agent: Annotated[str, typer.Argument(help="Agent id or slug.")],
|
|
459
|
+
) -> None:
|
|
460
|
+
"""Delete the agent's inbound webhook."""
|
|
461
|
+
_webhook_request("DELETE", f"/api/v1/agents/{agent}/webhooks")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "levain-cli"
|
|
3
|
-
version = "0.1.
|
|
3
|
+
version = "0.1.14"
|
|
4
4
|
description = "Levain recipe toolchain: PlusCal validator, TLC model checking, and GraphState codegen for agent recipes"
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = "Apache-2.0"
|
|
@@ -27,7 +27,7 @@ dependencies = [
|
|
|
27
27
|
"tree-sitter==0.26.0",
|
|
28
28
|
"tree-sitter-tlaplus==1.5.0",
|
|
29
29
|
"pydantic==2.13.4",
|
|
30
|
-
"typer==0.27.
|
|
30
|
+
"typer==0.27.3",
|
|
31
31
|
# Sign-in and credential minting. Imported lazily so validation
|
|
32
32
|
# never pays for it.
|
|
33
33
|
"httpx==0.28.1",
|
|
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
|