From d78ed4cda4916f8d20ddd6de16df9c0ef76828f3 Mon Sep 17 00:00:00 2001 From: AmeerJ97 <55268303+AmeerJ97@users.noreply.github.com> Date: Wed, 27 May 2026 17:47:17 -0400 Subject: [PATCH 1/2] #B6A0C56A #TASK-01: polish public repository hygiene Task: TASK-01 Kind: maintenance Base: bbf4fef Evidence: git diff --check; bun run format; bun run lint; bun run typecheck; bun run test; bun run build Remote-Evidence: branch protection verified; topics/homepage/wiki updated; vulnerability alerts and private vulnerability reporting enabled --- .github/ISSUE_TEMPLATE/config.yml | 2 +- .github/pull_request_template.md | 2 + CONTRIBUTING.md | 71 ++++++++++++++++++++++++++ README.md | 18 ++++++- SECURITY.md | 51 +++++++++++++++++++ docs/maintainer-runbook.md | 16 ++++++ docs/public-repo-audit.md | 82 +++++++++++++++++++++++++++++++ package.json | 12 +++++ 8 files changed, 251 insertions(+), 3 deletions(-) create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 docs/public-repo-audit.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e42e2e2..d828961 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,4 +1,4 @@ -blank_issues_enabled: true +blank_issues_enabled: false contact_links: - name: Security-sensitive report url: https://github.com/AmeerJ97/grok-cli-vertex/security/advisories/new diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 5440aab..75a37a2 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -8,8 +8,10 @@ ## Verification +- [ ] `bun run format` - [ ] `bun run typecheck` - [ ] `bun run lint` +- [ ] `bun run test` - [ ] `bun run build:binary` - [ ] Relevant tests: - [ ] Manual smoke, if applicable: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..0ef4e81 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,71 @@ +# Contributing + +Thanks for helping improve `grok-cli-vertex`. This fork is Vertex-first, with +the inherited native xAI path kept for compatibility and comparison. + +## Project Direction + +- Prefer Vertex AI behavior unless a change is explicitly about the native xAI + fallback or upstream compatibility. +- Keep backend-specific behavior behind `src/providers/` and the + `GrokProviderAdapter` contract. +- Use typed capability errors for unsupported provider features instead of + letting unsupported endpoints fail late. +- Keep public docs honest that this project is community-built and is not an + official xAI or Google product. + +## Local Setup + +```bash +bun install +bun run typecheck +bun run test +bun run build +``` + +For changes that touch runtime behavior, also run the narrow test file while +iterating: + +```bash +bunx --bun vitest run path/to/file.test.ts +``` + +Vertex mode requires Google Application Default Credentials and a project id: + +```bash +gcloud auth application-default login +GROK_PROVIDER=vertex GROK_VERTEX_PROJECT_ID=my-gcp-project bun run dev +``` + +Native xAI fallback testing still requires `GROK_API_KEY`. + +## Pull Requests + +- Start from current `main`. +- Keep PRs focused and avoid mixing code, docs, dependency, and release changes + unless they are part of one behavior change. +- Include the commands you actually ran in the PR body. +- Add or update tests for provider behavior, storage migrations, tool loops, + CLI flags, and user-visible error handling. +- Update README, CLI help, or docs when behavior changes. +- Call out any provider-specific risk, especially when changing shared agent or + UI code that can affect both Vertex and native xAI modes. + +## Issue Triage + +Useful reports include: + +- OS and terminal emulator +- Bun version +- Provider mode (`vertex` or `xai`) +- Relevant non-secret environment variables +- Reproduction steps and logs + +Do not include API keys, Google Cloud project secrets, Telegram tokens, session +transcripts, or private repository data in public issues. + +## Branch Hygiene + +Merged PR branches are normally deleted on GitHub. Local branches may remain as +private working references, but new public polish or maintenance work should use +a fresh branch from current `main`. diff --git a/README.md b/README.md index 88069ff..ad2acdc 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,9 @@ # grok-cli-vertex: a Vertex AI-focused Grok coding agent -[CI](https://github.com/AmeerJ97/grok-cli-vertex/actions/workflows/typecheck.yml) +[![CI](https://github.com/AmeerJ97/grok-cli-vertex/actions/workflows/typecheck.yml/badge.svg)](https://github.com/AmeerJ97/grok-cli-vertex/actions/workflows/typecheck.yml) +[![Security Scan](https://github.com/AmeerJ97/grok-cli-vertex/actions/workflows/security.yml/badge.svg)](https://github.com/AmeerJ97/grok-cli-vertex/actions/workflows/security.yml) +[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](./LICENSE) [npm package inherited from upstream](https://www.npmjs.com/package/grok-dev) -[License: MIT](./LICENSE) [TypeScript](https://www.typescriptlang.org/) [Bun](https://bun.sh/) @@ -18,6 +19,16 @@ Some native xAI paths remain because they are inherited from upstream and useful - [Demo script](docs/demo-script.md) — a short walkthrough for showing the project without exposing private credentials. - [Maintainer runbook](docs/maintainer-runbook.md) — local checks, PR policy, release flow, and troubleshooting. - [Roadmap](docs/roadmap.md) — near-term hardening work and explicit non-goals. +- [Contributing](CONTRIBUTING.md) — local setup, PR expectations, provider-boundary guardrails, and issue triage. +- [Security policy](SECURITY.md) — private vulnerability reporting and supported security scope. +- [Public repo audit](docs/public-repo-audit.md) — current branch/repo hygiene notes and public polish follow-ups. + +## Project status + +This repository is public and early-maintainer-led. The default branch is kept +Vertex-first, CI-verified, and dependency-monitored with Dependabot. Public +issues are appropriate for reproducible bugs and focused feature requests; +security-sensitive reports should use GitHub private vulnerability reporting. ## Upstream attribution @@ -563,6 +574,9 @@ bun run typecheck bun run lint ``` +See [CONTRIBUTING.md](CONTRIBUTING.md) for the full local setup, PR checklist, +provider-boundary expectations, and issue-triage guidance. + --- ## Trademarks diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..ed2d073 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,51 @@ +# Security Policy + +## Supported Versions + +Security fixes target the current `main` branch and the latest release tag, when +a release exists. Older local builds and unpublished development branches are +not supported as separate security maintenance lines. + +## Reporting A Vulnerability + +Please report suspected vulnerabilities through GitHub private vulnerability +reporting: + +https://github.com/AmeerJ97/grok-cli-vertex/security/advisories/new + +Use a public issue only for non-sensitive hardening requests. Do not post API +keys, Google Cloud project secrets, Telegram bot tokens, session transcripts, +or private repository contents in public issues. + +## Useful Report Details + +Include as much non-secret detail as possible: + +- Affected version, commit, or install method +- Provider mode (`vertex` or native `xai`) +- Operating system and terminal environment +- Reproduction steps +- Expected impact and whether credentials are required +- Relevant logs with secrets redacted + +## Scope + +In scope: + +- Credential handling in Vertex and native xAI configuration paths +- Local file, shell, MCP, LSP, hook, and sandbox behavior +- Install, update, release, and dependency lifecycle behavior +- Telegram remote-control authentication and pairing behavior + +Out of scope: + +- Vulnerabilities in upstream cloud provider services +- Social engineering or phishing against maintainers +- Denial-of-service reports that require unrealistic local resource exhaustion +- Reports that depend on exposing intentionally provided local credentials + +## Disclosure Expectations + +Please give maintainers a reasonable chance to investigate before public +disclosure. The project is community-maintained, so response times may vary, but +security-sensitive reports will be handled separately from public issue triage. diff --git a/docs/maintainer-runbook.md b/docs/maintainer-runbook.md index 805c637..9fddcb7 100644 --- a/docs/maintainer-runbook.md +++ b/docs/maintainer-runbook.md @@ -40,6 +40,8 @@ Before marking a PR ready: - Confirm Vertex-specific behavior uses provider capabilities instead of hardcoded backend checks in random call sites. - Confirm xAI fallback behavior still works when compatibility code is touched. +- Confirm security-sensitive changes are routed through `SECURITY.md` guidance + instead of public issue details. ## Merge Policy @@ -54,6 +56,20 @@ on `main`. Maintainers can merge once: Dependabot PRs can be merged when CI and security checks pass and the dependency scope is clear. +## Public Repository Hygiene + +For public maintenance branches, keep the public-facing project surfaces aligned: + +- README links to architecture, roadmap, contributing, security, and the public + repo audit. +- `package.json` includes repository, issue tracker, and homepage metadata. +- `SECURITY.md` points reporters to private vulnerability reporting. +- Merged PR branches may be pruned remotely; local branches with upstreams marked + `gone` should not be deleted unless the maintainer confirms they are no + longer useful. +- New polish or maintenance work should start from current `main` on one focused + branch, not by replaying old local branches wholesale. + ## Release Flow Releases are produced by `.github/workflows/release.yml`. diff --git a/docs/public-repo-audit.md b/docs/public-repo-audit.md new file mode 100644 index 0000000..c884008 --- /dev/null +++ b/docs/public-repo-audit.md @@ -0,0 +1,82 @@ +# Public Repository Audit + +Snapshot date: 2026-05-27 + +This audit records the public-repo polish pass that consolidated the old branch +state into a single maintenance branch: `chore/repo-polish-audit`. + +## Current Remote State + +- Repository: `AmeerJ97/grok-cli-vertex` +- Visibility: public +- Default branch: `main` +- Local `main`: clean and aligned with `origin/main` at `bbf4fef` +- Branch protection: enabled on `main`, requiring strict status checks for + `verify` and `security-scan`; conversation resolution is required; force + pushes and branch deletion are disabled. +- Repository topics: `bun`, `cli`, `coding-agent`, `google-cloud`, `grok`, + `opentui`, `typescript`, and `vertex-ai` +- Homepage: `https://github.com/AmeerJ97/grok-cli-vertex#readme` +- Wiki: disabled so public documentation stays in version-controlled files +- Vulnerability alerts and private vulnerability reporting: enabled +- Active remote branches: + - `origin/main` + - `origin/dependabot/bun/bun-dependencies-e5bce18172` +- Open remote work: + - PR #20, Dependabot Bun dependency group update, CI and security scan passing +- Current remote gaps before this branch lands: no GitHub-recognized security + policy, no latest release, and no CodeQL/code-scanning analysis available. + +## Old Branch Assessment + +GitHub PR history shows the old issue/fix/docs branches were merged or closed. +After `git fetch --prune origin`, their remote-tracking refs were removed, but +local branches remain as private references with upstreams marked `gone`. + +Do not replay those local branches wholesale. They are historical working +branches whose public PR outcomes are already represented by merged history on +`main` or by closed Dependabot state. + +Recommended handling: + +- Keep them untouched until the maintainer confirms whether any local-only + context is still useful. +- Delete local branches only after confirming they are no longer needed. +- Use fresh branches from `main` for new public polish, maintenance, or release + work. + +## Public Polish Findings + +Completed in this branch: + +- Added `CONTRIBUTING.md` so new contributors can find setup, provider-boundary, + PR, and issue-triage expectations. +- Added `SECURITY.md` so GitHub can surface a security policy and reporters have + a private disclosure path. +- Added package metadata for repository, issue tracker, and homepage links. +- Linked contributing, security, and this audit from the README and maintainer + runbook. +- Tightened GitHub templates so blank issues are disabled and the PR checklist + matches the CI gate more closely. +- Updated GitHub repository metadata: homepage, topics, wiki setting, + vulnerability alerts, and private vulnerability reporting. + +Recommended GitHub follow-ups after this branch lands: + +- Consider adding CodeQL or another code-scanning workflow if the project needs + GitHub-native security alerting beyond the current secret scan. +- Keep delete-branch-on-merge enabled. +- Publish a release when install-script release assets are ready; no latest + release currently exists. + +## Verification + +Run before merging: + +```bash +bun run format +bun run lint +bun run typecheck +bun run test +bun run build +``` diff --git a/package.json b/package.json index 766e741..d94b96c 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,14 @@ "name": "grok-dev", "version": "1.1.6", "description": "A Vertex AI-focused Grok coding agent fork built with Bun and OpenTUI.", + "homepage": "https://github.com/AmeerJ97/grok-cli-vertex#readme", + "repository": { + "type": "git", + "url": "git+https://github.com/AmeerJ97/grok-cli-vertex.git" + }, + "bugs": { + "url": "https://github.com/AmeerJ97/grok-cli-vertex/issues" + }, "type": "module", "main": "dist/index.js", "exports": { @@ -37,9 +45,13 @@ "cli", "agent", "grok", + "vertex-ai", + "google-cloud", "ai", "coding", "terminal", + "typescript", + "bun", "opentui" ], "author": "AmeerJ97", From bae5ccf0581cab2a79c76ca82dc9c3485dd8f262 Mon Sep 17 00:00:00 2001 From: AmeerJ97 <55268303+AmeerJ97@users.noreply.github.com> Date: Wed, 27 May 2026 17:57:18 -0400 Subject: [PATCH 2/2] #5DD033B1 #FIX-01: separate vertex install command Task: FIX-01 Kind: fix Base: d78ed4c Evidence: git diff --check; bun run format; bunx --bun vitest run src/utils/install-manager.test.ts; bun run lint; bun run typecheck; bun run test; bun run build; bun run build:binary Local-Evidence: grok resolves to official x.ai CLI; grok-vertex resolves to ~/.local/bin/grok-vertex and reports 1.1.6 --- README.md | 66 ++++++++++++++----------- docs/maintainer-runbook.md | 6 ++- docs/public-repo-audit.md | 3 ++ install.sh | 16 +++---- package.json | 3 +- src/utils/install-manager.test.ts | 36 ++++++++++++-- src/utils/install-manager.ts | 80 ++++++++++++++++++++++++------- 7 files changed, 150 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index ad2acdc..2b1b752 100644 --- a/README.md +++ b/README.md @@ -44,14 +44,19 @@ official distribution of the upstream project. curl -fsSL https://raw.githubusercontent.com/AmeerJ97/grok-cli-vertex/main/install.sh | bash ``` +The script-installed command is `grok-vertex` and the binary is installed under +`~/.grok-vertex/bin`. This intentionally avoids clobbering the official x.ai +CLI installed by `curl -fsSL https://x.ai/cli/install.sh | bash`, which owns +`~/.grok/bin/grok` and the `grok` command. + **Local source install** (requires Bun on PATH): ```bash bun install bun run build mkdir -p ~/.local/bin -printf '#!/usr/bin/env bash\nexec %q/dist/index.js "$@"\n' "$PWD" > ~/.local/bin/grok -chmod +x ~/.local/bin/grok +printf '#!/usr/bin/env bash\nexec %q/dist/index.js "$@"\n' "$PWD" > ~/.local/bin/grok-vertex +chmod +x ~/.local/bin/grok-vertex ``` Do not use `npm install -g grok-dev` or `bun add -g grok-dev` for this Vertex @@ -61,10 +66,10 @@ inherited npm package can be xAI-only and may ignore saved Vertex settings. **Self-management** (script-installed only): ```bash -grok update -grok uninstall -grok uninstall --dry-run -grok uninstall --keep-config +grok-vertex update +grok-vertex uninstall +grok-vertex uninstall --dry-run +grok-vertex uninstall --keep-config ``` **Prerequisites:** a Google Cloud project with Vertex AI enabled, Application Default Credentials for local auth, and a modern terminal emulator for the interactive OpenTUI experience. Native xAI mode still requires a **Grok API key** from [x.ai](https://x.ai). Headless `--prompt` mode does not depend on terminal UI support. If you want host desktop automation via the built-in computer sub-agent, also enable **Accessibility** permission for your terminal app on macOS. @@ -76,9 +81,12 @@ grok uninstall --keep-config **Interactive (default)** — launches the OpenTUI coding agent: ```bash -grok +grok-vertex ``` +If you also use the official x.ai CLI, reserve `grok` for that CLI and use +`grok-vertex` for this fork. + ### Supported terminals For the most reliable interactive OpenTUI experience, use a modern terminal emulator. We currently document and recommend: @@ -93,18 +101,18 @@ Other modern terminals may work, but these are the terminal apps we currently re **Pick a project directory:** ```bash -grok -d /path/to/your/repo +grok-vertex -d /path/to/your/repo ``` **Headless** — one prompt, then exit (scripts, CI, automation): ```bash -grok --prompt "run the test suite and summarize failures" -grok -p "show me package.json" --directory /path/to/project -grok --prompt "refactor X" --max-tool-rounds 30 -grok --prompt "summarize the repo state" --format json -grok --prompt "review the repo overnight" --batch-api -grok --verify +grok-vertex --prompt "run the test suite and summarize failures" +grok-vertex -p "show me package.json" --directory /path/to/project +grok-vertex --prompt "refactor X" --max-tool-rounds 30 +grok-vertex --prompt "summarize the repo state" --format json +grok-vertex --prompt "review the repo overnight" --batch-api +grok-vertex --verify ``` `--batch-api` is inherited from the native xAI backend and is not available on @@ -116,8 +124,8 @@ For a reproducible walkthrough, see [docs/demo-script.md](docs/demo-script.md). **Continue a saved session:** ```bash -grok --session latest -grok -s +grok-vertex --session latest +grok-vertex -s ``` Works in interactive mode too—same flag. @@ -125,7 +133,7 @@ Works in interactive mode too—same flag. **Structured headless output:** ```bash -grok --prompt "summarize the repo state" --format json +grok-vertex --prompt "summarize the repo state" --format json ``` `--format json` emits a newline-delimited JSON event stream instead of the @@ -139,8 +147,8 @@ Grok ships a built-in `**computer**` sub-agent backed by `[agent-desktop](https: Ask for it in natural language, for example: ```bash -grok "Use the computer sub-agent to take a screenshot of my host desktop and tell me what is open." -grok "Use the computer sub-agent to launch Google Chrome, snapshot the UI, and tell me which refs correspond to the address bar and tabs." +grok-vertex "Use the computer sub-agent to take a screenshot of my host desktop and tell me what is open." +grok-vertex "Use the computer sub-agent to launch Google Chrome, snapshot the UI, and tell me which refs correspond to the address bar and tabs." ``` Notes: @@ -169,7 +177,7 @@ and updates CHANGELOG.md from the latest merged commits. Recurring schedules require the background daemon: ```bash -grok daemon --background +grok-vertex daemon --background ``` Use `/schedule` in the TUI to browse saved schedules. One-time schedules start @@ -179,13 +187,13 @@ daemon is active. **List Grok models and pricing hints:** ```bash -grok models +grok-vertex models ``` **Pass an opening message without another prompt:** ```bash -grok fix the flaky test in src/foo.test.ts +grok-vertex fix the flaky test in src/foo.test.ts ``` Media generation commands are inherited from the xAI backend. They are capability @@ -233,7 +241,7 @@ GROK_API_KEY=your_key_here **CLI once:** ```bash -grok -k your_key_here +grok-vertex -k your_key_here ``` **Saved in user settings** — `~/.grok/user-settings.json`: @@ -284,10 +292,10 @@ This fork routes Grok traffic through **Google Cloud Vertex AI** as the preferre ```bash # CLI flag -grok --provider vertex +grok-vertex --provider vertex # Or via env var -GROK_PROVIDER=vertex GROK_VERTEX_PROJECT_ID=my-gcp-project grok +GROK_PROVIDER=vertex GROK_VERTEX_PROJECT_ID=my-gcp-project grok-vertex # Or save in ~/.grok/user-settings.json { @@ -370,7 +378,7 @@ Send a voice note or audio attachment in Telegram and Grok will transcribe it wi Optional headless flow when you do not want the TUI open: ```bash -grok telegram-bridge +grok-vertex telegram-bridge ``` Treat the bot token like a password. @@ -443,8 +451,8 @@ All settings are saved in `~/.grok/user-settings.json` (user) and `.grok/setting Run `**/verify`** in the TUI or `**--verify`** on the CLI to verify your app locally: ```bash -grok --verify -grok -d /path/to/your/app --verify +grok-vertex --verify +grok-vertex -d /path/to/your/app --verify ``` The agent inspects your project, figures out how to build and run it, spins up a sandbox, and produces a verification report with screenshots and video evidence. Works with any app type. @@ -492,7 +500,7 @@ uses Google ADC and `GROK_VERTEX_PROJECT_ID`. export GROK_API_KEY=your_key_here # Or save to user settings -grok -k your_key_here +grok-vertex -k your_key_here ``` Get native xAI API keys from [x.ai](https://x.ai). diff --git a/docs/maintainer-runbook.md b/docs/maintainer-runbook.md index 9fddcb7..092ded8 100644 --- a/docs/maintainer-runbook.md +++ b/docs/maintainer-runbook.md @@ -81,8 +81,10 @@ Releases are produced by `.github/workflows/release.yml`. 5. Confirm `checksums.txt` is present in the GitHub Release. Release artifacts are standalone binaries built with Bun. The install script -should prefer release assets when available and should keep update/uninstall -behavior script-managed. +should prefer release assets when available, install the fork as `grok-vertex` +under `~/.grok-vertex/bin`, and keep update/uninstall behavior script-managed. +Do not reuse `~/.grok/bin/grok`; that path belongs to the official x.ai CLI +installer and will cause PATH and metadata collisions. ## Troubleshooting diff --git a/docs/public-repo-audit.md b/docs/public-repo-audit.md index c884008..60676db 100644 --- a/docs/public-repo-audit.md +++ b/docs/public-repo-audit.md @@ -58,6 +58,9 @@ Completed in this branch: runbook. - Tightened GitHub templates so blank issues are disabled and the PR checklist matches the CI gate more closely. +- Separated the script-managed Vertex fork install from the official x.ai CLI: + new installs use `grok-vertex` under `~/.grok-vertex/bin`, while legacy + script-managed metadata remains readable for update/uninstall compatibility. - Updated GitHub repository metadata: homepage, topics, wiki setting, vulnerability alerts, and private vulnerability reporting. diff --git a/install.sh b/install.sh index 8f3bdfd..99b610d 100755 --- a/install.sh +++ b/install.sh @@ -1,13 +1,13 @@ #!/usr/bin/env bash set -euo pipefail -APP="grok" +APP="grok-vertex" REPO="AmeerJ97/grok-cli-vertex" RELEASES_API="https://api.github.com/repos/${REPO}/releases" -USER_DIR="${HOME}/.grok" +USER_DIR="${HOME}/.grok-vertex" INSTALL_DIR="${USER_DIR}/bin" METADATA_PATH="${USER_DIR}/install.json" -PATH_MARKER="# grok" +PATH_MARKER="# grok-cli-vertex" requested_version="" binary_path="" @@ -22,7 +22,7 @@ Install grok-cli-vertex from GitHub Releases. Usage: curl -fsSL https://raw.githubusercontent.com/AmeerJ97/grok-cli-vertex/main/install.sh | bash curl -fsSL https://raw.githubusercontent.com/AmeerJ97/grok-cli-vertex/main/install.sh | bash -s -- --version 1.1.4 - bash install.sh --binary /path/to/grok + bash install.sh --binary /path/to/grok-standalone Options: -v, --version Install a specific version @@ -102,10 +102,10 @@ resolve_target() { TARGET="${OS}-${ARCH}" if [[ "$TARGET" == windows-* ]]; then ASSET_NAME="grok-${TARGET}.exe" - BINARY_NAME="grok.exe" + BINARY_NAME="${APP}.exe" else ASSET_NAME="grok-${TARGET}" - BINARY_NAME="grok" + BINARY_NAME="${APP}" fi } @@ -351,8 +351,8 @@ echo "" echo "Grok ${INSTALLED_VERSION} installed to ${INSTALL_DIR}/${BINARY_NAME}" echo "" echo "Run:" -echo " grok --help" +echo " ${BINARY_NAME} --help" echo "" echo "To uninstall later:" -echo " grok uninstall" +echo " ${BINARY_NAME} uninstall" echo "" diff --git a/package.json b/package.json index d94b96c..c3b7c14 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,8 @@ } }, "bin": { - "grok": "dist/index.js" + "grok": "dist/index.js", + "grok-vertex": "dist/index.js" }, "scripts": { "dev": "bun run src/index.ts", diff --git a/src/utils/install-manager.test.ts b/src/utils/install-manager.test.ts index 3f5fde4..c33b105 100644 --- a/src/utils/install-manager.test.ts +++ b/src/utils/install-manager.test.ts @@ -34,6 +34,8 @@ describe("getReleaseTargetForPlatform", () => { expect(getReleaseTargetForPlatform("darwin", "x64")?.assetName).toBe("grok-darwin-arm64"); expect(getReleaseTargetForPlatform("linux", "x64")?.assetName).toBe("grok-linux-x64"); expect(getReleaseTargetForPlatform("win32", "x64")?.assetName).toBe("grok-windows-x64.exe"); + expect(getReleaseTargetForPlatform("linux", "x64")?.binaryName).toBe("grok-vertex"); + expect(getReleaseTargetForPlatform("win32", "x64")?.binaryName).toBe("grok-vertex.exe"); expect(getReleaseTargetForPlatform("linux", "arm64")).toBeNull(); }); }); @@ -110,6 +112,34 @@ describe("getScriptInstallContext", () => { const ctx = getScriptInstallContext(homeDir); expect(ctx?.metadata.installMethod).toBe("script"); expect(ctx?.binaryPath).toBe(path.join(installDir, currentTarget!.binaryName)); + expect(ctx?.userDir).toBe(path.join(homeDir, ".grok-vertex")); + }); + + it("can discover metadata from the active executable path", () => { + const homeDir = createTempDir("grok-ctx-exec-"); + const installHome = path.join(homeDir, ".grok-vertex"); + const installDir = path.join(installHome, "bin"); + const currentTarget = getReleaseTargetForPlatform()!; + const binaryPath = path.join(installDir, currentTarget.binaryName); + fs.mkdirSync(installDir, { recursive: true }); + + saveScriptInstallMetadata( + { + schemaVersion: 1, + installMethod: "script" as const, + version: "1.2.3", + repo: GROK_GITHUB_REPO, + binaryPath, + installDir, + assetName: currentTarget.assetName, + target: currentTarget.key, + installedAt: "2026-04-03T00:00:00.000Z", + }, + homeDir, + ); + + const ctx = getScriptInstallContext(homeDir, [binaryPath]); + expect(ctx?.metadataPath).toBe(path.join(installHome, "install.json")); }); it("returns null when no metadata exists", () => { @@ -173,7 +203,7 @@ describe("isCurrentScriptManagedInstall", () => { }); describe("buildScriptUninstallPlan", () => { - it("removes the full ~/.grok directory by default", () => { + it("removes the full ~/.grok-vertex install directory by default", () => { const homeDir = createTempDir("grok-uninstall-"); const installDir = getScriptInstallDir(homeDir); const currentTarget = getReleaseTargetForPlatform()!; @@ -195,7 +225,7 @@ describe("buildScriptUninstallPlan", () => { ); const plan = buildScriptUninstallPlan({}, homeDir); - expect(plan?.removePaths).toContain(path.join(homeDir, ".grok")); + expect(plan?.removePaths).toContain(path.join(homeDir, ".grok-vertex")); }); it("keeps config and data when requested", () => { @@ -220,7 +250,7 @@ describe("buildScriptUninstallPlan", () => { ); const plan = buildScriptUninstallPlan({ keepConfig: true, keepData: true }, homeDir); - expect(plan?.removePaths).not.toContain(path.join(homeDir, ".grok")); + expect(plan?.removePaths).not.toContain(path.join(homeDir, ".grok-vertex")); expect(plan?.removePaths).toContain(path.join(installDir, currentTarget.binaryName)); }); }); diff --git a/src/utils/install-manager.ts b/src/utils/install-manager.ts index 7daa54d..988717e 100644 --- a/src/utils/install-manager.ts +++ b/src/utils/install-manager.ts @@ -13,7 +13,7 @@ export const SCRIPT_INSTALL_METHOD = "script"; const FETCH_TIMEOUT_MS = 5_000; const INSTALL_SCHEMA_VERSION = 1; -const PATH_MARKER = "# grok"; +const PATH_MARKER = "# grok-cli-vertex"; const CONFIG_FILENAMES = ["user-settings.json", "AGENTS.md"]; const DATA_ENTRIES = ["daemon.pid", "delegations", "grok.db", "models", "schedules"]; @@ -41,6 +41,8 @@ export interface ScriptInstallContext { metadata: ScriptInstallMetadata; target: ReleaseTarget; binaryPath: string; + metadataPath: string; + userDir: string; } export interface ScriptUpdateRunResult { @@ -81,26 +83,32 @@ export function getGrokUserDir(homeDir = os.homedir()): string { return path.join(homeDir, ".grok"); } +export function getGrokVertexInstallUserDir(homeDir = os.homedir()): string { + return path.join(homeDir, ".grok-vertex"); +} + export function getScriptInstallDir(homeDir = os.homedir()): string { - return path.join(getGrokUserDir(homeDir), "bin"); + return path.join(getGrokVertexInstallUserDir(homeDir), "bin"); } export function getInstallMetadataPath(homeDir = os.homedir()): string { - return path.join(getGrokUserDir(homeDir), "install.json"); + return path.join(getGrokVertexInstallUserDir(homeDir), "install.json"); } export function getReleaseTargetForPlatform(platform = process.platform, arch = process.arch): ReleaseTarget | null { if (platform === "darwin" && (arch === "arm64" || arch === "x64")) - return { key: "darwin-arm64", assetName: "grok-darwin-arm64", binaryName: "grok" }; + return { key: "darwin-arm64", assetName: "grok-darwin-arm64", binaryName: "grok-vertex" }; if (platform === "linux" && arch === "x64") - return { key: "linux-x64", assetName: "grok-linux-x64", binaryName: "grok" }; + return { key: "linux-x64", assetName: "grok-linux-x64", binaryName: "grok-vertex" }; if (platform === "win32" && arch === "x64") - return { key: "windows-x64", assetName: "grok-windows-x64.exe", binaryName: "grok.exe" }; + return { key: "windows-x64", assetName: "grok-windows-x64.exe", binaryName: "grok-vertex.exe" }; return null; } -export function loadScriptInstallMetadata(homeDir = os.homedir()): ScriptInstallMetadata | null { - const metadataPath = getInstallMetadataPath(homeDir); +export function loadScriptInstallMetadata( + homeDir = os.homedir(), + metadataPath = getInstallMetadataPath(homeDir), +): ScriptInstallMetadata | null { try { if (!fs.existsSync(metadataPath)) return null; const parsed = JSON.parse(fs.readFileSync(metadataPath, "utf8")) as Partial; @@ -136,16 +144,34 @@ export function saveScriptInstallMetadata(metadata: ScriptInstallMetadata, homeD fs.writeFileSync(metadataPath, `${JSON.stringify(metadata, null, 2)}\n`, { mode: 0o600 }); } -export function getScriptInstallContext(homeDir = os.homedir()): ScriptInstallContext | null { +export function getScriptInstallContext( + homeDir = os.homedir(), + executablePaths = getCurrentExecutablePaths(), +): ScriptInstallContext | null { const target = getReleaseTargetForPlatform(); if (!target) return null; + for (const metadataPath of getCandidateInstallMetadataPaths(homeDir, executablePaths)) { + const metadata = loadScriptInstallMetadata(homeDir, metadataPath); + if (!metadata) continue; + const userDir = path.dirname(metadataPath); + return { + metadata, + target: getReleaseTargetForPlatformKey(metadata.target) ?? target, + binaryPath: metadata.binaryPath, + metadataPath, + userDir, + }; + } + const metadata = loadScriptInstallMetadata(homeDir); if (metadata) { return { metadata, target: getReleaseTargetForPlatformKey(metadata.target) ?? target, binaryPath: metadata.binaryPath, + metadataPath: getInstallMetadataPath(homeDir), + userDir: getGrokVertexInstallUserDir(homeDir), }; } @@ -160,7 +186,7 @@ export function isCurrentScriptManagedInstall( homeDir = os.homedir(), executablePaths = getCurrentExecutablePaths(), ): boolean { - const context = getScriptInstallContext(homeDir); + const context = getScriptInstallContext(homeDir, executablePaths); if (!context) return false; const scriptBinaryPath = normalizeComparablePath(context.binaryPath); @@ -247,7 +273,7 @@ export function buildScriptUninstallPlan( const context = getScriptInstallContext(homeDir); if (!context) return null; - const userDir = getGrokUserDir(homeDir); + const userDir = context.userDir; const removePaths = new Set(); const pruneDirs = new Set(); @@ -255,10 +281,10 @@ export function buildScriptUninstallPlan( removePaths.add(userDir); } else { removePaths.add(context.binaryPath); - removePaths.add(getInstallMetadataPath(homeDir)); + removePaths.add(context.metadataPath); if (!options.keepConfig) for (const f of CONFIG_FILENAMES) removePaths.add(path.join(userDir, f)); if (!options.keepData) for (const e of DATA_ENTRIES) removePaths.add(path.join(userDir, e)); - pruneDirs.add(getScriptInstallDir(homeDir)); + pruneDirs.add(context.metadata.installDir); pruneDirs.add(userDir); } @@ -318,18 +344,38 @@ function normalizeComparablePath(filePath: string): string { function getReleaseTargetForPlatformKey(key: string): ReleaseTarget | null { switch (key) { case "darwin-arm64": - return { key, assetName: "grok-darwin-arm64", binaryName: "grok" }; + return { key, assetName: "grok-darwin-arm64", binaryName: "grok-vertex" }; case "darwin-x64": - return { key: "darwin-arm64", assetName: "grok-darwin-arm64", binaryName: "grok" }; + return { key: "darwin-arm64", assetName: "grok-darwin-arm64", binaryName: "grok-vertex" }; case "linux-x64": - return { key, assetName: "grok-linux-x64", binaryName: "grok" }; + return { key, assetName: "grok-linux-x64", binaryName: "grok-vertex" }; case "windows-x64": - return { key, assetName: "grok-windows-x64.exe", binaryName: "grok.exe" }; + return { key, assetName: "grok-windows-x64.exe", binaryName: "grok-vertex.exe" }; default: return null; } } +function getCandidateInstallMetadataPaths(homeDir: string, executablePaths: string[]): string[] { + const candidates = new Set(); + + for (const executablePath of executablePaths) { + const normalized = path.resolve(executablePath); + const binDir = path.dirname(normalized); + if (path.basename(binDir) === "bin") { + candidates.add(path.join(path.dirname(binDir), "install.json")); + } + } + + candidates.add(getInstallMetadataPath(homeDir)); + + // Legacy installs before this fork separated from the official x.ai CLI used + // ~/.grok/install.json. Keep reading it so existing users can still update or + // uninstall, but new installs go to ~/.grok-vertex. + candidates.add(path.join(getGrokUserDir(homeDir), "install.json")); + return [...candidates]; +} + async function resolveReleaseDownload(target: ReleaseTarget): Promise { const release = await fetchReleaseJson(`${GROK_RELEASES_API}/latest`); if (!release) return null;