chore: rename CLI and project to stoke

This commit is contained in:
kimi-reviewer-andresmgsl 2026-07-22 15:16:42 +00:00
parent 25670253ea
commit 9e7c204201
5 changed files with 90 additions and 58 deletions

View file

@ -1,4 +1,6 @@
# forgejo-cli
# stoke
> CLI for the heavy-duty forge (Forgejo). Named after the act of feeding and tending a fire — the operator's hand on the forge.
A command-line interface for [Forgejo](https://forgejo.org/), built with [Commander.js](https://github.com/tj/commander.js/). It targets the instance at `https://forgejo.heavyduty.builders` and is designed so that every real operation performed against Forgejo becomes a new CLI command.
@ -10,9 +12,9 @@ A command-line interface for [Forgejo](https://forgejo.org/), built with [Comman
## Installation
```bash
cd forgejo-cli
cd stoke
npm install
npm link # makes the `forgejo` binary available globally
npm link # makes the `stoke` binary available globally
```
Or run it directly without linking:
@ -25,8 +27,8 @@ node src/cli.js <command>
Authentication state is stored in a JSON file:
- Default: `~/.config/forgejo-cli/config.json`
- Override with `--config <path>` or `FORGEJO_CONFIG_FILE`
- Default: `~/.config/stoke/config.json`
- Override with `--config <path>` or `STOKE_CONFIG_FILE` (or `FORGEJO_CONFIG_FILE` as a fallback)
The configuration directory is created with permissions `0700` and the file with `0600` so only the owner can read the token.
@ -47,14 +49,16 @@ Example stored config:
| Variable | Purpose |
| --- | --- |
| `FORGEJO_URL` | Default Forgejo base URL |
| `FORGEJO_USERNAME` | Default username/email for `auth login` |
| `FORGEJO_PASSWORD` | Default password for `auth login` |
| `FORGEJO_CONFIG_FILE` | Path to the config file |
| `FORGEJO_CONFIG_DIR` | Directory for the config file |
| `STOKE_URL` | Default Forgejo base URL |
| `STOKE_USERNAME` | Default username/email for `auth login` |
| `STOKE_PASSWORD` | Default password for `auth login` |
| `STOKE_CONFIG_FILE` | Path to the config file |
| `STOKE_CONFIG_DIR` | Directory for the config file |
| `XDG_CONFIG_HOME` | Followed when resolving the default config directory |
| `GITHUB_TOKEN` | GitHub token used by `repo import` when `--github-token` is omitted |
`FORGEJO_*` variants are still accepted as fallbacks for backward compatibility.
## Commands
### Global options
@ -65,7 +69,7 @@ Example stored config:
-V, --version display version
```
### `forgejo auth login`
### `stoke auth login`
Authenticate and persist an access token.
@ -83,29 +87,29 @@ Options:
Interactive example:
```bash
forgejo auth login
stoke auth login
# prompts for username and password
```
Non-interactive example using environment variables:
```bash
export FORGEJO_USERNAME='kimi-reviewer-andresmgsl'
export FORGEJO_PASSWORD='...'
forgejo auth login
export STOKE_USERNAME='kimi-reviewer-andresmgsl'
export STOKE_PASSWORD='...'
stoke auth login
```
Password file example (avoids shell history and special-character issues):
```bash
chmod 600 /run/secrets/forgejo-password
forgejo auth login -n kimi-reviewer-andresmgsl --password-file /run/secrets/forgejo-password
chmod 600 /run/secrets/stoke-password
stoke auth login -n kimi-reviewer-andresmgsl --password-file /run/secrets/stoke-password
```
Existing token example:
```bash
forgejo auth login -t <personal-access-token>
stoke auth login -t <personal-access-token>
```
Flow:
@ -115,30 +119,30 @@ Flow:
3. Requests the standard non-admin scopes: `read/write` for `activitypub`, `issue`, `misc`, `organization`, `package`, `repository`, and `user`.
4. Writes the token, token id, user details and URL to the config file.
### `forgejo auth logout`
### `stoke auth logout`
Revoke the stored token remotely and delete the local config.
```bash
forgejo auth logout
stoke auth logout
```
Flow:
1. Calls `DELETE /api/v1/users/{login}/tokens/{id}` using the stored token.
2. Removes `~/.config/forgejo-cli/config.json`.
2. Removes `~/.config/stoke/config.json`.
### `forgejo auth status`
### `stoke auth status`
Display the currently authenticated user.
```bash
forgejo auth status
stoke auth status
```
Calls `GET /api/v1/user` with the stored token.
### `forgejo repo create`
### `stoke repo create`
Create a new repository for the authenticated user.
@ -155,13 +159,13 @@ Options:
Example:
```bash
forgejo repo create --name forgejo-cli-test --private \
-d "Test repository created via forgejo-cli"
stoke repo create --name stoke-test --private \
-d "Test repository created via stoke"
```
Calls `POST /api/v1/user/repos`.
### `forgejo repo list`
### `stoke repo list`
List repositories for the authenticated user.
@ -171,12 +175,12 @@ Options:
```
```bash
forgejo repo list
stoke repo list
```
Calls `GET /api/v1/user/repos` and auto-paginates.
### `forgejo repo import`
### `stoke repo import`
Import a remote repository into Forgejo, including git history, issues, pull requests, labels, milestones, releases and wiki.
@ -207,7 +211,7 @@ Options:
Example used to mirror `heavy-duty/box`:
```bash
forgejo repo import \
stoke repo import \
--from https://github.com/heavy-duty/box.git \
--name box \
--service github \
@ -217,7 +221,7 @@ forgejo repo import \
Calls `POST /api/v1/repos/migrate`.
### `forgejo repo import-batch`
### `stoke repo import-batch`
Import multiple repositories from a JSON manifest.
@ -249,13 +253,13 @@ Manifest format:
Example:
```bash
forgejo repo import-batch -f repos.json
forgejo repo import-batch -f repos.json --dry-run
stoke repo import-batch -f repos.json
stoke repo import-batch -f repos.json --dry-run
```
Calls `POST /api/v1/repos/migrate` once per entry.
### `forgejo issue list`
### `stoke issue list`
List issues in a repository.
@ -269,12 +273,12 @@ Options:
```
```bash
forgejo issue list -o kimi-reviewer-andresmgsl -r box -s all -l 0
stoke issue list -o kimi-reviewer-andresmgsl -r box -s all -l 0
```
Calls `GET /api/v1/repos/{owner}/{repo}/issues` and auto-paginates.
### `forgejo pr list`
### `stoke pr list`
List pull requests in a repository.
@ -287,12 +291,12 @@ Options:
```
```bash
forgejo pr list -o kimi-reviewer-andresmgsl -r box -s all -l 0
stoke pr list -o kimi-reviewer-andresmgsl -r box -s all -l 0
```
Calls `GET /api/v1/repos/{owner}/{repo}/pulls` and auto-paginates.
### `forgejo branch list`
### `stoke branch list`
List branches in a repository.
@ -304,12 +308,12 @@ Options:
```
```bash
forgejo branch list -o kimi-reviewer-andresmgsl -r box
stoke branch list -o kimi-reviewer-andresmgsl -r box
```
Calls `GET /api/v1/repos/{owner}/{repo}/branches` and auto-paginates.
### `forgejo collaborator add`
### `stoke collaborator add`
Add a collaborator to a repository.
@ -324,8 +328,8 @@ Options:
Example:
```bash
forgejo collaborator add -o kimi-reviewer-andresmgsl -r infra -u andres --permission admin
forgejo collaborator add -o kimi-reviewer-andresmgsl -r infra -u dan --permission admin
stoke collaborator add -o kimi-reviewer-andresmgsl -r infra -u andres --permission admin
stoke collaborator add -o kimi-reviewer-andresmgsl -r infra -u dan --permission admin
```
Calls `PUT /api/v1/repos/{owner}/{repo}/collaborators/{user}`.
@ -347,7 +351,7 @@ src/
- Tokens are stored on disk with `0600` permissions.
- Passwords are never persisted; they are only used to generate a token.
- Prefer `--password-file` or `FORGEJO_PASSWORD` over `-p` to keep passwords out of shell history and avoid `!` history-expansion issues.
- Prefer `--password-file` or `STOKE_PASSWORD` over `-p` to keep passwords out of shell history and avoid `!` history-expansion issues.
- The generated token name includes the hostname and a timestamp to avoid collisions.
## Verification: heavy-duty repository imports
@ -367,4 +371,4 @@ Counts match GitHub for all repositories. Git history, issues, pull requests, la
## Next steps
The CLI is authenticated and the first full repository import is complete. Every subsequent Forgejo task you need will be added as a new command under `forgejo`.
The CLI is authenticated and the first full repository import is complete. Every subsequent Forgejo task you need will be added as a new command under `stoke`.

View file

@ -1,8 +1,8 @@
{
"name": "forgejo-cli",
"name": "stoke",
"version": "1.0.0",
"description": "",
"main": "index.js",
"description": "CLI for the heavy-duty forge (Forgejo)",
"main": "src/cli.js",
"scripts": {
"test": "node --test test/**/*.test.js",
"start": "node src/cli.js"
@ -15,6 +15,6 @@
"commander": "^15.0.0"
},
"bin": {
"forgejo": "src/cli.js"
"stoke": "src/cli.js"
}
}

View file

@ -149,6 +149,12 @@ class ForgejoClient {
permission,
});
}
async renameRepo(owner, repo, newName) {
return this.request('PATCH', `/repos/${encodeURIComponent(owner)}/${encodeURIComponent(repo)}`, {
name: newName,
});
}
}
module.exports = { ForgejoClient };

View file

@ -12,8 +12,8 @@ const pkg = require('../package.json');
const program = new Command();
program
.name('forgejo')
.description('CLI for Forgejo (https://forgejo.heavyduty.builders)')
.name('stoke')
.description('CLI for the heavy-duty forge (https://forgejo.heavyduty.builders)')
.version(pkg.version)
.configureOutput({ outputError: (str, write) => write(`Error: ${str}`) });
@ -21,7 +21,7 @@ program
.option('-c, --config <path>', 'path to configuration file')
.hook('preAction', (thisCommand) => {
if (thisCommand.opts().config) {
process.env.FORGEJO_CONFIG_FILE = thisCommand.opts().config;
process.env.STOKE_CONFIG_FILE = thisCommand.opts().config;
}
});
@ -53,7 +53,7 @@ function readSecretFile(filePath, label) {
function makeTokenName() {
const host = require('node:os').hostname() || 'unknown';
return `forgejo-cli-${host}-${Date.now()}`;
return `stoke-${host}-${Date.now()}`;
}
const DEFAULT_TOKEN_SCOPES = [
@ -84,9 +84,9 @@ const auth = program
auth
.command('login')
.description('Authenticate against a Forgejo instance and store an access token')
.option('-u, --url <url>', 'Forgejo base URL', process.env.FORGEJO_URL || 'https://forgejo.heavyduty.builders')
.option('-n, --username <username>', 'account username or email', process.env.FORGEJO_USERNAME)
.option('-p, --password <password>', 'account password', process.env.FORGEJO_PASSWORD)
.option('-u, --url <url>', 'Forgejo base URL', process.env.STOKE_URL || process.env.FORGEJO_URL || 'https://forgejo.heavyduty.builders')
.option('-n, --username <username>', 'account username or email', process.env.STOKE_USERNAME || process.env.FORGEJO_USERNAME)
.option('-p, --password <password>', 'account password', process.env.STOKE_PASSWORD || process.env.FORGEJO_PASSWORD)
.option('--password-file <path>', 'read account password from a file')
.option('-t, --token <token>', 'use an existing personal access token instead of generating one')
.option('--token-file <path>', 'read an existing personal access token from a file')
@ -350,6 +350,26 @@ repo
}
});
repo
.command('rename')
.description('Rename a repository')
.requiredOption('-o, --owner <owner>', 'repository owner')
.requiredOption('-r, --repo <repo>', 'current repository name')
.requiredOption('--name <new-name>', 'new repository name')
.action(async (options) => {
try {
const config = loadConfig();
const client = ForgejoClient.fromConfig(config);
const result = await client.renameRepo(options.owner, options.repo, options.name);
console.log(`Repository renamed to ${result.full_name}`);
console.log(`URL: ${result.html_url}`);
} catch (err) {
console.error(`Repository rename failed: ${err.message}`);
if (err.status) console.error(`HTTP status: ${err.status}`);
process.exit(1);
}
});
repo
.command('import-batch')
.description('Import multiple repositories from a JSON manifest')

View file

@ -2,9 +2,11 @@ const path = require('node:path');
const os = require('node:os');
const fs = require('node:fs');
const CONFIG_DIR = process.env.FORGEJO_CONFIG_DIR
|| path.join(process.env.XDG_CONFIG_HOME || os.homedir(), '.config', 'forgejo-cli');
const CONFIG_PATH = process.env.FORGEJO_CONFIG_FILE
const CONFIG_DIR = process.env.STOKE_CONFIG_DIR
|| process.env.FORGEJO_CONFIG_DIR
|| path.join(process.env.XDG_CONFIG_HOME || os.homedir(), '.config', 'stoke');
const CONFIG_PATH = process.env.STOKE_CONFIG_FILE
|| process.env.FORGEJO_CONFIG_FILE
|| path.join(CONFIG_DIR, 'config.json');
const CONFIG_MODE = 0o600;
const DIR_MODE = 0o700;