Skip to content
Merged
70 changes: 57 additions & 13 deletions justfile
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
set working-directory := "codex-rs"
set positional-arguments
export JUST_SHELL := justfile_directory() / "scripts/just-shell.py"
set shell := ["python3", "-c", 'import os, runpy; runpy.run_path(os.environ["JUST_SHELL"], run_name="__main__")']
set windows-shell := ["python", "-c", 'import os, runpy; runpy.run_path(os.environ["JUST_SHELL"], run_name="__main__")']

rust_min_stack := "8388608" # 8 MiB
python := if os_family() == "windows" { "python" } else { "python3" }

# Display help
help:
Expand All @@ -10,81 +14,115 @@ help:
# `codex`
alias c := codex
codex *args:
cargo run --bin codex -- "$@"
cargo run --bin codex -- {args}

# `codex exec`
exec *args:
cargo run --bin codex -- exec "$@"
cargo run --bin codex -- exec {args}

# Start `codex exec-server` and run codex-tui.
[unix]
[no-cd]
[positional-arguments]
tui-with-exec-server *args:
{{ justfile_directory() }}/scripts/run_tui_with_exec_server.sh "$@"

# Run the CLI version of the file-search crate.
file-search *args:
cargo run --bin codex-file-search -- "$@"
cargo run --bin codex-file-search -- {args}

# Build the CLI and run the app-server test client
app-server-test-client *args:
cargo build -p codex-cli
cargo run -p codex-app-server-test-client -- --codex-bin ./target/debug/codex "$@"
cargo run -p codex-app-server-test-client -- --codex-bin ./target/debug/codex {args}

# Format Rust and Python SDK code.
fmt:
cargo fmt -- --config imports_granularity=Item 2>/dev/null
cargo fmt -- --config imports_granularity=Item {stderr-null}
uv run --frozen --project ../sdk/python --extra dev ruff check --fix --fix-only ../sdk/python
uv run --frozen --project ../sdk/python --extra dev ruff format ../sdk/python

fix *args:
cargo clippy --fix --tests --allow-dirty "$@"
cargo clippy --fix --tests --allow-dirty {args}

clippy *args:
cargo clippy --tests "$@"
cargo clippy --tests {args}

[unix]
install:
rustup show active-toolchain
cargo fetch

[windows]
install:
#!powershell.exe -File
$pwsh = Get-Command pwsh.exe -ErrorAction SilentlyContinue
if (-not $pwsh) {
winget install --exact --id Microsoft.PowerShell --source winget --accept-package-agreements --accept-source-agreements
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
}
rustup show active-toolchain
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
cargo fetch
exit $LASTEXITCODE

# Run nextest with --no-fail-fast so all tests are run.
#
# Run `cargo install --locked cargo-nextest` if you don't have it installed.
# Prefer this for routine local runs. Workspace crate features are banned, so
# there should be no need to add `--all-features`.
[unix]
test *args:
RUST_MIN_STACK={{ rust_min_stack }} cargo nextest run --no-fail-fast "$@"
just bench-smoke

[windows]
test *args:
$env:RUST_MIN_STACK = "{{ rust_min_stack }}"; cargo nextest run --no-fail-fast @($args | Select-Object -Skip 1)
just bench-smoke

# Run explicit workspace benchmark targets.
bench *args:
cargo bench --workspace --bench '*' "$@"
cargo bench --workspace --bench '*' {args}

# Run benchmark targets once to ensure they start successfully.
bench-smoke:
just bench -- --test

# Build and run Codex from source using Bazel.
# Note we have to use the combination of `[no-cd]` and `--run_under="cd $PWD &&"`
# to ensure that Bazel runs the command in the current working directory.
# On Unix, use `[no-cd]` and `--run_under="cd $PWD &&"` to ensure Bazel runs
# the command in the current working directory.
[unix]
[no-cd]
bazel-codex *args:
bazel run //codex-rs/cli:codex --run_under="cd $PWD &&" -- "$@"

[windows]
bazel-codex *args:
bazel run //codex-rs/cli:codex --run_under='cd /d "{{invocation_directory_native()}}" &&' -- @($args | Select-Object -Skip 1)

[no-cd]
bazel-lock-update:
bazel mod deps --lockfile_mode=update

[unix]
[no-cd]
bazel-lock-check:
{{ justfile_directory() }}/scripts/check-module-bazel-lock.sh

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can be done in a follow-up, but maybe this should be a platform-independent Python script?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed - will look at that as a follow-up.


[windows]
bazel-lock-check:
bazel mod deps --lockfile_mode=error; if ($LASTEXITCODE -ne 0) { Write-Error "MODULE.bazel.lock is out of date. Run 'just bazel-lock-update' and commit the updated lockfile."; exit 1 }

bazel-test:
bazel test --test_tag_filters=-argument-comment-lint //... --keep_going

[unix]
[no-cd]
bazel-clippy:
bazel_targets="$({{ justfile_directory() }}/scripts/list-bazel-clippy-targets.sh)" && bazel build --config=clippy -- ${bazel_targets}

[unix]
[no-cd]
bazel-argument-comment-lint:
bazel build --config=argument-comment-lint -- $({{ justfile_directory() }}/tools/argument-comment-lint/list-bazel-targets.sh)
Expand All @@ -97,21 +135,22 @@ build-for-release:

# Run the MCP server
mcp-server-run *args:
cargo run -p codex-mcp-server -- "$@"
cargo run -p codex-mcp-server -- {args}

# Regenerate the json schema for config.toml from the current config types.
write-config-schema:
cargo run -p codex-core --bin codex-write-config-schema

# Regenerate vendored app-server protocol schema artifacts.
write-app-server-schema *args:
cargo run -p codex-app-server-protocol --bin write_schema_fixtures -- "$@"
cargo run -p codex-app-server-protocol --bin write_schema_fixtures -- {args}

[no-cd]
write-hooks-schema:
cargo run --manifest-path {{ justfile_directory() }}/codex-rs/Cargo.toml -p codex-hooks --bin write_hooks_schema_fixtures

# Run the argument-comment Dylint checks across codex-rs.
[unix]
[no-cd]
argument-comment-lint *args:
if [ "$#" -eq 0 ]; then \
Expand All @@ -122,8 +161,13 @@ argument-comment-lint *args:

[no-cd]
argument-comment-lint-from-source *args:
{{ justfile_directory() }}/tools/argument-comment-lint/run.py "$@"
{{ python }} {{ justfile_directory() }}/tools/argument-comment-lint/run.py {args}

# Tail logs from the state SQLite database
[unix]
log *args:
if [ "${1:-}" = "--" ]; then shift; fi; cargo run -p codex-state --bin logs_client -- "$@"

[windows]
log *args:
$forwarded_args = @($args | Select-Object -Skip 1); if ($forwarded_args.Count -gt 0 -and $forwarded_args[0] -eq "--") { $forwarded_args = @($forwarded_args | Select-Object -Skip 1) }; cargo run -p codex-state --bin logs_client -- @forwarded_args
72 changes: 72 additions & 0 deletions scripts/just-shell.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
#!/usr/bin/env python3
"""Cross-platform shell launcher for `just` recipes.

This keeps recipe bodies as normal shell snippets while giving the justfile one
portable placeholder, `{args}`, for forwarding variadic recipe arguments.
"""

from __future__ import annotations

import os
import shutil
import subprocess
import sys


ARGS_TOKEN = "{args}"
STDERR_NULL_TOKEN = "{stderr-null}"
POWERSHELL_ARGS = "@($args | Select-Object -Skip 1)"
POWERSHELL_STDERR_NULL = '2>$null; exit $LASTEXITCODE'
SH_ARGS = '"$@"'
SH_STDERR_NULL = "2>/dev/null"


def main() -> int:
if len(sys.argv) < 2:
print("just shell adapter expected a recipe command.", file=sys.stderr)
return 1

command = sys.argv[1]
recipe_name = sys.argv[2] if len(sys.argv) > 2 else ""
recipe_args = sys.argv[3:]

if os.name == "nt":
return run_powershell(command, recipe_name, recipe_args)
else:
return run_sh(command, recipe_name, recipe_args)


def run_sh(command: str, recipe_name: str, recipe_args: list[str]) -> int:
command = command.replace(ARGS_TOKEN, SH_ARGS)
command = command.replace(STDERR_NULL_TOKEN, SH_STDERR_NULL)
os.execvp("sh", ["sh", "-cu", command, recipe_name, *recipe_args])


def run_powershell(command: str, recipe_name: str, recipe_args: list[str]) -> int:
pwsh = shutil.which("pwsh.exe") or shutil.which("pwsh")
if pwsh is None:
print(
"PowerShell ('pwsh') is required for Windows just recipes. "
"Run 'just install' to install it.",
file=sys.stderr,
)
return 1

command = command.replace(ARGS_TOKEN, POWERSHELL_ARGS)
command = command.replace(STDERR_NULL_TOKEN, POWERSHELL_STDERR_NULL)
return subprocess.run(
[
pwsh,
"-NoLogo",
"-NoProfile",
"-CommandWithArgs",
command,
recipe_name,
*recipe_args,
],
check=False,
).returncode


if __name__ == "__main__":
raise SystemExit(main())
8 changes: 5 additions & 3 deletions sdk/python/tests/test_artifact_workflow_and_binaries.py
Original file line number Diff line number Diff line change
Expand Up @@ -81,14 +81,16 @@ def test_root_fmt_recipe_formats_rust_and_python_sdk() -> None:
fmt_recipe = lines[fmt_index:next_recipe_index]
actual = {
"working_directory": lines[0],
"previous_attribute": lines[fmt_index - 1],
"previous_comment": next(
Comment thread
iceweasel-oai marked this conversation as resolved.
line for line in reversed(lines[:fmt_index]) if line.startswith("#")
),
"commands": [line.strip() for line in fmt_recipe[1:] if line.strip()],
}
expected = {
"working_directory": 'set working-directory := "codex-rs"',
"previous_attribute": "# Format Rust and Python SDK code.",
"previous_comment": "# Format Rust and Python SDK code.",
"commands": [
"cargo fmt -- --config imports_granularity=Item 2>/dev/null",
"cargo fmt -- --config imports_granularity=Item {stderr-null}",
"uv run --frozen --project ../sdk/python --extra dev ruff check --fix --fix-only ../sdk/python",
"uv run --frozen --project ../sdk/python --extra dev ruff format ../sdk/python",
],
Expand Down
Loading