Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ jobs:
# "test (24)") are the required checks in the repository rulesets.
node: [22, 24]
steps:
# Every action is pinned by full commit SHA (see CLAUDE.md "CI").
# Every action is pinned by full commit SHA (see CONTRIBUTING.md "CI and workflows").
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Version enforcement compares with the exact PR base commit.
Expand Down
5 changes: 2 additions & 3 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,8 @@ jobs:

publish:
needs: [verify, release]
# Only from the official repository: never from a fork, nor from the old
# planadecu/glassnode-terminal before the transfer (GN-177), where the `npm` environment and
# its required reviewer don't exist.
# Only from the official repository: never from a fork, where the `npm` environment and its
# required reviewer don't exist.
if: needs.release.outputs.action != 'skip' && github.repository == 'glassnode/glassnode-terminal'
runs-on: ubuntu-latest
# Required reviewer (the maintainer) and a `main`-only deployment branch rule are configured
Expand Down
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,12 @@ node_modules/
dist/
*.tsbuildinfo
.DS_Store
.env
.claude/worktrees/

# Local env and credentials
.env
.env.*
!.env.example
*.local
*.pem
*.key
18 changes: 18 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# glassnode-terminal: agent instructions

Read [CONTRIBUTING.md](CONTRIBUTING.md) first: setup, project layout, conventions, the version
bump and the release flow all live there. Before opening a PR, run the checks in its "Run the
local checks" step.

## Don't

- Edit `src/lib/x402-catalog.ts` by hand: it is generated by `pnpm run gen:x402-metrics`
(`scripts/generate-x402-metrics.mjs`).
- Run `pnpm run gen:x402-metrics` or the app against the live API unless asked: it needs a real
`GLASSNODE_API_KEY`, and in x402 mode (`X402_PRIVATE_KEY`) every call, metadata included,
spends USDC from a real wallet. Tests and the CLI smoke test need no credentials.
- Change `scripts/release-*.{sh,mjs}` here alone: they are shared with
[glassnode-api-ts-client](https://github.com/glassnode/glassnode-api-ts-client) and tested in
`test/release-scripts.spec.ts`. Say in the PR that the other repo needs the same change.
- Move a GitHub Action to a tag such as `@v7`: every action is pinned by full commit SHA (see
CONTRIBUTING.md "CI and workflows").
92 changes: 0 additions & 92 deletions CLAUDE.md

This file was deleted.

65 changes: 54 additions & 11 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ the release** (`.github/workflows/publish.yml`). `main` only accepts changes thr
Node.js >= 22, and CI runs on both.
- **pnpm** (the version is pinned in `package.json` `packageManager`; `corepack enable` picks it
up). Supply-chain settings (build-script allowlist, 7-day release-age cooldown) live in
`pnpm-workspace.yaml`.
`pnpm-workspace.yaml`. `glassnode-api` and `ink-uplot` are published by this project's author
and are exempt from the cooldown, so their new releases can be picked up right away.
- System libraries for [node-canvas](https://github.com/Automattic/node-canvas#compiling)
(charts). On macOS: `brew install pkg-config cairo pango`.
- A Glassnode API key (`GLASSNODE_API_KEY`) to run the app against the live API.
Expand All @@ -32,14 +33,38 @@ pnpm install

### 2. Make the change

Project layout (more detail in `CLAUDE.md`):

- `src/cli.tsx` - entry point: picks API-key or x402 mode, validates credentials, renders the app
- `src/App.tsx` - the three-pane layout and keyboard handling
- `src/components/` - Ink UI components; `src/hooks/` - React hooks
- `src/lib/` - pure library code (API client setup, startup data and cache, formatting)
Project layout:

- `src/cli.tsx` - entry point: picks the mode (`--api` / `--x402` / `GLASSNODE_MODE`), validates
credentials, renders the app
- `src/App.tsx` - the three-pane layout, browse mode toggle and keyboard handling
- `src/components/` - Ink UI components (asset, metric and data panes, parameter bar, search
overlay, price ticker, log view)
- `src/hooks/` - React hooks: `useAssets`, `useMetrics`, `useMetricMetadata` (startup catalog
data, cached), `useMetricData` (live data for the selected metric and asset), `usePulses` (live
prices over the Pulses WebSocket), `useListNavigation` (scrollable lists)
- `src/lib/` - pure library code:
- `api-client.ts` - the shared `GlassnodeAPI` client, in API-key or x402 pay-per-call mode
- `startup-data.ts`, `cache.ts` - fetch all assets, metrics and metric metadata at startup and
cache them in `~/.glassnode-terminal/cache/` for 1 day (a separate cache per mode)
- `x402-catalog.ts` - the metric catalog bundled for x402 mode; generated by
`pnpm run gen:x402-metrics`, never edited by hand
- `logger.ts` - in-memory log of API calls (API key redacted) shown in the log view
- `time-parse.ts`, `format.ts`, `types.ts` - time parsing, formatting, shared types
- `scripts/` - the x402 catalog generator and the release tooling
- `test/` - Vitest tests
- `test/` - Vitest tests (`*.spec.ts(x)`)

Conventions:

- TypeScript everywhere; Ink components are `.tsx`.
- `src/lib/` has no React imports, except the `useLogs` hook in `logger.ts`.
- Use the `glassnode-api` types (`AssetMetadata`, `MetricMetadata`, ...) instead of redefining
them. Metric display names come from `MetricMetadata.descriptors.name`, with a path-based
fallback.
- After startup, the only live calls are `useMetricData` and the `usePulses` WebSocket;
everything else comes from the cached startup data.
- The parameter bar maps to these API query parameters: asset `a` (BTC, ETH, ...), interval `i`
(10m, 1h, 24h, 1w, 1month), since `s` (unix timestamp), currency `c` (usd, native).

Add or update tests for what you change. Run the app (`GLASSNODE_API_KEY=… pnpm start`) to check
UI changes by eye; charts draw differently in kitty, iTerm2/VS Code and plain terminals.
Expand Down Expand Up @@ -117,11 +142,29 @@ version is already npm's `latest`, the older one is published under the
`backport-<major>.<minor>` dist-tag instead, so `latest` never moves backwards, and its GitHub
Release is not marked "Latest". A prerelease version is published under `next`.

## CI and workflows (for maintainers)

- `.github/workflows/ci.yml` runs on PRs into `main` and `release/**`; `publish.yml` calls it
(`workflow_call`) as its `verify` job, so a release runs exactly the PR checks. The job runs on
Node 22 and 24, and `test (22)` and `test (24)` are the required checks in the repository
rulesets: renaming the job or the matrix means updating the rulesets.
- Every action is pinned by full commit SHA with a `# vX.Y.Z` comment, never a movable tag.
Dependabot proposes updates. To bump one by hand, resolve the tag with
`gh api repos/<owner>/<repo>/git/ref/tags/<tag>` (dereference an annotated tag with
`gh api repos/<owner>/<repo>/git/tags/<sha>`), update the SHA and the comment together, and
read the release notes.
- `publish.yml` publishes with npm Trusted Publishing (OIDC) and provenance; there is no
`NPM_TOKEN`. The Trusted Publisher for `glassnode-terminal` on npmjs.com must name the
repository `glassnode/glassnode-terminal`, the workflow `publish.yml` and the environment `npm`.
- `scripts/release-*.{sh,mjs}` are shared with
[glassnode-api-ts-client](https://github.com/glassnode/glassnode-api-ts-client) and tested in
`test/release-scripts.spec.ts`; keep the two repositories in sync.
`scripts/check-changelog-heading.mjs` additionally enforces the PR version bump here.

## Security

- Report vulnerabilities privately, through GitHub's private vulnerability reporting on this
repository (the **Security** tab → **Report a vulnerability**). Never open a public issue for
them.
- Report vulnerabilities privately, as described in [SECURITY.md](SECURITY.md). Never open a
public issue for them.
- Never commit API keys, wallet private keys (`X402_PRIVATE_KEY`) or other secrets, including in
`.env` files, tests or logs. `.env` is git-ignored.

Expand Down
21 changes: 21 additions & 0 deletions SECURITY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Security policy

## Contents

- [Reporting a vulnerability](#reporting-a-vulnerability)
- [Supported versions](#supported-versions)

## Reporting a vulnerability

Don't open a public issue. Report it privately:

- **GitHub:** this repository's Security tab → "Report a vulnerability" (private vulnerability
reporting).
- **Email:** security@glassnode.com, if you can't use GitHub.

Include the affected version, steps to reproduce and the impact. Glassnode has no bug bounty
program.

## Supported versions

Only the latest release published to npm receives security fixes.
Loading