2026-07-22 15:16:42 +00:00
# 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.
2026-07-22 15:03:32 +00:00
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.
## Requirements
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
- Node.js >= 22.12 (required by `commander@15` ; the CLI also uses the global `fetch` API)
2026-07-22 15:03:32 +00:00
- npm
## Installation
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
### With apt (Debian/Ubuntu — recommended)
2026-08-31 15:14:12 +00:00
The package is published to the public Debian registry of the forge itself.
One-time setup:
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
```bash
curl -fsSL https://forgejo.heavyduty.builders/heavy-duty/stoke/raw/branch/main/scripts/install-apt.sh | bash
```
2026-08-31 15:14:12 +00:00
If a private registry or a `FORGE_URL=` override requires authentication,
download the installer and supply a Forgejo login and package-readable token:
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
```bash
2026-08-30 11:35:08 +00:00
export FORGE_USER=your-forgejo-login
read -rsp 'Forgejo token: ' FORGE_TOKEN & & echo & & export FORGE_TOKEN
curl -fsSLo /tmp/stoke-install-apt.sh \
https://forgejo.heavyduty.builders/heavy-duty/stoke/raw/branch/main/scripts/install-apt.sh
sudo --preserve-env=FORGE_USER,FORGE_TOKEN bash /tmp/stoke-install-apt.sh
unset FORGE_TOKEN
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
```
2026-08-31 15:14:12 +00:00
The authenticated path keeps credentials out of the source URL in a
root-readable apt auth file. To configure that file manually before adding the
source:
2026-08-30 11:35:08 +00:00
```bash
sudo install -d -m 0755 /etc/apt/auth.conf.d
2026-08-31 15:14:12 +00:00
sudo install -m 0600 /dev/null /etc/apt/auth.conf.d/forgejo-heavy-duty.conf
2026-08-30 11:35:08 +00:00
printf 'machine forgejo.heavyduty.builders\nlogin %s\npassword %s\n' \
"$FORGE_USER" "$FORGE_TOKEN" \
| sudo tee /etc/apt/auth.conf.d/forgejo-heavy-duty.conf >/dev/null
```
Then add the forge's registry as an apt source:
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
```bash
sudo install -d /etc/apt/keyrings
curl -fsSL https://forgejo.heavyduty.builders/api/packages/heavy-duty/debian/repository.key \
| sudo tee /etc/apt/keyrings/forgejo-heavy-duty.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/forgejo-heavy-duty.asc] https://forgejo.heavyduty.builders/api/packages/heavy-duty/debian stable main" \
| sudo tee /etc/apt/sources.list.d/forgejo-heavy-duty.list
```
2026-07-22 21:56:26 +00:00
The package depends on `nodejs (>= 22.12)` , which the distro archives of Debian 13 (Node 20) and Ubuntu 24.04 (Node 18) cannot satisfy — on those distros, also add a Node 22 source such as [NodeSource ](https://deb.nodesource.com ):
2026-07-22 21:39:51 +00:00
```bash
curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \
| sudo tee /etc/apt/keyrings/nodesource.asc >/dev/null
echo "deb [signed-by=/etc/apt/keyrings/nodesource.asc] https://deb.nodesource.com/node_22.x nodistro main" \
| sudo tee /etc/apt/sources.list.d/nodesource.list
```
2026-07-22 21:56:26 +00:00
Then install:
```bash
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
sudo apt-get update & & sudo apt-get install stoke
```
2026-07-22 21:56:26 +00:00
Upgrades then arrive through regular `apt-get upgrade` . `install-apt.sh` performs all of the above, adding the NodeSource repository only when no already-configured apt source offers a new-enough nodejs.
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
2026-08-31 10:48:42 +00:00
Note: apt releases that verify OpenPGP with `sqv` (Debian 13+, apt >= 2.9)
may reject signatures produced by affected Forgejo versions. By default,
`install-apt.sh` refuses that signature failure and removes the Forge source;
authentication, network, and all other update failures are also fatal and never
disable verification.
If the installer reports the known `sqv` parsing failure and you deliberately
accept HTTPS-only integrity without OpenPGP verification, opt in on a second
run:
```bash
export STOKE_ALLOW_UNVERIFIED_APT=1
2026-08-31 15:14:12 +00:00
curl -fsSL https://forgejo.heavyduty.builders/heavy-duty/stoke/raw/branch/main/scripts/install-apt.sh | bash
2026-08-31 10:48:42 +00:00
unset STOKE_ALLOW_UNVERIFIED_APT
```
2026-08-31 15:14:12 +00:00
For a private registry, re-run the downloaded installer with
`sudo --preserve-env=FORGE_USER,FORGE_TOKEN,STOKE_ALLOW_UNVERIFIED_APT` instead.
2026-08-31 10:48:42 +00:00
This exact opt-in is the only path in the installer that writes a
`[trusted=yes]` source. The installer prints the security trade-off again when
it takes that path.
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
As a fallback, each release also has the `.deb` attached for direct install: `sudo dpkg -i stoke_<version>_all.deb` .
### From source
2026-07-22 15:03:32 +00:00
```bash
2026-07-22 15:16:42 +00:00
cd stoke
2026-07-22 15:03:32 +00:00
npm install
2026-07-22 15:16:42 +00:00
npm link # makes the `stoke` binary available globally
2026-07-22 15:03:32 +00:00
```
Or run it directly without linking:
```bash
node src/cli.js < command >
```
## Configuration
Authentication state is stored in a JSON file:
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
- Default: `~/.config/stoke/config.json` (or `$XDG_CONFIG_HOME/stoke/config.json` when `XDG_CONFIG_HOME` is set)
2026-07-22 15:16:42 +00:00
- Override with `--config <path>` or `STOKE_CONFIG_FILE` (or `FORGEJO_CONFIG_FILE` as a fallback)
2026-07-22 15:03:32 +00:00
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
Note: the global `--config` flag must be passed before the subcommand, e.g. `stoke --config /path/to/config.json auth status` .
2026-07-22 15:03:32 +00:00
The configuration directory is created with permissions `0700` and the file with `0600` so only the owner can read the token.
Example stored config:
```json
{
"url": "https://forgejo.heavyduty.builders",
"login": "kimi-reviewer-andresmgsl",
"username": "kimi-reviewer-andresmgsl",
"email": "andres+4@heavyduty.builders",
"token": "< sha1 > ",
"tokenId": 42
}
```
## Environment variables
| Variable | Purpose |
| --- | --- |
2026-07-22 15:16:42 +00:00
| `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 |
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
| `XDG_CONFIG_HOME` | Followed when resolving the default config directory (`$XDG_CONFIG_HOME/stoke`) |
| `GITHUB_TOKEN` | GitHub token used by `repo import` and `repo import-batch` when `--github-token` is omitted |
2026-07-22 15:03:32 +00:00
2026-07-22 15:16:42 +00:00
`FORGEJO_*` variants are still accepted as fallbacks for backward compatibility.
2026-07-22 15:03:32 +00:00
## Commands
2026-07-26 21:46:28 +00:00
Read commands (`auth status`, `repo list` , `issue list` , `issue show` , `pr list` , `pr show` , `release list` , `release view` , `label list` , `branch list` , `org repos` , `org team list` , `org team member-list` , `user list` , `user show` ) accept a `--json` flag that prints the raw API response, pretty-printed, instead of the human-readable format — useful for scripting.
2026-07-22 15:03:32 +00:00
### Global options
```text
-c, --config < path > path to configuration file
-h, --help display help
-V, --version display version
```
2026-07-22 15:16:42 +00:00
### `stoke auth login`
2026-07-22 15:03:32 +00:00
Authenticate and persist an access token.
```text
Options:
-u, --url < url > Forgejo base URL (default: https://forgejo.heavyduty.builders)
-n, --username < username > account username or email
-p, --password < password > account password
--password-file < path > read account password from a file
-t, --token < token > use an existing personal access token instead of generating one
--token-file < path > read an existing personal access token from a file
--token-name < name > name for the generated token
2026-07-26 21:43:06 +00:00
--full-scopes grant full read/write access on all non-admin scopes
--scopes < csv > comma-separated list of scopes for the generated token
2026-07-22 15:03:32 +00:00
```
Interactive example:
```bash
2026-07-22 15:16:42 +00:00
stoke auth login
2026-07-22 15:03:32 +00:00
# prompts for username and password
```
Non-interactive example using environment variables:
```bash
2026-07-22 15:16:42 +00:00
export STOKE_USERNAME='kimi-reviewer-andresmgsl'
export STOKE_PASSWORD='...'
stoke auth login
2026-07-22 15:03:32 +00:00
```
Password file example (avoids shell history and special-character issues):
```bash
2026-07-22 15:16:42 +00:00
chmod 600 /run/secrets/stoke-password
stoke auth login -n kimi-reviewer-andresmgsl --password-file /run/secrets/stoke-password
2026-07-22 15:03:32 +00:00
```
Existing token example:
```bash
2026-07-22 15:16:42 +00:00
stoke auth login -t < personal-access-token >
2026-07-22 15:03:32 +00:00
```
Flow:
1. Calls `GET /api/v1/user` to verify credentials and resolve the canonical `login` name.
2. Calls `POST /api/v1/users/{login}/tokens` to generate a personal access token.
2026-07-26 21:43:06 +00:00
3. Requests the default least-privilege scopes (see "Token scopes" below).
2026-07-22 15:03:32 +00:00
4. Writes the token, token id, user details and URL to the config file.
2026-07-26 21:43:06 +00:00
Token scopes:
By default the generated token is least-privilege, covering the common
issue/PR/repository commands:
- `read:issue` , `write:issue` — issues, PR comments/reviews, labels
- `read:repository` , `write:repository` — repositories, branches, releases, collaborators, pull requests
- `read:user` — `auth status` , `user list` , `user show`
- `read:organization` — `org repos` , `org team list` , `org team member-list`
Organization administration (`org create`, `org avatar` , `org team create` ,
`org team member-add` , `org team member-remove` ) and package publishing need
broader access. Pass `--full-scopes` for the previous all-scopes behavior
(`read`/`write` on `activitypub` , `issue` , `misc` , `organization` , `package` ,
`repository` , `user` ), or `--scopes <csv>` for a custom list:
```bash
stoke auth login --scopes read:issue,write:issue,read:repository
```
The scopes the token was created with are printed after a successful login.
2026-07-22 15:16:42 +00:00
### `stoke auth logout`
2026-07-22 15:03:32 +00:00
Revoke the stored token remotely and delete the local config.
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
```text
Options:
-p, --password < password > account password, needed to revoke the token remotely
--password-file < path > read account password from a file
--local-only skip remote revocation and only delete the local config
```
2026-07-22 15:03:32 +00:00
```bash
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
stoke auth logout # prompts for the password on a TTY
stoke auth logout --password-file /run/secrets/pw # non-interactive
stoke auth logout --local-only # keep the token active, just forget it locally
2026-07-22 15:03:32 +00:00
```
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
Forgejo only accepts Basic auth on its token endpoints — a token cannot revoke itself — so remote revocation needs the account password. Without one (or with `--local-only` ), the token stays active on the server and can be revoked from the web UI under Settings > Applications.
2026-07-22 15:03:32 +00:00
Flow:
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
1. Calls `DELETE /api/v1/users/{login}/tokens/{id}` using Basic auth.
2026-07-22 15:16:42 +00:00
2. Removes `~/.config/stoke/config.json` .
2026-07-22 15:03:32 +00:00
2026-07-22 15:16:42 +00:00
### `stoke auth status`
2026-07-22 15:03:32 +00:00
Display the currently authenticated user.
```bash
2026-07-22 15:16:42 +00:00
stoke auth status
2026-07-22 15:03:32 +00:00
```
Calls `GET /api/v1/user` with the stored token.
2026-07-23 22:44:21 +00:00
### `stoke repo clone`
Clone a repository from the configured Forgejo instance using the stored credentials.
```text
Arguments:
[directory] destination directory (default: repository name)
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
--branch < branch > checkout this branch instead of the default branch
--depth < depth > create a shallow clone with the given history depth
--origin < name > name for the created remote (default: origin)
```
```bash
stoke repo clone -o heavy-duty -r stoke
stoke repo clone -o heavy-duty -r stoke ~/src/stoke --depth 1
```
The stored token is handed to git ephemerally through environment-based config (`GIT_CONFIG_*`): it never appears in the remote URL, on the command line, or in the cloned repository's `.git/config` . Git's output is streamed directly and its exit status is forwarded, so failures behave exactly like a plain `git clone` .
2026-07-22 15:16:42 +00:00
### `stoke repo create`
2026-07-22 15:03:32 +00:00
2026-08-21 06:37:04 +00:00
Create a new repository for the authenticated user or an organization.
2026-07-22 15:03:32 +00:00
```text
Options:
--name < name > repository name (required)
2026-08-21 06:37:04 +00:00
-o, --owner < owner > repository owner (authenticated user or organization)
2026-07-22 15:03:32 +00:00
-d, --description < description > repository description
--private make the repository private
--public make the repository public
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
--auto-init initialize with a README (default)
--no-auto-init create an empty repository without a README
2026-07-22 15:03:32 +00:00
--default-branch < branch > default branch name (default: "main")
```
Example:
```bash
2026-07-22 15:16:42 +00:00
stoke repo create --name stoke-test --private \
-d "Test repository created via stoke"
2026-08-21 06:37:04 +00:00
stoke repo create -o heavy-duty --name shared-project --private
2026-07-22 15:03:32 +00:00
```
2026-08-21 06:37:04 +00:00
When `--owner` is omitted or names the authenticated user (case-insensitively),
calls `POST /api/v1/user/repos` . For another owner, calls
`POST /api/v1/orgs/{owner}/repos` ; Forgejo returns `403` when the caller cannot
create repositories for that organization.
2026-07-22 15:03:32 +00:00
2026-07-22 15:16:42 +00:00
### `stoke repo list`
2026-07-22 15:03:32 +00:00
List repositories for the authenticated user.
```text
Options:
-l, --limit < number > maximum repositories to display (default: 50; use 0 for all)
```
```bash
2026-07-22 15:16:42 +00:00
stoke repo list
2026-07-22 15:03:32 +00:00
```
Calls `GET /api/v1/user/repos` and auto-paginates.
2026-07-22 15:16:42 +00:00
### `stoke repo import`
2026-07-22 15:03:32 +00:00
Import a remote repository into Forgejo, including git history, issues, pull requests, labels, milestones, releases and wiki.
```text
Options:
--from < clone-addr > source clone URL (required)
--name < name > repository name in Forgejo (required)
--service < service > source service type: git, github, gitea, gitlab, ... (default: github)
--owner < owner > Forgejo owner for the imported repo (default: current user)
-d, --description < description > repository description
--private / --public visibility
--issues migrate issues (default)
--no-issues skip issues
--labels migrate labels (default)
--no-labels skip labels
--milestones migrate milestones (default)
--no-milestones skip milestones
--pull-requests migrate pull requests (default)
--no-pull-requests skip pull requests
--releases migrate releases (default)
--no-releases skip releases
--wiki migrate wiki (default)
--no-wiki skip wiki
--lfs migrate LFS objects
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
--github-token < token > source service token (for GitHub defaults to GITHUB_TOKEN or `gh auth token` )
2026-07-22 15:03:32 +00:00
```
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
A source token is only required when `--service github` (the default): it raises rate limits and enables private repositories. For other services (`git`, `gitlab` , `gitea` , ...) no token is sent unless one is explicitly provided.
2026-07-22 15:03:32 +00:00
Example used to mirror `heavy-duty/box` :
```bash
2026-07-22 15:16:42 +00:00
stoke repo import \
2026-07-22 15:03:32 +00:00
--from https://github.com/heavy-duty/box.git \
--name box \
--service github \
--public \
--issues --labels --milestones --pull-requests --releases --wiki
```
Calls `POST /api/v1/repos/migrate` .
2026-07-22 15:16:42 +00:00
### `stoke repo import-batch`
2026-07-22 15:03:32 +00:00
Import multiple repositories from a JSON manifest.
```text
Options:
-f, --file < path > path to JSON manifest (required)
--dry-run print the manifest without importing
```
Manifest format:
```json
[
{
"name": "rig",
"from": "https://github.com/heavy-duty/rig.git",
"service": "github",
"private": false,
"issues": true,
"labels": true,
"milestones": true,
"pull_requests": true,
"releases": true,
"wiki": true
}
]
```
Example:
```bash
2026-07-22 15:16:42 +00:00
stoke repo import-batch -f repos.json
stoke repo import-batch -f repos.json --dry-run
2026-07-22 15:03:32 +00:00
```
Calls `POST /api/v1/repos/migrate` once per entry.
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
### `stoke repo rename`
Rename a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > current repository name (required)
--name < new-name > new repository name (required)
```
```bash
stoke repo rename -o heavy-duty -r old-name --name new-name
```
Calls `PATCH /api/v1/repos/{owner}/{repo}` .
2026-07-22 17:47:48 +00:00
### `stoke repo transfer`
Transfer a repository to a new owner (a user or an organization). The authenticated user must have admin rights on the repository and permission to create repositories under the new owner (e.g. be an organization owner), in which case the transfer completes immediately.
```text
Options:
-o, --owner < owner > current repository owner (required)
-r, --repo < repo > repository name (required)
--to < new-owner > new owner: username or organization name (required)
```
Example used to move the heavy-duty repositories into the `heavy-duty` organization:
```bash
stoke repo transfer -o kimi-reviewer-andresmgsl -r box --to heavy-duty
```
Calls `POST /api/v1/repos/{owner}/{repo}/transfer` .
2026-07-22 15:16:42 +00:00
### `stoke issue list`
2026-07-22 15:03:32 +00:00
List issues in a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-s, --state < state > open, closed, all (default: open)
-t, --type < type > issues or pulls (default: issues)
-l, --limit < number > maximum issues to display (default: 50; use 0 for all)
```
```bash
2026-07-22 15:16:42 +00:00
stoke issue list -o kimi-reviewer-andresmgsl -r box -s all -l 0
2026-07-22 15:03:32 +00:00
```
Calls `GET /api/v1/repos/{owner}/{repo}/issues` and auto-paginates.
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
### `stoke issue create`
Create an issue in a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-t, --title < title > issue title (required)
-b, --body < body > issue body (markdown)
--body-file < path > read the issue body from a file
--assignee < username... > assign the issue to one or more users
2026-08-18 00:46:47 +00:00
--label < name... > apply one or more labels by name
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
```
```bash
2026-08-18 00:46:47 +00:00
stoke issue create -o heavy-duty -r stoke -t "Ship v2" --body-file body.md \
--label ready --label enhancement
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
```
2026-08-18 00:46:47 +00:00
Requested label names are resolved through the paginated repository label list,
then their numeric IDs are included in `POST /api/v1/repos/{owner}/{repo}/issues` .
An unknown label fails before the issue is created.
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
2026-07-26 21:46:28 +00:00
### `stoke issue show`
Show details of an issue.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-n, --number < number > issue number (required)
--json print raw JSON instead of human-readable output
```
```bash
stoke issue show -o heavy-duty -r stoke -n 10
```
Calls `GET /api/v1/repos/{owner}/{repo}/issues/{number}` .
### `stoke issue comment`
Add a comment to an issue. Body is required (whitespace-only is rejected). When both `-b` and `--body-file` are set, ** `--body-file` wins**.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-n, --number < number > issue number (required)
-b, --body < body > comment body (markdown; required unless --body-file)
--body-file < path > read the comment body from a file (wins over -b)
```
```bash
stoke issue comment -o heavy-duty -r stoke -n 10 -b "Confirmed."
```
Calls `POST /api/v1/repos/{owner}/{repo}/issues/{number}/comments` .
2026-07-22 15:16:42 +00:00
### `stoke pr list`
2026-07-22 15:03:32 +00:00
List pull requests in a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-s, --state < state > open, closed, all (default: open)
-l, --limit < number > maximum PRs to display (default: 50; use 0 for all)
```
```bash
2026-07-22 15:16:42 +00:00
stoke pr list -o kimi-reviewer-andresmgsl -r box -s all -l 0
2026-07-22 15:03:32 +00:00
```
Calls `GET /api/v1/repos/{owner}/{repo}/pulls` and auto-paginates.
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
### `stoke pr create`
Create a pull request in a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-t, --title < title > pull request title (required)
--head < branch > source branch (required; for cross-repo PRs use user:branch)
--base < branch > target branch (default: main)
-b, --body < body > pull request body (markdown)
--body-file < path > read the pull request body from a file
```
```bash
stoke pr create -o heavy-duty -r stoke -t "Fix config handling" \
--head fix/config --base main --body-file pr-body.md
```
Calls `POST /api/v1/repos/{owner}/{repo}/pulls` .
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
### `stoke pr merge`
Merge a pull request.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-n, --number < number > pull request number (required)
--method < method > merge, rebase, rebase-merge, squash (default: merge)
--title < title > custom merge commit title
--message < message > custom merge commit message
--delete-branch delete the source branch after merging
```
```bash
stoke pr merge -o heavy-duty -r stoke -n 2 --delete-branch
```
Calls `POST /api/v1/repos/{owner}/{repo}/pulls/{number}/merge` .
2026-07-22 21:21:21 +00:00
### `stoke pr show`
Show details of a pull request.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-n, --number < number > pull request number (required)
```
```bash
stoke pr show -o heavy-duty -r stoke -n 3
```
Calls `GET /api/v1/repos/{owner}/{repo}/pulls/{number}` .
### `stoke pr comment`
2026-07-22 23:18:43 +00:00
Add a comment to a pull request. Body is required (whitespace-only is rejected). When both `-b` and `--body-file` are set, ** `--body-file` wins**.
2026-07-22 21:21:21 +00:00
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-n, --number < number > pull request number (required)
2026-07-22 23:18:43 +00:00
-b, --body < body > comment body (markdown; required unless --body-file)
--body-file < path > read the comment body from a file (wins over -b)
2026-07-22 21:21:21 +00:00
```
```bash
stoke pr comment -o heavy-duty -r stoke -n 3 -b "Looks good."
```
Calls `POST /api/v1/repos/{owner}/{repo}/issues/{number}/comments` .
### `stoke pr review`
2026-07-22 23:18:43 +00:00
Submit a review on a pull request. `approve` / `approved` may omit a body; `request-changes` and `comment` require a non-empty body (raw body is preserved — only emptiness is checked with `trim()` ). When both `-b` and `--body-file` are set, ** `--body-file` wins**.
2026-07-22 21:21:21 +00:00
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-n, --number < number > pull request number (required)
2026-07-22 23:18:43 +00:00
--event < event > approve|approved, request-changes|request_changes, comment (required)
-b, --body < body > review body (markdown; required for request-changes and comment)
--body-file < path > read the review body from a file (wins over -b)
2026-07-26 21:46:28 +00:00
--commit < sha > commit SHA the review applies to (sent as commit_id)
2026-07-22 21:21:21 +00:00
```
```bash
stoke pr review -o heavy-duty -r stoke -n 3 --event approve -b "Ship it."
2026-07-22 23:18:43 +00:00
stoke pr review -o heavy-duty -r stoke -n 3 --event request-changes --body-file notes.md
2026-07-26 21:46:28 +00:00
stoke pr review -o heavy-duty -r stoke -n 3 --event approve --commit 9fceb02
2026-07-22 21:21:21 +00:00
```
2026-07-26 21:46:28 +00:00
Calls `POST /api/v1/repos/{owner}/{repo}/pulls/{number}/reviews` . `--commit` is sent as `commit_id` ; when omitted, no `commit_id` is sent. Prints the review URL when the forge returns one.
2026-07-22 21:21:21 +00:00
2026-07-26 20:31:07 +00:00
### `stoke release list`
List releases in a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-l, --limit < number > maximum releases to display (default: 50; use 0 for all)
```
```bash
stoke release list -o heavy-duty -r stoke
```
Calls `GET /api/v1/repos/{owner}/{repo}/releases` and auto-paginates.
### `stoke release view`
2026-08-30 09:58:06 +00:00
Show the release for a tag, including its notes and attached assets. Each asset
line includes its filename, size in bytes and download URL.
2026-07-26 20:31:07 +00:00
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
--tag < tag > tag name of the release (required)
```
```bash
stoke release view -o heavy-duty -r stoke --tag v1.2.1
```
Calls `GET /api/v1/repos/{owner}/{repo}/releases/tags/{tag}` .
### `stoke release create`
Create a release. If the tag does not exist yet, Forgejo creates it from `--target` (or the repository default branch). When both `-b` and `--body-file` are set, ** `--body-file` wins**.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
--tag < tag > tag name for the release (required)
--target < ref > branch or commit the tag is created from (default: default branch)
-t, --title < title > release title (default: the tag name)
-b, --body < body > release notes (markdown)
--body-file < path > read the release notes from a file (wins over -b)
2026-08-30 09:58:06 +00:00
--asset < path > attach an asset (repeatable)
--asset-name < name > override the uploaded filename (exactly one asset)
2026-07-26 20:31:07 +00:00
--draft create as a draft release
--prerelease mark as a prerelease
```
```bash
2026-08-30 09:58:06 +00:00
stoke release create -o heavy-duty -r stoke --tag v1.3.0 \
--body-file release-notes.md --asset dist/stoke_1.3.0_all.deb
2026-07-26 20:31:07 +00:00
```
2026-08-30 09:58:06 +00:00
The command prints the numeric release id, tag and URL. It calls
`POST /api/v1/repos/{owner}/{repo}/releases` , then uploads each asset. If an
upload fails, the release and any assets that already landed are kept; every
asset is attempted, the command names successes and failures, and exits
non-zero.
### `stoke release upload`
Attach one or more assets to an existing release. `--asset-name` overrides the
uploaded filename and is valid only when exactly one `--asset` is supplied.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
--tag < tag > tag name of the existing release (required)
--asset < path > asset to upload (required, repeatable)
--asset-name < name > override the uploaded filename (exactly one asset)
```
```bash
stoke release upload -o heavy-duty -r stoke --tag v1.3.0 \
--asset dist/checksums.txt --asset dist/stoke_1.3.0_all.deb
```
The command resolves the tag once with
`GET /api/v1/repos/{owner}/{repo}/releases/tags/{tag}` , then uploads each file
to the release's numeric-id asset endpoint. It attempts every asset and exits
non-zero if any upload fails.
2026-07-26 20:31:07 +00:00
### `stoke label list`
List labels in a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-l, --limit < number > maximum labels to display (default: 50; use 0 for all)
```
```bash
stoke label list -o heavy-duty -r stoke
```
Calls `GET /api/v1/repos/{owner}/{repo}/labels` and auto-paginates.
### `stoke label create`
Create a label in a repository. The color is validated (6 hex digits, with or without a leading `#` ) before any network call.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
--name < name > label name (required)
--color < color > label color, 6 hex digits (required)
-d, --description < description > label description
```
```bash
stoke label create -o heavy-duty -r stoke --name release --color 0E8A16 \
-d "Release flow and version/packaging work"
```
Calls `POST /api/v1/repos/{owner}/{repo}/labels` .
### `stoke label delete`
2026-07-26 20:52:29 +00:00
Delete a label from a repository, by `--id` or `--name` (exactly one is required; passing both is rejected).
2026-07-26 20:31:07 +00:00
```bash
stoke label delete -o heavy-duty -r stoke --name needs-triage
```
Calls `DELETE /api/v1/repos/{owner}/{repo}/labels/{id}` . A `--name` is resolved to an id via the repository label list first.
### `stoke label add`
Add labels to an issue or pull request (PRs are issues as far as labels are concerned).
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-n, --number < number > issue or pull request number (required)
--name < name... > one or more label names (required)
```
```bash
stoke label add -o heavy-duty -r stoke -n 12 --name release scope:cli
```
Calls `POST /api/v1/repos/{owner}/{repo}/issues/{number}/labels` . Names are resolved to ids first; an unknown name fails with `Label not found` .
### `stoke label remove`
Remove labels from an issue or pull request.
```bash
stoke label remove -o heavy-duty -r stoke -n 12 --name needs-triage
```
Calls `DELETE /api/v1/repos/{owner}/{repo}/issues/{number}/labels/{id}` once per label.
2026-07-22 15:16:42 +00:00
### `stoke branch list`
2026-07-22 15:03:32 +00:00
List branches in a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-l, --limit < number > maximum branches to display (default: 50; use 0 for all)
```
```bash
2026-07-22 15:16:42 +00:00
stoke branch list -o kimi-reviewer-andresmgsl -r box
2026-07-22 15:03:32 +00:00
```
Calls `GET /api/v1/repos/{owner}/{repo}/branches` and auto-paginates.
2026-07-22 15:16:42 +00:00
### `stoke collaborator add`
2026-07-22 15:06:35 +00:00
Add a collaborator to a repository.
```text
Options:
-o, --owner < owner > repository owner (required)
-r, --repo < repo > repository name (required)
-u, --user < username > username of the collaborator (required)
--permission < permission > read, write, or admin (default: write)
```
Example:
```bash
2026-07-22 15:16:42 +00:00
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
2026-07-22 15:06:35 +00:00
```
Calls `PUT /api/v1/repos/{owner}/{repo}/collaborators/{user}` .
2026-07-22 17:47:48 +00:00
### `stoke org create`
Create a new organization. The authenticated user becomes its first owner.
```text
Options:
--name < name > organization username, used in URLs (required)
--full-name < full-name > display name of the organization
-d, --description < description > organization description
--website < website > organization website
--location < location > organization location
--visibility < visibility > public, limited, private (default: public)
```
Example used to create the Heavy Duty Builders organization:
```bash
stoke org create --name heavy-duty --full-name "Heavy Duty Builders" \
--website https://heavyduty.builders --visibility public
```
Calls `POST /api/v1/orgs` .
### `stoke org repos`
List repositories owned by an organization.
```text
Options:
-o, --org < org > organization name (required)
-l, --limit < number > maximum repositories to display (default: 50; use 0 for all)
```
```bash
stoke org repos -o heavy-duty -l 0
```
Calls `GET /api/v1/orgs/{org}/repos` and auto-paginates.
### `stoke org avatar`
Set the avatar (logo) of an organization from a local image file. The image is read, base64-encoded and uploaded; the caller must be an owner of the organization.
```text
Options:
-o, --org < org > organization name (required)
-f, --file < path > path to the image file (png, jpeg, gif, ...) (required)
```
Example used to set the Heavy Duty Builders logo (sourced from the official GitHub organization avatar at `https://github.com/heavy-duty.png` ):
```bash
stoke org avatar -o heavy-duty -f heavy-duty-logo.png
```
Calls `POST /api/v1/orgs/{org}/avatar` .
2026-07-22 17:56:14 +00:00
### `stoke org team list`
List teams in an organization.
```bash
stoke org team list -o heavy-duty
```
Calls `GET /api/v1/orgs/{org}/teams` and auto-paginates.
### `stoke org team create`
Create a team in an organization.
```text
Options:
-o, --org < org > organization name (required)
--name < name > team name (required)
-d, --description < description > team description
--permission < permission > read, write, admin (default: read)
--all-repos grant access to all current and future org repositories
--can-create-repo allow members to create repositories in the organization
--units < units > comma-separated team units
(default: repo.code,repo.issues,repo.pulls,repo.releases,repo.wiki,repo.projects)
```
Example used to create the regular members team:
```bash
stoke org team create -o heavy-duty --name members --permission write --all-repos
```
Calls `POST /api/v1/orgs/{org}/teams` .
### `stoke org team member-list`
List members of a team. Requires being a member of that team (or an instance admin).
```bash
stoke org team member-list --team-id 2
```
Calls `GET /api/v1/teams/{id}/members` and auto-paginates.
### `stoke org team member-add`
Add a user to a team. Adding a user to any team also makes them a member of the organization; membership in the `Owners` team is what makes a user an organization admin.
```text
Options:
--team-id < id > team id, see `stoke org team list` (required)
-u, --user < username > username to add (required)
```
Example used to make Dan and Andres organization admins:
```bash
stoke org team member-add --team-id 1 -u andres
stoke org team member-add --team-id 1 -u dan
```
Calls `PUT /api/v1/teams/{id}/members/{username}` .
### `stoke org team member-remove`
Remove a user from a team.
```text
Options:
--team-id < id > team id, see `stoke org team list` (required)
-u, --user < username > username to remove (required)
```
```bash
stoke org team member-remove --team-id 1 -u kimi-reviewer-andresmgsl
```
Calls `DELETE /api/v1/teams/{id}/members/{username}` .
### `stoke user list`
Search/list users on the Forgejo instance. Non-admin searches are visibility-limited: an empty query typically returns only the authenticated user.
```text
Options:
-q, --query < query > search query (default: empty)
-l, --limit < number > maximum users to display (default: 50; use 0 for all)
```
```bash
stoke user list -q andres
```
Calls `GET /api/v1/users/search` and auto-paginates.
### `stoke user show`
Show a single user profile. Useful to check whether a username exists.
```bash
stoke user show -u andres
```
Calls `GET /api/v1/users/{username}` .
2026-07-26 20:31:07 +00:00
### `stoke api`
Make an authenticated request to any Forgejo API endpoint and print the JSON response. The escape hatch for everything stoke does not wrap yet — pass the endpoint path without the `/api/v1` prefix.
```text
Arguments:
< endpoint > endpoint path starting with / (required)
Options:
-X, --method < method > GET, POST, PUT, PATCH or DELETE
(default: GET, or POST when --input is given)
--input < json > JSON request body, inline or @path to read from a file
2026-07-26 20:52:29 +00:00
--paginate fetch all pages (GET endpoints returning a JSON array);
overrides any limit/page in the endpoint
2026-07-26 20:31:07 +00:00
```
```bash
stoke api /user
stoke api "/repos/heavy-duty/stoke/pulls?state=closed" --paginate
stoke api /repos/heavy-duty/stoke/issues/12/comments --input '{"body":"hi"}'
stoke api /repos/heavy-duty/stoke/contents/CHANGELOG.md --input @payload .json
```
2026-07-26 20:52:29 +00:00
Calls `{METHOD} /api/v1{endpoint}` with the stored token. The endpoint must start with `/` ; the method, `--paginate` + non-GET, `GET` + `--input` (a GET cannot carry a body), and malformed `--input` JSON are all rejected before any network call.
**Security:** `stoke api` is a full authenticated passthrough — it does anything the stored token is allowed to do. Never interpolate untrusted strings (issue titles, PR bodies, user input) into the endpoint or `--input` ; treat every call like the credential it carries.
2026-07-26 20:31:07 +00:00
2026-07-22 15:03:32 +00:00
## Architecture
```text
src/
├── cli.js # Commander program, commands and user I/O
├── api.js # Forgejo API client (fetch wrapper)
└── config.js # Secure filesystem-based config storage
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
test/
├── cli.test.js # end-to-end CLI behavior (spawned processes)
├── api.test.js # API client with a mocked fetch
└── config.test.js # config path resolution and persistence
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
scripts/
├── build-deb.sh # build dist/stoke_< version > _all.deb
├── publish-deb.sh # upload a .deb to the Forgejo Debian registry
└── install-apt.sh # consumer-side apt source setup + install
.forgejo/workflows/
└── release.yml # tag-driven build + publish + release attachment
2026-07-22 15:03:32 +00:00
```
- `cli.js` defines commands and options, handles prompts and prints results.
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
- `api.js` encapsulates all HTTP calls to Forgejo. It supports both Basic auth (for the token endpoints, which reject token auth) and token auth (for all other calls).
- `config.js` reads/writes JSON config and enforces restrictive file permissions. Paths are resolved lazily so the global `--config` flag works.
## Testing
The test suite uses the Node.js built-in test runner — no extra dependencies:
```bash
npm test
```
2026-07-22 15:03:32 +00:00
Add apt distribution: deb packaging, registry publish, docs (#1)
Implements #1 — stoke installable with apt-get install stoke.
Packaging:
- scripts/build-deb.sh: builds dist/stoke_<version>_all.deb from a clean
staging copy (src + fresh npm ci --omit=dev), pure-JS Architecture: all,
Depends: nodejs (>= 22.12), /usr/lib/stoke payload with /usr/bin/stoke
symlink, copyright + changelog, normalized permissions. Lintian-clean.
- scripts/publish-deb.sh: uploads a .deb to the Forgejo Debian registry
(owner/distribution/component parameterized, defaults heavy-duty/
stable/main), authenticating with STOKE_TOKEN or the stoke login token.
- scripts/install-apt.sh: consumer-side one-time setup — adds the
registry key and apt source, then apt-get install stoke. Falls back to
a [trusted=yes] source when apt's sqv verifier rejects the forge's
registry signature (known upstream Forgejo signing bug; the script
prefers the signed source so setups heal once the forge is fixed).
- .forgejo/workflows/release.yml: on v* tags — test, build, publish to
the heavy-duty registry, attach the .deb to the release page. Needs a
runner and a RELEASE_TOKEN secret with org package write.
New command:
- stoke pr merge (-n, --method merge|rebase|rebase-merge|squash,
--title, --message, --delete-branch) — gap found while merging !2.
Docs and housekeeping:
- README: 'Install with apt' as the primary installation method with
manual setup and dpkg fallback, signature caveat, pr merge reference,
Packaging and releasing section with a release checklist.
- dist/ gitignored; version bumped to 1.2.0.
Verified end-to-end on this machine: built the deb (lintian-clean),
published it to the Forgejo Debian registry, installed it with
apt-get install stoke via install-apt.sh, and confirmed the installed
CLI works against the live forge. The test upload was removed from the
personal namespace afterwards; publishing under heavy-duty needs an
org-member token (401 reqPackageAccess with this restricted account).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:40:51 +00:00
## Packaging and releasing
The Debian package is a pure-JS `Architecture: all` package that ships the CLI to `/usr/lib/stoke` with a `/usr/bin/stoke` symlink and declares `Depends: nodejs (>= 22.12)` .
Build locally (needs `dpkg-deb` ; runs `lintian` when installed):
```bash
scripts/build-deb.sh # -> dist/stoke_< version > _all.deb
```
Publish to the Forgejo Debian registry (uses `STOKE_TOKEN` or the `stoke auth login` token; the account needs package write access on the owner):
```bash
scripts/publish-deb.sh dist/stoke_< version > _all.deb heavy-duty stable main
```
Releases are automated in `.forgejo/workflows/release.yml` : pushing a `v*` tag runs the tests, builds the `.deb` , publishes it to the `heavy-duty` registry and attaches it to the tag's release page. The workflow needs a Forgejo Actions runner and a `RELEASE_TOKEN` secret (package + repository write for the `heavy-duty` org); adjust `runs-on` to a label your runner advertises.
Release checklist:
1. Bump `version` in `package.json` and `package-lock.json` .
2. Commit, tag `v<version>` , push the tag.
3. CI publishes the package; consumers get it with `apt-get update && apt-get upgrade` .
2026-07-22 15:03:32 +00:00
## Security notes
- Tokens are stored on disk with `0600` permissions.
Audit: fix auth/config bugs, add issue/pr create, tests and docs
Fixes found during a full audit of the CLI:
- auth logout: remote token revocation always failed with 401 because
Forgejo only accepts Basic auth on the token endpoints. Logout now
asks for (or accepts) the account password, supports --password,
--password-file and --local-only, and clearly reports when the token
is left active.
- Silent password prompt actually echoed the password on a TTY:
overriding rl.write does not suppress readline echo. Switched to the
callback readline module and mute _writeToOutput instead (the
readline/promises interface does not honor that hook).
- Global --config flag was silently ignored: config paths were resolved
at require time, before the preAction hook set STOKE_CONFIG_FILE.
Paths are now resolved lazily on every access.
- XDG_CONFIG_HOME handling put the config in $XDG_CONFIG_HOME/.config/stoke;
per the XDG spec it now resolves to $XDG_CONFIG_HOME/stoke.
- repo create: --auto-init defaulted to true with no way to disable it;
added --no-auto-init.
- repo import/import-batch: a GitHub token was required even for
non-GitHub services (e.g. --service git), making those imports fail
without gh/GITHUB_TOKEN. Tokens are now only auto-resolved for the
github service; batch imports resolve per entry and memoize.
- Branding leftovers: 'Run: forgejo auth login' hint and
forgejo-cli/1.0.0 User-Agent now say stoke (UA tracks pkg.version).
- Added request timeouts (30s default, 10m for migrations).
- --limit and --team-id are validated as integers instead of silently
misbehaving on garbage (NaN made -l show all results).
New commands (per the repo's every-operation-becomes-a-command design):
- stoke issue create (title/body/body-file/assignees)
- stoke pr create (head/base/title/body/body-file)
Tests and metadata:
- New test suite on the built-in node:test runner (25 tests) covering
config resolution/persistence, the API client with a mocked fetch,
and end-to-end CLI behavior. npm test previously matched no files.
- package.json: engines >=22.12.0 (required by commander@15 — the
README claimed Node 18), repository, keywords, author; version 1.1.0.
- README: corrected Node requirement, documented repo rename (was
missing), issue create, pr create, logout options and revocation
caveat, --no-auto-init, XDG behavior, import token rules, testing.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-22 19:28:23 +00:00
- Passwords are never persisted; they are only used to generate (and revoke) a token, and interactive password prompts do not echo to the terminal.
2026-07-22 15:16:42 +00:00
- Prefer `--password-file` or `STOKE_PASSWORD` over `-p` to keep passwords out of shell history and avoid `!` history-expansion issues.
2026-07-22 15:03:32 +00:00
- The generated token name includes the hostname and a timestamp to avoid collisions.
## Verification: heavy-duty repository imports
2026-07-22 17:47:48 +00:00
The heavy-duty repositories were imported into Forgejo under `https://forgejo.heavyduty.builders/kimi-reviewer-andresmgsl` and later transferred to the `heavy-duty` organization (`https://forgejo.heavyduty.builders/heavy-duty`) using `stoke repo transfer` .
2026-07-22 15:03:32 +00:00
| Repository | Visibility | Branches | Commits | Open issues | Total issues | PRs | Labels | Milestones | Releases |
| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `box` | public | 1 | 306 | 11 | 65 | 92 | 21 | 0 | 4 |
| `rig` | public | 1 | 198 | 10 | 49 | 59 | 21 | 0 | 3 |
| `cast` | public | 1 | 194 | 7 | 67 | 75 | 21 | 0 | 3 |
| `infra` | private | 1 | 86 | 2 | 8 | 22 | 9 | 0 | 0 |
| `handbook` | private | 1 | 29 | 28 | 28 | 13 | 9 | 5 | 0 |
| `incubator` | private | 1 | 1,326 | 1 | 1 | 23 | 9 | 0 | 0 |
Counts match GitHub for all repositories. Git history, issues, pull requests, labels, milestones and releases are included. Discussions are not enabled on any of the source repositories. The `cast` wiki is enabled on GitHub but contains no pages, so nothing was migrated.
## Next steps
2026-07-22 15:16:42 +00:00
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` .
2026-07-22 16:38:14 +00:00
## Why the name `stoke`?
The heavy-duty handbook defines a strict naming style for tools:
- **one syllable**, plain concrete English — industrial: the shop floor and the site
- **a repurposed common word**, never coined jargon
- **a verb⇄noun with a double meaning** that hints at the job
Existing tools follow this exactly: `cast` pours a part and is the part; `rig` sets up and is the setup; `jig` holds work and is the fixture; `boss` runs the site and is the supervisor; `hand` works and is the worker; `gig` is a one-off job and the job itself; `gauge` measures and is the instrument.
The handbook calls the Forgejo instance ** "the forge"** — the coordination home where issues, PRs, reviews, and git state live. A forge only stays useful if someone feeds it fuel and air. *To stoke* a fire is to tend it and keep it burning. This CLI does the same thing programmatically: it creates repos, opens issues, imports projects, adds collaborators — it keeps the forge active.
`stoke` also fits the operator relationship. While `jig` , `boss` , `hand` , and `gauge` are autonomous or daemon-like, this tool is the operator's hand on the forge. You don't forge by accident; you stoke on purpose.
Other names were considered and rejected:
- `forge` — too literal; the forge is the platform, not the tool.
- `tap` — machining term, but "tapping" is about threading holes, not tending a forge.
- `weld` / `braze` — join-metal verbs, but the CLI is not primarily joining things.
- `die` / `mold` / `stamp` — shaping tools, but `die` carries a strong negative meaning and `mold` has the fungus connotation.
- `quench` — forge-related, but quenching cools/finishes; the CLI starts and feeds work.
- `draft` / `blast` — air-feeding the forge, but feel like background services, not an operator CLI.
- `flux` — nice metaphor for flow, but reads as chemistry rather than the forge shop.
`stoke` was the only candidate that was clearly forge-specific, operator-facing, one syllable, and already a common verb/noun.