diff --git a/README.md b/README.md index c4390c2..ff1c0a0 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # AIStack CLI -AIStack CLI is an experimental swiss-knife command-line application designed to streamline the installation and management of AI development tools, including `gemini-cli`, `opencode` and various MCP servers. The main goal is to provide a convenient way to install and configure AI tools, ensuring minimal system, to test or use them. +AIStack CLI is an experimental swiss-knife command-line application designed to streamline the installation and management of AI development tools, including `gemini-cli`, `opencode`, `codex` and various MCP servers. The main goal is to provide a convenient way to install and configure AI tools, ensuring minimal system, to test or use them. ## Key Features of AIStack @@ -68,6 +68,10 @@ See [Gemini CLI](doc/geminicli.md) See [Opencode](doc/opencode.md) +### Codex + +See [Codex](doc/codex.md) + ### VS Code See [VS Code](doc/vscode.md) diff --git a/aistack b/aistack index edc9cb3..123d0bf 100755 --- a/aistack +++ b/aistack @@ -13,6 +13,7 @@ STELLA_LOG_STATE="OFF" . "${_CURRENT_FILE_DIR}/lib/lib_vscode.sh" . "${_CURRENT_FILE_DIR}/lib/lib_gemini.sh" . "${_CURRENT_FILE_DIR}/lib/lib_opencode.sh" +. "${_CURRENT_FILE_DIR}/lib/lib_codex.sh" . "${_CURRENT_FILE_DIR}/lib/lib_orla.sh" . "${_CURRENT_FILE_DIR}/lib/lib_mcp.sh" @@ -63,6 +64,18 @@ Options: oc mcp github install|uninstall Add mcp-github remote server configuration. oc mcp context7 install|uninstall Add mcp-context7 local server configuration. ---- + cx : codex - https://github.com/openai/codex + cx install [@version] Install and configure Codex CLI. + cx uninstall Uninstalling Codex CLI and unregister Codex CLI PATH (keep all configuration unchanged, to remove configuration use 'aistack cx reset' command) + cx configure Configure Codex CLI. ('aistack cx install' include configuration) + cx show-config Show current Codex CLI configuration. + cx reset Reset all Codex CLI configuration. + cx register |vs Register Codex CLI PATH into shell env PATH ("bash", "zsh" or "fish") or into VS Code integrated terminal env PATH ("vs") + cx unregister |vs Unregister Codex CLI PATH into shell env PATH ("bash", "zsh", "fish" or "all") or into VS Code integrated terminal env PATH ("vs") + cx launch [context folder] -- + Launch Codex CLI. Instead use 'codex' command if ${AISTACK_CODEX_LAUNCHER_HOME} is in your PATH, + you could use 'aistack cx register ' + ---- kc : kilocode VS Code extension - https://kilo.ai/ kc connect cpa Connect KiloCode VS Code extension to CLIProxyAPI. (require 'aistack cpa install' before) ---- @@ -199,6 +212,9 @@ main() { cpa) . "${_CURRENT_FILE_DIR}/lib/main_cpa.sh" ;; + cx) + . "${_CURRENT_FILE_DIR}/lib/main_cx.sh" + ;; vs) . "${_CURRENT_FILE_DIR}/lib/main_vs.sh" ;; diff --git a/doc/codex.md b/doc/codex.md new file mode 100644 index 0000000..57b1373 --- /dev/null +++ b/doc/codex.md @@ -0,0 +1,13 @@ +# Codex CLI + +This page is a placeholder for Codex CLI usage with AIStack. + +Basic lifecycle commands: + +```bash +./aistack cx install +./aistack cx register bash +./aistack cx launch -- --help +./aistack cx show-config +./aistack cx reset +``` diff --git a/lib/lib.sh b/lib/lib.sh index 67002ae..3115385 100644 --- a/lib/lib.sh +++ b/lib/lib.sh @@ -18,6 +18,7 @@ aistack_path() { node_path gemini_path opencode_path + codex_path vscode_path cpa_path orla_path @@ -194,6 +195,8 @@ aistack_uninstall() { gemini_path_unregister_for_vs_terminal opencode_path_unregister_for_shell "all" opencode_path_unregister_for_vs_terminal + codex_path_unregister_for_shell "all" + codex_path_unregister_for_vs_terminal orla_path_unregister_for_shell "all" orla_path_unregister_for_vs_terminal diff --git a/lib/lib_codex.sh b/lib/lib_codex.sh new file mode 100644 index 0000000..aa44780 --- /dev/null +++ b/lib/lib_codex.sh @@ -0,0 +1,108 @@ +codex_path() { + # codex specific paths + export AISTACK_CODEX_CONFIG_HOME="${HOME}/.codex" + export AISTACK_CODEX_CONFIG_FILE="${AISTACK_CODEX_CONFIG_HOME}/config.toml" + + # aistack path for codex + export AISTACK_CODEX_LAUNCHER_HOME="${AISTACK_LAUNCHER_HOME}/codex" + mkdir -p "${AISTACK_CODEX_LAUNCHER_HOME}" +} + +codex_path_register_for_shell() { + local shell_name="$1" + path_register_for_shell "codex" "$shell_name" "${AISTACK_CODEX_LAUNCHER_HOME}" +} + +codex_path_unregister_for_shell() { + local shell_name="$1" + path_unregister_for_shell "codex" "$shell_name" +} + +codex_path_register_for_vs_terminal() { + vscode_path_register_for_vs_terminal "codex" "${AISTACK_CODEX_LAUNCHER_HOME}" +} + +codex_path_unregister_for_vs_terminal() { + vscode_path_unregister_for_vs_terminal "codex" "${AISTACK_CODEX_LAUNCHER_HOME}" +} + +codex_install() { + local version="$1" + [ -z "${version}" ] && version="@latest" + + echo "Installing Codex CLI ${version}" + PATH="${AISTACK_NODEJS_BIN_PATH}:${STELLA_ORIGINAL_SYSTEM_PATH}" npm install --verbose -g @openai/codex${version} +} + +codex_uninstall() { + PATH="${AISTACK_NODEJS_BIN_PATH}:${STELLA_ORIGINAL_SYSTEM_PATH}" npm uninstall -g @openai/codex +} + +codex_launch_export_variables="AISTACK_RUNTIME_PATH_FILE AISTACK_NODEJS_BIN_PATH" +codex_launch() { + set -- "$@" + + ( + . "${AISTACK_RUNTIME_PATH_FILE}" + + if [ "$#" -gt 0 ]; then + "${AISTACK_NODEJS_BIN_PATH}/codex" "$@" + else + "${AISTACK_NODEJS_BIN_PATH}/codex" + fi + ) +} + +codex_launcher_manage() { + local action="${1:-create}" + + case $action in + create) + { + echo '#!/bin/sh' + for v in $codex_launch_export_variables; do + printf '%s=%s\n' "$v" "$(shell_quote_posix "${!v}")" + done + + declare -f codex_launch + + echo codex_launch \"\$@\" + } > "${AISTACK_CODEX_LAUNCHER_HOME}/codex" + + chmod +x "${AISTACK_CODEX_LAUNCHER_HOME}/codex" + ;; + delete) + rm -f "${AISTACK_CODEX_LAUNCHER_HOME}/codex" + ;; + esac +} + +codex_settings_configure() { + mkdir -p "${AISTACK_CODEX_CONFIG_HOME}" + + local start_marker="# >>> aistack-codex-settings >>>" + local end_marker="# <<< aistack-codex-settings <<<" + local template="${AISTACK_POOL}/settings/codex/config.toml" + local tmp_file="$(mktemp)" + + [ -f "${AISTACK_CODEX_CONFIG_FILE}" ] || touch "${AISTACK_CODEX_CONFIG_FILE}" + + awk -v start="$start_marker" -v end="$end_marker" ' + $0 == start {in_block=1; next} + $0 == end {in_block=0; next} + !in_block {print} + ' "${AISTACK_CODEX_CONFIG_FILE}" > "$tmp_file" + + cat "$tmp_file" > "${AISTACK_CODEX_CONFIG_FILE}" + rm -f "$tmp_file" + + { + printf "\n%s\n" "$start_marker" + cat "$template" + printf "\n%s\n" "$end_marker" + } >> "${AISTACK_CODEX_CONFIG_FILE}" +} + +codex_settings_remove() { + rm -Rf "$AISTACK_CODEX_CONFIG_HOME" +} diff --git a/lib/main_cx.sh b/lib/main_cx.sh new file mode 100644 index 0000000..df8b134 --- /dev/null +++ b/lib/main_cx.sh @@ -0,0 +1,98 @@ +if ! check_requirements "jq"; then echo " -- ERROR : jq missing, launch aistack init"; exit 1; fi; +local sub_command="$1" +shift +case "$sub_command" in + install) + if ! check_requirements "nodejs"; then echo " -- ERROR : nodejs missing, launch aistack init"; exit 1; fi; + + codex_install "$1" + + echo "Configuring Codex CLI" + codex_settings_configure + + codex_launcher_manage + + echo "You could now register it's path in shell OR vscode terminal" + echo "$0 cx register bash|zsh|fish" + echo " OR" + echo "$0 cx register vs" + ;; + uninstall) + if ! check_requirements "nodejs"; then echo " -- ERROR : nodejs missing, launch aistack init"; exit 1; fi; + + echo "Uninstalling Codex CLI and unregister Codex CLI PATH (keep all configuration unchanged, to remove configuration use reset command)" + codex_uninstall + + codex_path_unregister_for_shell "all" + codex_path_unregister_for_vs_terminal + + codex_launcher_manage "delete" + ;; + configure) + echo "Configuring Codex CLI" + codex_settings_configure + + codex_launcher_manage + ;; + reset) + echo "Resetting Codex CLI configuration" + codex_settings_remove + + codex_launcher_manage + ;; + register) + echo "Registering Codex CLI launcher in PATH for $1" + case "$1" in + "vs") + codex_path_register_for_vs_terminal + ;; + *) + codex_path_register_for_shell "$1" + ;; + esac + ;; + unregister) + echo "Unegistering Codex CLI launcher PATH from $1" + case "$1" in + "vs") + codex_path_unregister_for_vs_terminal + ;; + *) + codex_path_unregister_for_shell "$1" + ;; + esac + ;; + show-config) + if [ -f "$AISTACK_CODEX_CONFIG_FILE" ]; then + echo "Current Codex CLI configuration file : $AISTACK_CODEX_CONFIG_FILE" + cat "$AISTACK_CODEX_CONFIG_FILE" + else + echo "No Codex CLI configuration file found." + fi + ;; + + launch) + codex_launcher_manage + + local folder= + if [ -n "$1" ] && [ "$1" != "--" ]; then + folder="$1" + if [ -d "$folder" ]; then + echo "change to context folder : $folder" + cd "$folder" || exit 1 + shift + else + echo "Error: Directory '$folder' not found" + exit 1 + fi + fi + [ "$1" = "--" ] && shift + + codex_launch "$@" + ;; + *) + echo "Error: Unknown command $sub_command for cx" + usage + exit 1 + ;; +esac diff --git a/pool/settings/codex/config.toml b/pool/settings/codex/config.toml new file mode 100644 index 0000000..a49c2fc --- /dev/null +++ b/pool/settings/codex/config.toml @@ -0,0 +1,5 @@ +# Default settings managed by aistack. +# https://github.com/openai/codex +model = "gpt-5-codex" +approval_policy = "on-request" +sandbox_mode = "workspace-write"