Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -645,7 +645,7 @@ Session management:

```bash
browser-cli session create
browser-cli session create --create-context
browser-cli session create --create-context --context-description "Office login context"
browser-cli session create --context-id <context_id> --context-mode read_write
browser-cli session create --context-metadata-json '{"purpose":"codex-login"}' --context-selection newest --create-context-if-missing
browser-cli session list --status active
Expand All @@ -658,7 +658,7 @@ Context management:

```bash
browser-cli context create
browser-cli context create --metadata-json '{"purpose":"codex"}'
browser-cli context create --description "Office login context" --metadata-json '{"purpose":"codex"}'
browser-cli context list --metadata-json '{"purpose":"codex-login"}' --selection newest --include-reuse-state
browser-cli context get --context-id <context_id>
browser-cli context status --context-id <context_id>
Expand Down
2 changes: 1 addition & 1 deletion SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ browser-cli commands --workflow persistent_login_state
Then use the returned context-selection steps, typically:

```bash
browser-cli context create
browser-cli context create --description "Office login context"
browser-cli context status --context-id <context_id>
browser-cli session create --context-id <context_id> --context-mode read_write
browser-cli session create --context-metadata-json '{"purpose":"codex-login"}' --context-selection newest --create-context-if-missing --context-mode read_write
Expand Down
2 changes: 1 addition & 1 deletion browser_cli/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

__all__ = ["__version__"]

__version__ = "0.3.7"
__version__ = "0.3.8"
4 changes: 2 additions & 2 deletions browser_cli/agent_skill/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -288,7 +288,7 @@ browser-cli commands --workflow persistent_login_state
Then use the returned context-selection steps, typically:

```bash
browser-cli context create
browser-cli context create --description "Office login context"
browser-cli context status --context-id <context_id>
browser-cli session create --context-id <context_id> --context-mode read_write
browser-cli session create --context-metadata-json '{"purpose":"codex-login"}' --context-selection newest --create-context-if-missing --context-mode read_write
Expand Down Expand Up @@ -403,7 +403,7 @@ browser-cli session keepalive --session-id <session_id>
Context lifecycle:

```bash
browser-cli context create
browser-cli context create --description "Office login context"
browser-cli context list --metadata-json '{"purpose":"codex-login"}' --selection newest --include-reuse-state
browser-cli context get --context-id <context_id>
browser-cli context status --context-id <context_id>
Expand Down
49 changes: 39 additions & 10 deletions browser_cli/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -8167,6 +8167,7 @@ def _select_or_create_context_for_session(
*,
command: str,
metadata_filter: dict[str, Any],
description: str | None = None,
status: str | None,
limit: int,
selection_strategy: str,
Expand Down Expand Up @@ -8221,7 +8222,10 @@ def _select_or_create_context_for_session(

if create_if_missing:
try:
context = admin.create_context(metadata=metadata_filter or None)
context_kwargs: dict[str, Any] = {"metadata": metadata_filter or None}
if description is not None:
context_kwargs["description"] = description
context = admin.create_context(**context_kwargs)
except Exception as exc:
_failure_from_exception(command, exc)
created_context = _model_payload(context)
Expand Down Expand Up @@ -11127,6 +11131,7 @@ def cmd_session_create(args: argparse.Namespace) -> None:
admin,
command=command,
metadata_filter=context_metadata_filter,
description=args.context_description,
status=args.context_status,
limit=args.context_limit,
selection_strategy=args.context_selection,
Expand All @@ -11142,13 +11147,16 @@ def cmd_session_create(args: argparse.Namespace) -> None:
context_reuse=context_reuse,
)

result = admin.create_session(
context_id=context_id,
create_context=create_context,
context_mode=args.context_mode,
browser_mode=args.browser_mode,
metadata=args.metadata,
)
session_kwargs: dict[str, Any] = {
"context_id": context_id,
"create_context": create_context,
"context_mode": args.context_mode,
"browser_mode": args.browser_mode,
"metadata": args.metadata,
}
if args.context_description is not None:
session_kwargs["context_description"] = args.context_description
result = admin.create_session(**session_kwargs)
except Exception as exc:
_failure_from_exception(command, exc)
payload = _model_payload(result)
Expand Down Expand Up @@ -11206,7 +11214,10 @@ def cmd_session_keepalive(args: argparse.Namespace) -> None:
def cmd_context_create(args: argparse.Namespace) -> None:
command = "context.create"
try:
context = LexmountBrowserAdmin().create_context(metadata=args.metadata)
context_kwargs: dict[str, Any] = {"metadata": args.metadata}
if args.description is not None:
context_kwargs["description"] = args.description
context = LexmountBrowserAdmin().create_context(**context_kwargs)
except Exception as exc:
_failure_from_exception(command, exc)
payload = _model_payload(context)
Expand Down Expand Up @@ -11376,7 +11387,10 @@ def cmd_context_pick(args: argparse.Namespace) -> None:

if args.create_if_missing:
try:
context = admin.create_context(metadata=metadata_filter or None)
context_kwargs: dict[str, Any] = {"metadata": metadata_filter or None}
if args.description is not None:
context_kwargs["description"] = args.description
context = admin.create_context(**context_kwargs)
except Exception as exc:
_failure_from_exception(command, exc)
created_context = _model_payload(context)
Expand Down Expand Up @@ -29856,6 +29870,13 @@ def _add_session_create_args(parser: argparse.ArgumentParser) -> None:
default="read_write",
type=_normalize_context_mode,
)
parser.add_argument(
"--context-description",
help=(
"Optional UTF-8 description for a newly created context when using "
"--create-context or --create-context-if-missing."
),
)
parser.add_argument(
"--browser-mode",
default="normal",
Expand Down Expand Up @@ -29972,6 +29993,10 @@ def _add_context_commands(subparsers: argparse._SubParsersAction[Any]) -> None:
type=_parse_metadata_json,
help="JSON object sent as context metadata",
)
context_create.add_argument(
"--description",
help="Optional UTF-8 description for the persistent context.",
)
context_create.set_defaults(func=cmd_context_create)

context_list = context_subparsers.add_parser("list", help="List contexts")
Expand Down Expand Up @@ -30040,6 +30065,10 @@ def _add_context_commands(subparsers: argparse._SubParsersAction[Any]) -> None:
action="store_true",
help="Create a context with the metadata filter when none is reusable.",
)
context_pick.add_argument(
"--description",
help="Optional UTF-8 description when --create-if-missing creates a context.",
)
context_pick.add_argument(
"--dry-run",
action="store_true",
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "browser-cli"
version = "0.3.7"
version = "0.3.8"
description = "Standalone CLI for operating Lexmount browser sessions"
readme = "README.md"
requires-python = ">=3.11"
Expand Down
44 changes: 37 additions & 7 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ def test_version_command_falls_back_to_package_constant(
assert exc_info.value.code == 0
payload = json.loads(capsys.readouterr().out)
assert payload["command"] == "version"
assert payload["version"] == "0.3.7"
assert payload["version"] == "0.3.8"
assert payload["version_source"] == "package_fallback"
assert payload["lex_browser_runtime_version"] == "unknown"
assert payload["lex_browser_runtime_version_known"] is False
Expand Down Expand Up @@ -9884,7 +9884,7 @@ def list_sessions(self, *, status: str | None) -> DummyModel:
assert exc_info.value.code == 0
payload = json.loads(capsys.readouterr().out)
checks = _checks_by_name(payload)
assert checks["browser_cli"]["version"] == "0.3.7"
assert checks["browser_cli"]["version"] == "0.3.8"
assert checks["browser_cli"]["version_known"] is True
assert checks["browser_cli"]["version_source"] == "package_fallback"
assert checks["lex_browser_runtime"]["version"] == "unknown"
Expand Down Expand Up @@ -13371,6 +13371,7 @@ def create_session(
context_mode: str,
browser_mode: str,
metadata: dict[str, Any] | None,
context_description: str | None = None,
) -> DummyModel:
observed.update(
{
Expand All @@ -13379,6 +13380,7 @@ def create_session(
"context_mode": context_mode,
"browser_mode": browser_mode,
"metadata": metadata,
"context_description": context_description,
}
)
return DummyModel(
Expand All @@ -13400,6 +13402,8 @@ def create_session(
"--create-context",
"--context-mode",
"read_only",
"--context-description",
"Office login context",
"--browser-mode",
"light",
"--metadata-json",
Expand All @@ -13414,6 +13418,7 @@ def create_session(
"context_mode": "read_only",
"browser_mode": "light",
"metadata": {"owner": "codex"},
"context_description": "Office login context",
}
payload = json.loads(capsys.readouterr().out)
assert payload["ok"] is True
Expand Down Expand Up @@ -14088,9 +14093,17 @@ def create_context(
self,
*,
metadata: dict[str, Any] | None,
description: str | None = None,
) -> DummyModel:
calls.append(("create", {"metadata": metadata}))
return DummyModel({"context_id": "ctx1", "metadata": metadata})
calls.append(("create", {"metadata": metadata, "description": description}))
return DummyModel(
{
"context_id": "ctx1",
"description": description,
"display_name": description or "ctx1",
"metadata": metadata,
}
)

def list_contexts(
self,
Expand Down Expand Up @@ -14118,9 +14131,20 @@ def delete_context(self, context_id: str) -> None:
monkeypatch.setattr("browser_cli.cli.LexmountBrowserAdmin", lambda: FakeAdmin())

with pytest.raises(SystemExit) as exc_info:
cli_main(["context", "create", "--metadata-json", '{"purpose":"test"}'])
cli_main(
[
"context",
"create",
"--metadata-json",
'{"purpose":"test"}',
"--description",
"Office login context",
]
)
assert exc_info.value.code == 0
assert json.loads(capsys.readouterr().out)["context"]["context_id"] == "ctx1"
created = json.loads(capsys.readouterr().out)["context"]
assert created["context_id"] == "ctx1"
assert created["description"] == "Office login context"

with pytest.raises(SystemExit) as exc_info:
cli_main(["context", "list", "--status", "available", "--limit", "5"])
Expand All @@ -14141,7 +14165,13 @@ def delete_context(self, context_id: str) -> None:
assert json.loads(capsys.readouterr().out)["deleted"] is True

assert calls == [
("create", {"metadata": {"purpose": "test"}}),
(
"create",
{
"metadata": {"purpose": "test"},
"description": "Office login context",
},
),
("list", {"status": "available", "limit": 5}),
("get", {"context_id": "ctx1"}),
("delete", {"context_id": "ctx1"}),
Expand Down