Skip to content

Conversation

@lutter
Copy link
Collaborator

@lutter lutter commented Jan 19, 2026

This is all Claude-generated code, I haven't even looked at it or tried it. It's mostly here for informational purposes

@lutter lutter force-pushed the lutter/gnd-cli branch 2 times, most recently from 0f39307 to 021d897 Compare January 20, 2026 04:32
@lutter lutter force-pushed the lutter/gnd-cli branch 5 times, most recently from fbf5d36 to 64a077d Compare January 21, 2026 00:10
@lutter lutter marked this pull request as ready for review January 21, 2026 01:46
@dimitrovmaksim
Copy link
Member

dimitrovmaksim commented Jan 21, 2026

Couple of things I noticed for the commands that i'm familiar with:

  1. test
    • It expects matchstick to be a node_module installed via matchstick-as (the equivalent of graph-ts for matchstick). In the ts graph-cli we used a lib to download and execute binaries, so it probably got confused by that.
      EDIT: I now see that the binaryinstall lib was removed and the matchstick bin was directly fetched from the repo into node_modules/.bin/, but I don't see the test command doing it here
    • I would probably remove the binary path and leave only the Docker path, or at least make it the default (or phase out the test command completelly)
  2. add
    • By default the add command indexes events as entities. This caused some issues with duplicated entities and abi overwrites. If there were collision in event/entity names with existing events/entity names it would prepend the new entity name with the contract name. It seems that Claude has cut that whole logic off and just ignores collsions, unless the --merge-entities flag is passed. IMO this descision back then caused more trouble than benefit, so I would remove the code that touches the schema with the add command and leave this to the developer. Anyways it seems rare that entites match events 1:1.
    • the to_kebab_case function seems to not handle some cases correctly
      assert_eq!(to_kebab_case("ERC20Token"), "e-r-c20-token");
      (i would expect the result in this case to be either erc-20-token or erc20-token in the best case scenario). The TS cli uses the gluegun/loadash implementation for kebabCase

@lutter lutter force-pushed the lutter/gnd-cli branch 3 times, most recently from 679785f to 0224afe Compare January 21, 2026 23:06
lutter and others added 16 commits January 22, 2026 13:03
- Move dev command logic to commands/dev.rs module
- Add subcommand structure with stubs for all graph-cli commands:
  codegen, build, deploy, init, add, create, remove, auth, publish, test, clean
- Add version output showing graph-cli compatibility version (0.98.1)
- Preserve all existing dev command functionality and options

This is Phase 1 of the gnd CLI expansion to become a drop-in
replacement for the TypeScript graph-cli.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add the `gnd clean` command to remove build artifacts and generated files.

- Removes `generated/` and `build/` directories by default
- Supports custom paths via --codegen-dir and --build-dir flags
- Includes unit tests for both success and missing directory cases
- Matches graph-cli clean command behavior

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add the `gnd auth` command to save deploy keys for Graph Node authentication.

- Stores keys in ~/.graph-cli.json (compatible with TS graph-cli)
- Supports custom node URLs via --node flag
- Defaults to Subgraph Studio URL
- Validates Studio deploy key format (32 hex chars)
- Includes unit tests for key storage and retrieval

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a JSON-RPC client for communicating with Graph Node's admin API.
This client is used by the create and remove commands to register and
unregister subgraph names.

Features:
- HTTP/HTTPS support with protocol validation
- Optional access token authentication via Bearer header
- User-Agent header with gnd version
- 120 second timeout for long operations
- create_subgraph and remove_subgraph methods

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add commands to register and unregister subgraph names with a Graph Node.

Both commands:
- Use GraphNodeClient for JSON-RPC communication
- Support --node/-g flag for Graph Node URL (required)
- Support --access-token flag for authentication
- Automatically read deploy key from ~/.graph-cli.json if no token provided
- Include unit tests for CLI argument parsing

Usage:
  gnd create <name> --node <url> [--access-token <token>]
  gnd remove <name> --node <url> [--access-token <token>]

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add the output module with spinner functionality matching the TypeScript
graph-cli output format (gluegun/ora style). This provides:

- Spinner struct for progress indicators with colored output
- with_spinner() helper for wrapping long-running operations
- SpinnerResult for operations that can warn or fail
- Checkmark/cross/warning symbols matching TS CLI output

The module uses indicatif and console crates for terminal handling.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit adds the foundation for code generation functionality:

- codegen/typescript.rs: AST builders for generating TypeScript/AssemblyScript
  code (classes, methods, types, imports)
- codegen/types.rs: Type conversion utilities between GraphQL, Ethereum ABI,
  and AssemblyScript types
- codegen/schema.rs: SchemaCodeGenerator that generates entity classes from
  GraphQL schemas, matching the TS CLI output format

The schema code generator supports:
- Entity classes with constructor, save(), load(), loadInBlock()
- Field getters and setters with proper type conversions
- Nullable field handling with proper null checks
- Entity reference fields (stored as string IDs)
- Derived fields with loader classes
- Multiple ID field types (String, Bytes, Int8)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements codegen/abi.rs that generates AssemblyScript bindings from
Ethereum contract ABIs:

- Event classes with typed parameters and getters
- Call classes for function calls with inputs/outputs
- Smart contract class with typed call methods
- Tuple handling for nested struct types
- Support for indexed event parameters
- Reserved word escaping for AssemblyScript

The generated code matches the format of the TypeScript graph-cli.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements codegen/template.rs that generates AssemblyScript classes
for subgraph data source templates:

- Template class extending DataSourceTemplate
- Static create() method for creating new data sources
- Static createWithContext() method with context parameter
- Support for Ethereum (Address param) and file (cid param) templates

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements formatter.rs that shells out to Prettier to format generated
TypeScript/AssemblyScript code:

- format_typescript() for strict formatting with error handling
- try_format_typescript() for graceful fallback when prettier unavailable
- Tries npx, pnpx, and global prettier installations
- is_prettier_available() utility to check for prettier

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the `gnd codegen` command that generates AssemblyScript types
from a subgraph manifest:

- Parses subgraph.yaml to extract schema, ABIs, and templates
- Generates schema.ts from GraphQL schema using SchemaCodeGenerator
- Generates <ABI>.ts for each ABI using AbiCodeGenerator
- Generates templates.ts for data source templates
- Formats output with Prettier when available
- Adds --output-dir, --skip-migrations, --watch, --ipfs flags

Also adds:
- Step/StepResult output utilities for consistent CLI formatting
- serde_yaml dependency for manifest parsing

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the --watch/-w flag for the codegen command that:

- Watches the manifest, schema, and ABI files for changes
- Automatically regenerates types when files are modified
- Uses debouncing to batch rapid file changes
- Shows informative messages about detected changes

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Implements the migrations framework matching the TypeScript graph-cli
behavior. Migrations automatically update subgraph manifests to newer
versions based on the installed graph-ts dependency.

Spec version migrations:
- 0.0.1 -> 0.0.2: Bump for top-level templates
- 0.0.2/0.0.3 -> 0.0.4: Bump for feature management

API version migrations (require specific graph-ts versions):
- 0.0.1 -> 0.0.2: Requires graph-ts > 0.5.1
- 0.0.2 -> 0.0.3: Requires graph-ts > 0.12.0
- 0.0.3 -> 0.0.4: Requires graph-ts > 0.17.0
- 0.0.4 -> 0.0.5: Requires graph-ts >= 0.22.0
- 0.0.5 -> 0.0.6: Requires graph-ts >= 0.24.0

The codegen command now runs migrations by default, with a
--skip-migrations flag to bypass them.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add IPFS upload functionality to the build command using the Kubo RPC
API. When --ipfs is provided, the build command now:

- Creates an IpfsClient using the Kubo HTTP API
- Uploads schema, ABI, and WASM mapping files to IPFS
- Updates the manifest with IPFS links (using {"/": "/ipfs/<hash>"} format)
- Uploads the updated manifest and returns its hash

The deploy command now uses this functionality to automatically build
and upload subgraphs before deploying, eliminating the need for users
to manually provide --ipfs-hash.

Changes:
- Add services/ipfs.rs with IpfsClient for Kubo RPC API
- Update build command to return BuildResult with optional IPFS hash
- Add upload_to_ipfs() and helpers for manifest transformation
- Update deploy command to use build's IPFS upload

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
lutter and others added 23 commits January 22, 2026 13:11
Add tests for:
- All Protocol enum variants' Display implementation
- from_subgraph mode in should_run_interactive
- InitOpt default values verification

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add test to verify that single-level array fields like [String!]! are
correctly generated with Array<string> type.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Test that the ABI codegen correctly disambiguates:
- Events with the same name but different inputs (Transfer, Transfer1, Transfer2)
- Functions with the same name but different inputs (getSomething, getSomething1)

This verifies the disambiguation logic matches the TS CLI behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for nested array types (matrices) like [[String]], [[Int]],
[[BigInt]], etc. in schema code generation:

- types.rs: Add matrix type mappings for asc_type_for_value(),
  value_to_asc(), and value_from_asc() functions. These now correctly
  generate Array<Array<T>> types and use toXxxMatrix()/fromXxxMatrix()
  methods.

- typescript.rs: Extend ArrayType to support any TypeExpr as inner type
  (not just NamedType), enabling nested array types. Add ArrayType::with_depth()
  helper for creating arrays with arbitrary nesting.

- schema.rs: Replace boolean is_list with list_depth counter to track
  nesting levels. Update value_type_from_field() to wrap base type with
  correct number of brackets. Update type_from_field() to create properly
  nested Array<Array<T>> types.

Add comprehensive tests for:
- Matrix type conversions in types.rs
- Nested array field generation in schema.rs
- list_depth() function correctness
- value_type_from_field() with nested arrays

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add comprehensive tests to verify tuple/struct handling in ABI code
generation:

- test_tuple_types_in_functions: Verifies struct classes are generated
  for both function inputs and outputs, with proper ethereum.Tuple
  extension and component accessors

- test_tuple_types_in_events: Verifies struct classes are generated for
  tuple parameters in events

- test_nested_tuple_types: Verifies nested tuples (struct containing
  struct) generate multiple struct classes with proper hierarchy

- test_tuple_array_types: Verifies tuple[] returns Array<StructType>

These tests cover important edge cases identified in the TS CLI test
suite and ensure tuple/struct handling matches expected behavior.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add a `completions` subcommand that generates shell completion scripts
for bash, elvish, fish, powershell, and zsh. Users can install
completions by adding the output to their shell configuration.

Example usage:
  gnd completions bash >> ~/.bashrc
  gnd completions zsh > ~/.zfunc/_gnd
  gnd completions fish > ~/.config/fish/completions/gnd.fish

This uses the clap_complete crate which generates completions directly
from the clap CLI definition, ensuring they stay in sync with the
actual commands and options.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add additional tests to cover array-related edge cases in ABI code
generation:

- test_array_types_in_events: Verifies array parameters in events
  (address[] and uint256[]) generate correct Array<Address> and
  Array<BigInt> return types

- test_matrix_types_in_functions: Verifies 2D array types (uint256[][])
  generate correct Array<Array<BigInt>> return types

These tests complement the existing tuple array tests and ensure
comprehensive coverage of array-based ABI patterns.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add integration tests that verify gnd codegen produces compatible output
to graph-cli codegen using golden test fixtures from the graph-cli repo.

Changes:
- Add walkdir and similar dev-dependencies for test infrastructure
- Create codegen_verification.rs with tests for 8 fixtures
- Fix ABI preprocessing to use correct default param names
- Fix typescript class method ordering to match graph-cli output

Known differences that are normalized in tests:
- Int8 import (gnd always includes it)
- Trailing commas (gnd uses them)
- 2D array accessors (gnd correctly uses toStringMatrix)

Skipped fixtures with documented reasons:
- derived-from-with-interface: derived field loaders not implemented
- invalid-graphql-schema: gnd generates schema.ts for invalid schemas
- no-network-names: template ABI types not in subdirectories

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Fix 3 previously skipped fixtures so all 11 pass verification:

- derived-from-with-interface: Generate derived field loaders by calling
  generate_derived_loaders() and combining with entity classes
- no-network-names: Generate ABI types in templates/<Name>/ subdirectories
  by parsing template ABIs from manifest and generating them alongside
  the templates.ts file
- invalid-graphql-schema: Add schema validation to reject non-nullable
  lists with nullable members (e.g., [Something]! is invalid)

Additional ABI codegen fixes:
- Include return types in function signatures for call/tryCall
- Generate getValue{N}() getters for unnamed output parameters
- Filter call functions to exclude view/pure (matching graph-cli)
- Sort functions alphabetically for deterministic output

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Embed fixture data directly in the gnd crate instead of requiring
graph-cli to be installed. This removes the GRAPH_CLI_PATH environment
variable dependency and makes tests runnable without external setup.

Added regenerate.sh script for updating fixtures when needed.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The publish command now:
- Builds the subgraph and uploads to IPFS (reusing build command)
- Opens browser to cli.thegraph.com/publish with query params
- Supports --ipfs-hash to skip build and use existing hash
- Supports --subgraph-id and --api-key for updating existing subgraphs
- Supports --protocol-network (arbitrum-one, arbitrum-sepolia)
- Prompts user before opening browser

This matches graph-cli's approach of delegating wallet/GRT handling
to the web UI rather than implementing it in the CLI.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add support for creating a subgraph scaffold from an existing deployed
subgraph. This fetches the manifest and schema from IPFS, validates the
network matches, finds immutable entities, and generates a scaffold with
grafting instructions.

Changes:
- Add IPFS cat/fetch_manifest/fetch_schema methods to IpfsClient
- Add manifest parsing utilities (extract_schema_cid, extract_network,
  get_min_start_block)
- Add GraphQL schema parsing to find immutable entities
- Implement full init_from_subgraph() async function
- Add 11 unit tests for parsing functions

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add comprehensive README.md with command reference for all gnd commands
- Add MIGRATING_FROM_GRAPH_CLI.md guide for users transitioning from graph-cli
- Document all flags, examples, and common workflows
- Mark documentation items as complete in the plan

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Update overall progress to ~98% (only manual testing remaining)
- Mark Phase 12 (Testing & Polish) as complete
- Add documentation file references to status summary
- Document test porting analysis (11/12 success fixtures, NEAR out of scope)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add test infrastructure to verify gnd works as a drop-in replacement
for graph-cli:

- tests/tests/gnd_cli_tests.rs: Integration tests that run with
  GRAPH_CLI pointing to gnd binary, testing codegen/create/deploy
  workflow via block-handlers, value-roundtrip, and int8 tests

- gnd/tests/cli_commands.rs: Standalone command tests for init, add,
  codegen, build, and clean commands that don't require Graph Node

- justfile: Add test-gnd-cli and test-gnd-commands targets

- Update plan/spec docs with Phase 13: CLI Integration Tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Integrate InputSchema::validate into gnd codegen and build commands to
give developers early feedback about schema issues that would cause
deployment failures.

- Add InputSchema::validate() function and InvalidSchema error variant
- Add validation module with validate_schema() and format_schema_errors()
- Extract spec_version from manifest in both codegen and build commands
- Run schema validation before code generation and compilation
- Fail with clear error messages listing all validation issues found

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add manifest validation to gnd that catches common errors before deployment:
- At least one data source exists
- All data sources use the same network
- Consistent API versions across data sources (>= 0.0.5 must be uniform)
- Spec version within supported range
- Referenced files exist (schema, mappings, ABIs)
- ABI files are valid JSON

Create shared pure validation functions in graph crate that both graph-node
and gnd can reuse. Refactor graph-node's UnvalidatedSubgraphManifest::validate()
to use these shared functions, eliminating code duplication.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change the default CLI for integration tests from graph-cli
(node_modules/.bin/graph) to gnd (../target/debug/gnd). The GRAPH_CLI
environment variable is preserved for fallback/compatibility testing.

- Update default CLI path in tests/src/config.rs
- Add gnd binary check to test-integration in justfile
- Add build-all target to build both graph-node and gnd
- Update CLAUDE.md documentation

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The integration tests now use gnd as the default CLI, so the test
subgraphs no longer need @graphprotocol/graph-cli as a devDependency.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When events or function return types contain tuples (structs) with named
components, the generated AssemblyScript code should have getters with
those names (e.g., `get addr()`, `get amount()`) instead of generic names
like `get value0()`, `get value1()`.

The issue was that ethabi's `ParamType::Tuple` only contains the component
types, not their names - the names are lost during ABI parsing.

This fix:
- Parses the raw ABI JSON to extract component names before they're lost
- Adds a `ComponentNames` struct to hold nested component name information
- Threads component names through the tuple generation code path
- Uses actual names when available, falling back to `valueN` naming

This enables proper struct field access like `event.params.asset.addr`
instead of requiring `event.params.asset.value0`.

Fixes the `declared-calls-struct-fields` integration test.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a subgraph manifest contains data sources with `kind: subgraph`,
gnd now:

1. Detects these subgraph data sources and extracts the IPFS address
2. Fetches the referenced subgraph's manifest from IPFS
3. Extracts the schema CID from the manifest
4. Fetches the schema and generates entity types (without store methods)
5. Writes types to `generated/subgraph-{IPFS_HASH}.ts`

This enables subgraphs to reference and consume data from other deployed
subgraphs, generating proper TypeScript types for the entities they expose.

The entity types are generated without `save()` and `load()` store methods
since subgraph data sources are read-only references to external data.

Also added `fetch_subgraph_schema()` method to the IPFS client to handle
the two-step fetch (manifest → schema CID → schema content).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
When a template data source and a regular data source share the same
mapping file, the build command was skipping the compilation for the
template without copying the WASM file to the template directory. This
caused deployment failures because the template WASM file was missing.

Additionally, template ABIs were not being copied to the build directory
at all, which caused issues during IPFS upload.

This commit fixes both issues:

1. Changed the compilation cache from HashSet<String> to
   HashMap<String, PathBuf> to track where compiled WASM files are
   located.

2. When a mapping file is already compiled, the existing WASM file is
   now copied to the new output location instead of skipping entirely.

3. Added code to copy template ABI files to build/templates/<name>/

4. Added code to upload template ABI files to IPFS

5. Updated update_template_ipfs_paths to also update ABI paths

6. Added abis field to Template struct and corresponding parsing logic

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
lutter and others added 6 commits January 22, 2026 15:27
Update the spec to document recent implementation work:

- Remove "Subgraph" from Non-Goals as kind:subgraph is now supported
- Document tuple/struct component name handling in ABI codegen
- Add build output structure section showing template directories
- Document subgraph data source codegen (generates subgraph-{HASH}.ts)
- Note that gnd copies WASM when multiple sources share mapping.ts
- Update test counts: 166 lib + 7 cli_commands + 12 codegen tests

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
The grafted test was failing because it used hardcoded POI values that
became stale when the base subgraph's deployment hash changed. This commit:

- Adds `patch_sources()` to dynamically patch source subgraph placeholders
  (e.g., `@base@`) with actual deployment hashes at runtime
- Modifies `deploy()` and `prepare()` to accept source mappings
- Replaces hardcoded POI values with dynamic computation using the same
  algorithm graph-node uses (matching spec version transitions)
- Updates Anvil to v1.4.0 for deterministic block hashes

The POI computation correctly handles the Legacy→Fast algorithm transition
when grafting from spec 0.0.5 to 0.0.6, starting from block 0 (genesis).

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded IPFS hash with `@source-subgraph@` placeholder that
gets patched at runtime with the actual deployment hash.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Replace hardcoded IPFS hashes with `@source-subgraph-a@` and
`@source-subgraph-b@` placeholders that get patched at runtime
with the actual deployment hashes.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Change codegen to use the datasource name instead of IPFS hash for
generated subgraph source type files. This produces stable filenames
like `subgraph-Contract.ts` instead of `subgraph-QmHash....ts`.

Also validates that subgraph datasource names are unique, erroring if
duplicates are found. This ensures the generated filenames remain
unambiguous.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update integration test mappings to use the new name-based import paths
generated by gnd codegen:
- subgraph-data-sources: use `subgraph-Contract`
- multiple-subgraph-datasources: use `subgraph-SourceA` and `subgraph-SourceB`

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
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.

3 participants