Skip to content

Add Grid CLI core infrastructure#134

Merged
jklein24 merged 2 commits intomainfrom
jk/grid-cli-core
Feb 4, 2026
Merged

Add Grid CLI core infrastructure#134
jklein24 merged 2 commits intomainfrom
jk/grid-cli-core

Conversation

@jklein24
Copy link
Contributor

  • Add CLI package with TypeScript configuration
  • Add config module for credential loading (~/.grid-credentials or env vars)
  • Add HTTP client with Basic Auth support
  • Add JSON output formatting utilities
  • Add minimal CLI entry point with Commander.js setup
  • Update project .gitignore, Makefile, and package.json with CLI targets

Copy link
Contributor Author

jklein24 commented Jan 27, 2026

This stack of pull requests is managed by Graphite. Learn more about stacking.

This was referenced Jan 27, 2026
- Add CLI package with TypeScript configuration
- Add config module for credential loading (~/.grid-credentials or env vars)
- Add HTTP client with Basic Auth support
- Add JSON output formatting utilities
- Add minimal CLI entry point with Commander.js setup
- Update project .gitignore, Makefile, and package.json with CLI targets
@jklein24 jklein24 marked this pull request as ready for review February 1, 2026 06:31
@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 1, 2026

Greptile Overview

Greptile Summary

This PR adds a new cli/ TypeScript package (grid-cli) with a minimal Commander.js entrypoint, a config module for loading credentials from env or ~/.grid-credentials, a fetch-based HTTP client using Basic Auth, and JSON output helpers. It also wires up root-level Makefile and npm scripts for installing/building/running the CLI, and updates .gitignore for local credential/build artifacts.

Key issues to address are around request URL construction (base URL + relative path) and ensuring credential file permissions are actually tightened when overwriting existing files.

Confidence Score: 3/5

  • This PR is mergeable but has a couple of correctness/security-footgun issues to fix first.
  • Most changes are straightforward scaffolding, but URL joining semantics in the client can easily send requests to the wrong endpoint depending on how paths are passed, and credential file permissions may not be tightened on overwrite as intended. Prior-thread items (DOM lib for fetch types, JSON.parse error handling) should also land to avoid runtime/TS issues.
  • cli/src/client.ts, cli/src/config.ts, cli/src/index.ts

Important Files Changed

Filename Overview
.gitignore Adds ignores for CLI credentials and cli/dist output.
Makefile Adds make targets for installing/building/running the new CLI; fixes missing newline.
cli/package.json Introduces standalone CLI package with commander, TypeScript build, and Node>=18 engine.
cli/src/client.ts Adds fetch-based HTTP client with Basic Auth; watch out for URL joining semantics if baseUrl lacks trailing slash.
cli/src/config.ts Adds config loading from env or JSON file and saves credentials; consider ensuring credential file permissions are tightened on overwrite.
cli/src/index.ts Adds commander program entrypoint and exports helpers; parsing on import can cause side effects for consumers.
cli/src/output.ts Adds JSON output formatting helpers and exit code handling on error responses.
cli/tsconfig.json Adds TS config for CLI build output; may need DOM lib for fetch types (already noted in prior thread).
package.json Adds root npm scripts to install/build/run the CLI package.

Sequence Diagram

sequenceDiagram
  participant User as User
  participant CLI as grid CLI (commander)
  participant Config as config.ts
  participant FS as ~/.grid-credentials (fs)
  participant Env as process.env
  participant Client as GridClient
  participant API as Grid API

  User->>CLI: run `grid ...` (options)
  CLI->>Config: loadConfig({configPath, baseUrl})
  alt configPath provided
    Config->>FS: readFileSync(configPath)
    FS-->>Config: JSON string
    Config-->>CLI: GridConfig
  else no configPath
    Config->>Env: read GRID_* vars
    Config->>FS: readFileSync(~/.grid-credentials) if exists
    FS-->>Config: JSON string
    Config-->>CLI: GridConfig
  end

  CLI->>Client: new GridClient(config)
  CLI->>Client: request(method, path, {params, body})
  Client->>API: fetch(url, headers: Basic Auth)
  API-->>Client: JSON or text response
  Client-->>CLI: ApiResponse{success,data|error}
  CLI-->>User: output JSON (output.ts)
  opt error
    CLI-->>User: sets process.exitCode = 1
  end
Loading

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

3 files reviewed, 5 comments

Edit Code Review Agent Settings | Greptile

@jklein24
Copy link
Contributor Author

jklein24 commented Feb 1, 2026

Greptile Review Response

Comment 1 (cli/src/config.ts:22) - JSON.parse for credentials

Applied. Added try-catch around JSON.parse with a clear error message for malformed credentials files.

Comment 2 (cli/src/config.ts:38) - JSON.parse for config

Applied. Added try-catch around JSON.parse with a clear error message for malformed config files.

Comment 3 (cli/src/config.ts:69) - JSON.parse for save credentials

Applied. Added try-catch that starts fresh with an empty object if the existing credentials file is malformed.

Comment 4 (cli/tsconfig.json:5) - Add DOM to lib

Not applicable. Node.js 18+ has native fetch and @types/node already provides the type definitions. Adding DOM lib would introduce browser-specific types (window, document, etc.) that don't exist in Node.

Comment 5 (cli/package.json:25) - Add engines field

Applied. Added engines field specifying Node.js >=18.0.0 to document the native fetch requirement.


Review response generated using /pr-review-respond Claude command.

- Add try-catch error handling for JSON.parse in config loading
- Add engines field specifying Node.js >=18.0.0 requirement

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

9 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

path: string,
params?: Record<string, string | number | boolean | undefined>
): string {
const url = new URL(path, this.config.baseUrl);
Copy link
Contributor

Choose a reason for hiding this comment

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

new URL(path, this.config.baseUrl) will drop the last path segment of baseUrl when baseUrl doesn’t end with / and path is relative (e.g., baseUrl https://api.lightspark.com/grid/2025-10-13 + path customers becomes https://api.lightspark.com/grid/customers). This will cause requests to hit the wrong endpoint unless callers always pass an absolute /... path or baseUrl always includes a trailing slash.

Also affects request() calls via buildUrl().

Consider normalizing baseUrl to include a trailing / (or always prefix path with /) before constructing the URL.

Context Used: Context from dashboard - CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: cli/src/client.ts
Line: 37:37

Comment:
`new URL(path, this.config.baseUrl)` will drop the last path segment of `baseUrl` when `baseUrl` doesn’t end with `/` and `path` is relative (e.g., baseUrl `https://api.lightspark.com/grid/2025-10-13` + path `customers` becomes `https://api.lightspark.com/grid/customers`). This will cause requests to hit the wrong endpoint unless callers always pass an absolute `/...` path or `baseUrl` always includes a trailing slash.

Also affects `request()` calls via `buildUrl()`.

Consider normalizing `baseUrl` to include a trailing `/` (or always prefix `path` with `/`) before constructing the URL.

**Context Used:** Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=21abe025-35ab-4ae8-a4a1-0071c2ac3b98))

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +85 to +87
fs.writeFileSync(credentialsPath, JSON.stringify(merged, null, 2), {
mode: 0o600,
});
Copy link
Contributor

Choose a reason for hiding this comment

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

fs.writeFileSync(..., { mode: 0o600 }) only reliably sets permissions on file creation; if the file already exists with broader permissions, Node won’t necessarily tighten them. This can leave credentials readable by other users depending on the prior mode.

If you want to guarantee 0600, you likely need to chmod after writing when the file already exists.

Context Used: Context from dashboard - CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: cli/src/config.ts
Line: 85:87

Comment:
`fs.writeFileSync(..., { mode: 0o600 })` only reliably sets permissions on file creation; if the file already exists with broader permissions, Node won’t necessarily tighten them. This can leave credentials readable by other users depending on the prior mode.

If you want to guarantee `0600`, you likely need to `chmod` after writing when the file already exists.

**Context Used:** Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=21abe025-35ab-4ae8-a4a1-0071c2ac3b98))

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +40 to +42
export { program, getClient, GridClient, GridConfig };

program.parse(process.argv);
Copy link
Contributor

Choose a reason for hiding this comment

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

program.parse(process.argv) runs on import, which makes this module hard to use as a library (and can surprise tests/other code that imports program or GridClient). This is especially relevant since you also export { program, getClient, ... }.

If you intend index.ts to be both the CLI entrypoint and an importable module, consider moving program.parse(...) behind a require.main === module / import.meta guard or into a separate bin entry file.

Context Used: Context from dashboard - CLAUDE.md (source)

Prompt To Fix With AI
This is a comment left during a code review.
Path: cli/src/index.ts
Line: 40:42

Comment:
`program.parse(process.argv)` runs on import, which makes this module hard to use as a library (and can surprise tests/other code that imports `program` or `GridClient`). This is especially relevant since you also `export { program, getClient, ... }`.

If you intend `index.ts` to be both the CLI entrypoint and an importable module, consider moving `program.parse(...)` behind a `require.main === module` / `import.meta` guard or into a separate `bin` entry file.

**Context Used:** Context from `dashboard` - CLAUDE.md ([source](https://app.greptile.com/review/custom-context?memory=21abe025-35ab-4ae8-a4a1-0071c2ac3b98))

How can I resolve this? If you propose a fix, please make it concise.

@jklein24 jklein24 requested a review from shreyav February 3, 2026 19:58
@jklein24 jklein24 merged commit 012b259 into main Feb 4, 2026
5 checks passed
@jklein24 jklein24 deleted the jk/grid-cli-core branch February 4, 2026 06:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants