Skip to content

Commit b25a6bb

Browse files
Add Random Joke CLI (index.js, package.json, README, .gitignore)
1 parent db24169 commit b25a6bb

4 files changed

Lines changed: 169 additions & 178 deletions

File tree

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules/
2+
.DS_Store

README.md

Lines changed: 19 additions & 178 deletions
Original file line numberDiff line numberDiff line change
@@ -1,194 +1,35 @@
1-
# GitHub Copilot CLI
1+
# Xx2Dee7xX-joke-cli
22

3-
The power of GitHub Copilot, now in your terminal.
3+
Small CLI that fetches random jokes from JokeAPI.
44

5-
GitHub Copilot CLI brings AI-powered coding assistance directly to your command line, enabling you to build, debug, and understand code through natural language conversations. Powered by the same agentic harness as GitHub's Copilot coding agent, it provides intelligent assistance while staying deeply integrated with your GitHub workflow.
5+
## Requirements
66

7-
See [our official documentation](https://docs.github.com/copilot/concepts/agents/about-copilot-cli) for more information.
7+
- Node.js 18+ (uses global fetch and AbortController)
88

9-
![Image of the splash screen for the Copilot CLI](https://github.com/user-attachments/assets/f40aa23d-09dd-499e-9457-1d57d3368887)
9+
## Install / Run
1010

11-
12-
## 🚀 Introduction and Overview
13-
14-
We're bringing the power of GitHub Copilot coding agent directly to your terminal. With GitHub Copilot CLI, you can work locally and synchronously with an AI agent that understands your code and GitHub context.
15-
16-
- **Terminal-native development:** Work with Copilot coding agent directly in your command line — no context switching required.
17-
- **GitHub integration out of the box:** Access your repositories, issues, and pull requests using natural language, all authenticated with your existing GitHub account.
18-
- **Agentic capabilities:** Build, edit, debug, and refactor code with an AI collaborator that can plan and execute complex tasks.
19-
- **MCP-powered extensibility:** Take advantage of the fact that the coding agent ships with GitHub's MCP server by default and supports custom MCP servers to extend capabilities.
20-
- **Full control:** Preview every action before execution — nothing happens without your explicit approval.
21-
22-
We're still early in our journey, but with your feedback, we're rapidly iterating to make the GitHub Copilot CLI the best possible companion in your terminal.
23-
24-
## 📦 Getting Started
25-
26-
### Supported Platforms
27-
28-
- **Linux**
29-
- **macOS**
30-
- **Windows**
31-
32-
### Prerequisites
33-
34-
- (On Windows) **PowerShell** v6 or higher
35-
- An **active Copilot subscription**. See [Copilot plans](https://github.com/features/copilot/plans?ref_cta=Copilot+plans+signup&ref_loc=install-copilot-cli&ref_page=docs).
36-
37-
If you have access to GitHub Copilot via your organization or enterprise, you cannot use GitHub Copilot CLI if your organization owner or enterprise administrator has disabled it in the organization or enterprise settings. See [Managing policies and features for GitHub Copilot in your organization](http://docs.github.com/copilot/managing-copilot/managing-github-copilot-in-your-organization/managing-github-copilot-features-in-your-organization/managing-policies-for-copilot-in-your-organization) for more information.
38-
39-
### Installation
40-
41-
Install with the install script (macOS and Linux):
42-
43-
```bash
44-
curl -fsSL https://gh.io/copilot-install | bash
45-
```
46-
47-
Or
11+
Make the script executable and run locally:
4812

4913
```bash
50-
wget -qO- https://gh.io/copilot-install | bash
14+
chmod +x index.js
15+
./index.js
5116
```
5217

53-
Use `| sudo bash` to run as root and install to `/usr/local/bin`.
54-
55-
Set `PREFIX` to install to `$PREFIX/bin/` directory. Defaults to `/usr/local`
56-
when run as root or `$HOME/.local` when run as a non-root user.
57-
58-
Set `VERSION` to install a specific version. Defaults to the latest version.
59-
60-
For example, to install version `v0.0.369` to a custom directory:
18+
Or run with node directly:
6119

6220
```bash
63-
curl -fsSL https://gh.io/copilot-install | VERSION="v0.0.369" PREFIX="$HOME/custom" bash
21+
node index.js --category Programming --repeat 3
6422
```
6523

66-
Install with [Homebrew](https://formulae.brew.sh/cask/copilot-cli) (macOS and Linux):
67-
68-
```bash
69-
brew install copilot-cli
70-
```
71-
72-
```bash
73-
brew install copilot-cli@prerelease
74-
```
75-
76-
77-
Install with [WinGet](https://github.com/microsoft/winget-cli) (Windows):
78-
79-
```bash
80-
winget install GitHub.Copilot
81-
```
82-
83-
```bash
84-
winget install GitHub.Copilot.Prerelease
85-
```
86-
87-
88-
Install with [npm](https://www.npmjs.com/package/@github/copilot) (macOS, Linux, and Windows):
89-
90-
```bash
91-
npm install -g @github/copilot
92-
```
93-
94-
```bash
95-
npm install -g @github/copilot@prerelease
96-
```
97-
98-
99-
### Launching the CLI
100-
101-
```bash
102-
copilot
103-
```
104-
105-
On first launch, you'll be greeted with our adorable animated banner! If you'd like to see this banner again, launch `copilot` with the `--banner` flag.
106-
107-
If you're not currently logged in to GitHub, you'll be prompted to use the `/login` slash command. Enter this command and follow the on-screen instructions to authenticate.
108-
109-
#### Authenticate with a Personal Access Token (PAT)
110-
111-
You can also authenticate using a fine-grained PAT with the "Copilot Requests" permission enabled.
112-
113-
1. Visit https://github.com/settings/personal-access-tokens/new
114-
2. Under "Permissions," click "add permissions" and select "Copilot Requests"
115-
3. Generate your token
116-
4. Add the token to your environment via the environment variable `GH_TOKEN` or `GITHUB_TOKEN` (in order of precedence)
117-
118-
### Using the CLI
119-
120-
Launch `copilot` in a folder that contains code you want to work with.
121-
122-
By default, `copilot` utilizes Claude Sonnet 4.5. Run the `/model` slash command to choose from other available models, including Claude Sonnet 4 and GPT-5.
123-
124-
### Experimental Mode
125-
126-
Experimental mode enables access to new features that are still in development. You can activate experimental mode by:
127-
128-
- Launching with the `--experimental` flag: `copilot --experimental`
129-
- Using the `/experimental` slash command from within the CLI
130-
131-
Once activated, the setting is persisted in your config, so the `--experimental` flag is no longer needed on subsequent launches.
132-
133-
#### Experimental Features
134-
135-
- **Autopilot mode:** Autopilot is a new mode (press `Shift+Tab` to cycle through modes), which encourages the agent to continue working until a task is completed.
136-
137-
Each time you submit a prompt to GitHub Copilot CLI, your monthly quota of premium requests is reduced by one. For information about premium requests, see [About premium requests](https://docs.github.com/copilot/managing-copilot/monitoring-usage-and-entitlements/about-premium-requests).
138-
139-
For more information about how to use the GitHub Copilot CLI, see [our official documentation](https://docs.github.com/copilot/concepts/agents/about-copilot-cli).
140-
141-
## 🔧 Configuring LSP Servers
142-
143-
GitHub Copilot CLI supports Language Server Protocol (LSP) for enhanced code intelligence. This feature provides intelligent code features like go-to-definition, hover information, and diagnostics.
144-
145-
### Installing Language Servers
146-
147-
Copilot CLI does not bundle LSP servers. You need to install them separately. For example, to set up TypeScript support:
148-
149-
```bash
150-
npm install -g typescript-language-server
151-
```
152-
153-
For other languages, install the corresponding LSP server and configure it following the same pattern shown below.
154-
155-
### Configuring LSP Servers
156-
157-
LSP servers are configured through a dedicated LSP configuration file. You can configure LSP servers at the user level or repository level:
158-
159-
**User-level configuration** (applies to all projects):
160-
Edit `~/.copilot/lsp-config.json`
161-
162-
**Repository-level configuration** (applies to specific project):
163-
Create `.github/lsp.json` in your repository root
164-
165-
Example configuration:
166-
167-
```json
168-
{
169-
"lspServers": {
170-
"typescript": {
171-
"command": "typescript-language-server",
172-
"args": ["--stdio"],
173-
"fileExtensions": {
174-
".ts": "typescript",
175-
".tsx": "typescript"
176-
}
177-
}
178-
}
179-
}
180-
```
181-
182-
### Viewing LSP Server Status
183-
184-
Check configured LSP servers using the `/lsp` command in an interactive session, or view your configuration files directly.
185-
186-
For more information, see the [changelog](./changelog.md).
187-
188-
## 📢 Feedback and Participation
24+
## Options
18925

190-
We're excited to have you join us early in the Copilot CLI journey.
26+
- `--category, -c` Joke category (Any, Programming, Misc, Dark, Pun, Spooky, Christmas, etc.)
27+
- `--unsafe` Allow all flags (disables blacklist). By default explicit/racist/etc. are filtered.
28+
- `--timeout` Fetch timeout in milliseconds (default 5000)
29+
- `--retries` Number of retries on network errors (default 2)
30+
- `--repeat` How many jokes to fetch (default 1)
19131

192-
We're building quickly. Expect frequent updates--please keep your client up to date for the latest features and fixes!
32+
## Notes
19333

194-
Your insights are invaluable! Open an issue in this repo, join Discussions, and run `/feedback` from the CLI to submit a confidential feedback survey!
34+
- The CLI uses [JokeAPI](https://v2.jokeapi.dev). No API key is required.
35+
- For Node <18 support, add a polyfill such as `node-fetch` and update the script accordingly.

index.js

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
#!/usr/bin/env node
2+
/**
3+
* Random Joke CLI (no dependencies)
4+
*
5+
* Usage:
6+
* node index.js [--category Any] [--unsafe] [--timeout 5000] [--retries 2] [--repeat 1]
7+
*
8+
* Examples:
9+
* ./index.js
10+
* ./index.js --category Programming
11+
* ./index.js --unsafe --repeat 3
12+
*/
13+
14+
const DEFAULT_TIMEOUT = 5000; // ms
15+
const DEFAULT_RETRIES = 2;
16+
const DEFAULT_REPEAT = 1;
17+
18+
function parseArgs(argv) {
19+
const args = {
20+
category: 'Any',
21+
safe: true,
22+
timeout: DEFAULT_TIMEOUT,
23+
retries: DEFAULT_RETRIES,
24+
repeat: DEFAULT_REPEAT,
25+
};
26+
27+
for (let i = 2; i < argv.length; i++) {
28+
const a = argv[i];
29+
if (a === '--category' || a === '-c') {
30+
args.category = argv[++i] || 'Any';
31+
} else if (a === '--unsafe') {
32+
args.safe = false;
33+
} else if (a === '--timeout') {
34+
args.timeout = Number(argv[++i]) || DEFAULT_TIMEOUT;
35+
} else if (a === '--retries') {
36+
args.retries = Math.max(0, Number(argv[++i]) || DEFAULT_RETRIES);
37+
} else if (a === '--repeat') {
38+
args.repeat = Math.max(1, Number(argv[++i]) || DEFAULT_REPEAT);
39+
} else if (a === '--help' || a === '-h') {
40+
printHelpAndExit();
41+
} else {
42+
console.warn(`Unknown arg: ${a}`);
43+
printHelpAndExit(1);
44+
}
45+
}
46+
return args;
47+
}
48+
49+
function printHelpAndExit(code = 0) {
50+
console.log(`
51+
Random Joke CLI
52+
53+
Usage:
54+
index.js [--category <Category>] [--unsafe] [--timeout <ms>] [--retries <n>] [--repeat <n>]
55+
56+
Options:
57+
--category, -c Joke category (Any, Programming, Misc, Dark, Pun, Spooky, Christmas, etc.)
58+
--unsafe Allow all flags (disables blacklist). By default explicit/racist/etc. are filtered.
59+
--timeout Fetch timeout in milliseconds (default ${DEFAULT_TIMEOUT})
60+
--retries Number of retries on network errors (default ${DEFAULT_RETRIES})
61+
--repeat How many jokes to fetch (default ${DEFAULT_REPEAT})
62+
--help, -h Show this help
63+
`);
64+
process.exit(code);
65+
}
66+
67+
async function fetchWithTimeout(url, timeoutMs, retries) {
68+
let lastErr = null;
69+
for (let attempt = 0; attempt <= retries; attempt++) {
70+
const controller = new AbortController();
71+
const id = setTimeout(() => controller.abort(), timeoutMs);
72+
73+
try {
74+
const res = await fetch(url, { signal: controller.signal });
75+
clearTimeout(id);
76+
if (!res.ok) {
77+
lastErr = new Error(`HTTP ${res.status}`);
78+
// For 4xx/5xx, don't retry further in many cases, but we'll retry anyway a limited number of times.
79+
throw lastErr;
80+
}
81+
const data = await res.json();
82+
return data;
83+
} catch (err) {
84+
clearTimeout(id);
85+
lastErr = err;
86+
const isAbort = err.name === 'AbortError';
87+
const isLast = attempt === retries;
88+
if (isLast) break;
89+
const backoff = 200 * Math.pow(2, attempt); // simple exponential backoff
90+
await new Promise(r => setTimeout(r, backoff));
91+
}
92+
}
93+
throw lastErr;
94+
}
95+
96+
function buildUrl(category, safe) {
97+
const base = 'https://v2.jokeapi.dev/joke';
98+
const cat = encodeURIComponent(category || 'Any');
99+
const params = new URLSearchParams();
100+
if (safe) params.set('blacklistFlags', 'nsfw,religious,political,racist,sexist,explicit');
101+
// You can add other params like lang= or format=
102+
return `${base}/${cat}?${params.toString()}`;
103+
}
104+
105+
function printJoke(data) {
106+
if (!data) return;
107+
if (data.error) {
108+
console.error('API error:', data.message || JSON.stringify(data));
109+
return;
110+
}
111+
if (data.type === 'single') {
112+
console.log(data.joke);
113+
} else {
114+
console.log(data.setup);
115+
console.log(data.delivery);
116+
}
117+
}
118+
119+
async function main() {
120+
const opts = parseArgs(process.argv);
121+
const url = buildUrl(opts.category, opts.safe);
122+
123+
for (let i = 0; i < opts.repeat; i++) {
124+
try {
125+
const data = await fetchWithTimeout(url, opts.timeout, opts.retries);
126+
printJoke(data);
127+
if (i < opts.repeat - 1) console.log('---'); // separator between jokes
128+
} catch (err) {
129+
console.error('Failed to fetch joke:', err.message || err);
130+
process.exitCode = 1;
131+
return;
132+
}
133+
}
134+
}
135+
136+
main();

package.json

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"name": "Xx2Dee7xX-joke-cli",
3+
"version": "0.1.0",
4+
"description": "Small CLI that fetches random jokes from JokeAPI",
5+
"bin": {
6+
"random-joke": "index.js"
7+
},
8+
"engines": {
9+
"node": ">=18"
10+
},
11+
"license": "MIT"
12+
}

0 commit comments

Comments
 (0)