@slahon/lazykit 1.3.0 → 1.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +19 -4
  2. package/git.js +10 -1
  3. package/init.js +40 -23
  4. package/package.json +1 -1
package/README.md CHANGED
@@ -21,12 +21,14 @@ Run this from your **project's root directory** — the same folder that contain
21
21
  - Node.js 18+
22
22
  - A GitHub repository with a remote set up (`git remote -v` should show a GitHub URL)
23
23
  - A Claude Pro or Max subscription ([claude.ai](https://claude.ai))
24
- - Claude Code installed locally (`npm install -g @anthropic-ai/claude-code`)
25
- - GitHub CLI (`gh`) — required for full automation (`brew install gh` / [cli.github.com](https://cli.github.com))
24
+ - **Claude Code CLI** `npm install -g @anthropic-ai/claude-code`
25
+ - **GitHub CLI (`gh`)** — `brew install gh` or [cli.github.com](https://cli.github.com), then `gh auth login`
26
26
  - **Claude Code GitHub App** installed on your repo — [github.com/apps/claude](https://github.com/apps/claude) *(required for the Actions workflow to run)*
27
27
 
28
28
  > **All `npx @slahon/lazykit` commands must be run from your project's root directory** — the folder where your `.git` directory lives and your GitHub remote is configured.
29
29
 
30
+ `init` checks for `gh` and `claude` before proceeding. If either is missing or not authenticated, it will show you exactly what to install and wait for you to confirm before continuing — no need to restart.
31
+
30
32
  ## How it works
31
33
 
32
34
  ### 1. Open an issue using the LazyKit Task template
@@ -137,9 +139,22 @@ During `npx @slahon/lazykit@latest init` you will be asked:
137
139
 
138
140
  LazyKit uses your Claude Pro/Max subscription via an OAuth token — no pay-per-token API billing.
139
141
 
140
- `init` handles this automatically: it runs `claude setup-token`, captures the token, and stores it as `CLAUDE_CODE_OAUTH_TOKEN` in your repo secrets via `gh secret set`.
142
+ During `init`, LazyKit runs `claude setup-token` and tries to capture the token automatically. On many systems a browser window opens, you approve access, and the token is stored as `CLAUDE_CODE_OAUTH_TOKEN` in your repo secrets without any extra steps.
143
+
144
+ If the token can't be captured automatically (varies by system), LazyKit falls back and shows you how to get it:
145
+
146
+ **Option A — run in a new terminal:**
147
+ ```bash
148
+ claude setup-token
149
+ ```
150
+ If the browser doesn't open, copy the URL it prints and open it manually in your browser.
151
+
152
+ **Option B — get it directly from Claude.ai:**
153
+ 1. Go to `https://claude.ai/settings/claude-code`
154
+ 2. Click **"Generate token"**
155
+ 3. Copy the token (starts with `sk-ant-oat...`)
141
156
 
142
- If the token can't be set automatically (Claude Code not installed or `gh` not available), you'll see step-by-step instructions to do it manually.
157
+ Then paste it when LazyKit prompts you it sets the GitHub secret automatically.
143
158
 
144
159
  **Token expiry:** OAuth tokens can expire. Run `lazykit status` to check the age of your token. If it's expired, re-run `npx @slahon/lazykit@latest init` to generate and store a fresh one.
145
160
 
package/git.js CHANGED
@@ -91,6 +91,15 @@ function detectStack() {
91
91
  return stack.length > 0 ? stack.join(' + ') : null;
92
92
  }
93
93
 
94
+ function isClaudeAvailable() {
95
+ try {
96
+ execSync('claude --version', { stdio: 'ignore' });
97
+ return true;
98
+ } catch {
99
+ return false;
100
+ }
101
+ }
102
+
94
103
  function hasBranchProtection({ owner, repo }) {
95
104
  try {
96
105
  execSync(`gh api repos/${owner}/${repo}/branches/main/protection`, { stdio: 'pipe' });
@@ -100,4 +109,4 @@ function hasBranchProtection({ owner, repo }) {
100
109
  }
101
110
  }
102
111
 
103
- module.exports = { getGitRemote, parseGitHubRepo, isGitRepo, isGhCliAvailable, isGhAuthenticated, detectStack, hasBranchProtection };
112
+ module.exports = { getGitRemote, parseGitHubRepo, isGitRepo, isGhCliAvailable, isGhAuthenticated, isClaudeAvailable, detectStack, hasBranchProtection };
package/init.js CHANGED
@@ -8,7 +8,7 @@ const ora = require('ora');
8
8
 
9
9
  const { log } = require('./logger');
10
10
  const { ask, confirm } = require('./prompt');
11
- const { isGitRepo, getGitRemote, parseGitHubRepo, isGhCliAvailable, isGhAuthenticated, detectStack, hasBranchProtection } = require('./git');
11
+ const { isGitRepo, getGitRemote, parseGitHubRepo, isGhCliAvailable, isGhAuthenticated, isClaudeAvailable, detectStack, hasBranchProtection } = require('./git');
12
12
  const { generateWorkflow } = require('./workflow');
13
13
  const { generateClaudeMd } = require('./claude-md');
14
14
  const { generateIssueTemplate } = require('./issue-template');
@@ -45,28 +45,38 @@ async function init({ dryRun = false } = {}) {
45
45
  process.exit(1);
46
46
  }
47
47
 
48
- // ─── Step 2: Check gh CLI and auth ───────────────────────────────────────
49
- const ghAvailable = isGhCliAvailable();
50
- let ghReady = false;
51
-
52
- if (!ghAvailable) {
53
- log.warn('GitHub CLI (gh) not found.');
54
- console.log(chalk.gray('\n LazyKit uses gh to create labels, set secrets, and enable PR permissions.'));
55
- console.log(chalk.gray(' Without it, those steps will be skipped and you will need to do them manually.\n'));
56
- console.log(chalk.gray(' Install gh from: ') + chalk.cyan('https://cli.github.com'));
57
- console.log(chalk.gray(' Then re-run: ') + chalk.cyan('npx @slahon/lazykit@latest init\n'));
58
- const cont = await confirm('Continue without gh? (some steps will be manual)', false);
59
- if (!cont) process.exit(0);
60
- } else if (!isGhAuthenticated()) {
61
- log.warn('GitHub CLI is not authenticated.');
62
- console.log(chalk.gray('\n Run the following to log in, then re-run LazyKit:\n'));
63
- console.log(chalk.cyan(' gh auth login'));
64
- console.log(chalk.gray('\n Then re-run: ') + chalk.cyan('npx @slahon/lazykit@latest init\n'));
65
- const cont = await confirm('Continue without gh auth? (some steps will be manual)', false);
66
- if (!cont) process.exit(0);
67
- } else {
68
- ghReady = true;
48
+ // ─── Step 2: Check dependencies (mandatory) ──────────────────────────────
49
+
50
+ // gh CLI
51
+ while (!isGhCliAvailable()) {
52
+ log.error('GitHub CLI (gh) is required but not found.');
53
+ console.log(chalk.gray('\n LazyKit uses gh to create labels, set secrets, and enable PR permissions.\n'));
54
+ console.log(chalk.gray(' Install it from: ') + chalk.cyan('https://cli.github.com'));
55
+ console.log(chalk.gray(' macOS: ') + chalk.cyan('brew install gh'));
56
+ console.log(chalk.gray(' Windows: ') + chalk.cyan('winget install --id GitHub.cli\n'));
57
+ await confirm('Press Enter once gh is installed to check again', true);
69
58
  }
59
+ log.success('GitHub CLI (gh) found');
60
+
61
+ // gh auth
62
+ while (!isGhAuthenticated()) {
63
+ log.error('GitHub CLI is not authenticated.');
64
+ console.log(chalk.gray('\n Run this in your terminal, then come back:\n'));
65
+ console.log(chalk.cyan(' gh auth login\n'));
66
+ await confirm('Press Enter once you are logged in to check again', true);
67
+ }
68
+ log.success('GitHub CLI authenticated');
69
+
70
+ // Claude Code CLI
71
+ while (!isClaudeAvailable()) {
72
+ log.error('Claude Code CLI is required but not found.');
73
+ console.log(chalk.gray('\n Install it with:\n'));
74
+ console.log(chalk.cyan(' npm install -g @anthropic-ai/claude-code\n'));
75
+ await confirm('Press Enter once Claude Code is installed to check again', true);
76
+ }
77
+ log.success('Claude Code CLI found');
78
+
79
+ const ghReady = true;
70
80
 
71
81
  log.blank();
72
82
 
@@ -203,7 +213,14 @@ async function init({ dryRun = false } = {}) {
203
213
  if (!token) {
204
214
  console.log();
205
215
  log.warn('Could not capture the token automatically.');
206
- console.log(chalk.gray(' If a browser opened, complete the auth and copy the token it shows.\n'));
216
+ console.log(chalk.gray('\n If no browser opened, here\'s how to get your token manually:\n'));
217
+ console.log(chalk.bold(' Option A — run in a new terminal window:'));
218
+ console.log(chalk.cyan(' claude setup-token'));
219
+ console.log(chalk.gray(' If the browser still doesn\'t open, copy the URL it prints and open it manually.\n'));
220
+ console.log(chalk.bold(' Option B — get it directly from Claude.ai:'));
221
+ console.log(chalk.gray(' 1. Go to: ') + chalk.cyan('https://claude.ai/settings/claude-code'));
222
+ console.log(chalk.gray(' 2. Click "Generate token"'));
223
+ console.log(chalk.gray(' 3. Copy the token (starts with sk-ant-oat...)\n'));
207
224
  const pasted = await ask('Paste your token here (or press Enter to skip)', '');
208
225
  if (pasted && pasted.trim().startsWith('sk-ant-oat')) {
209
226
  token = pasted.trim();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@slahon/lazykit",
3
- "version": "1.3.0",
3
+ "version": "1.3.2",
4
4
  "description": "Drop an issue, get a PR. AI-powered issue-to-PR automation using Claude.",
5
5
  "bin": {
6
6
  "lazykit": "./index.js"