client-handover 1.0.4 → 1.0.5

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.
package/README.md CHANGED
@@ -163,7 +163,9 @@ All prompt builders accept an optional `projectInfo` string. If omitted, Claude
163
163
  ## Requirements
164
164
 
165
165
  - Node.js 18+
166
- - An Anthropic API key — [get one free at console.anthropic.com](https://console.anthropic.com)
166
+ - One of the following:
167
+ - [Claude Code](https://marketplace.visualstudio.com/items?itemName=anthropic.claude-code) installed (zero config — credentials detected automatically)
168
+ - Or an Anthropic API key — [get one free at console.anthropic.com](https://console.anthropic.com)
167
169
 
168
170
  ---
169
171
 
@@ -196,6 +198,27 @@ client-handover/
196
198
 
197
199
  ---
198
200
 
201
+ ## Changelog
202
+
203
+ ### 1.0.5
204
+ - Interactive API key setup prompt on install — no manual config needed
205
+ - Added `handover key <api-key>` command to save key at any time
206
+ - Key is stored in `~/.handover/config.json` and persists across all sessions
207
+
208
+ ### 1.0.4
209
+ - Auto-detects Claude Code credentials — no API key setup needed if you have Claude Code installed
210
+
211
+ ### 1.0.3
212
+ - Commands now work with or without a leading `/` — fixes Git Bash path conversion issues on Windows
213
+
214
+ ### 1.0.2
215
+ - Added `all` command — generates every section as separate files in a single named folder
216
+
217
+ ### 1.0.1
218
+ - Initial release
219
+
220
+ ---
221
+
199
222
  ## Contributing
200
223
 
201
224
  Pull requests are welcome. For major changes, open an issue first.
package/cli.js CHANGED
@@ -5,7 +5,7 @@ import { deploy } from './deploy.js'
5
5
  import { credentials } from './credentials.js'
6
6
  import { handover } from './handover.js'
7
7
  import { license } from './license.js'
8
- import { generateDoc } from './generator.js'
8
+ import { generateDoc, saveApiKey } from './generator.js'
9
9
  import chalk from 'chalk'
10
10
  import fs from 'fs'
11
11
  import path from 'path'
@@ -33,6 +33,7 @@ function printHelp() {
33
33
  console.log(` ${chalk.cyan(cmd.padEnd(16))} ${label}`)
34
34
  })
35
35
  console.log(` ${chalk.cyan('all'.padEnd(16))} All sections in a single folder`)
36
+ console.log(` ${chalk.cyan('key <api-key>'.padEnd(16))} Save your Anthropic API key (one-time setup)`)
36
37
  console.log('\n' + chalk.dim('Examples:'))
37
38
  console.log(' handover handover # Full doc with placeholders')
38
39
  console.log(' handover setup project-info.txt # Setup section using your notes')
@@ -74,6 +75,17 @@ async function main() {
74
75
 
75
76
  const command = normalizeCommand(rawCommand)
76
77
 
78
+ if (command === 'key') {
79
+ const key = infoFile // second arg is the key
80
+ if (!key) {
81
+ console.error(chalk.red('\n❌ Usage: handover key <your-api-key>\n'))
82
+ process.exit(1)
83
+ }
84
+ saveApiKey(key)
85
+ console.log(chalk.green('\n✅ API key saved. You\'re all set — run any handover command.\n'))
86
+ process.exit(0)
87
+ }
88
+
77
89
  // Read optional project info file
78
90
  let projectInfo = ''
79
91
  if (infoFile) {
package/generator.js CHANGED
@@ -7,6 +7,17 @@ import os from 'os'
7
7
  function resolveApiKey() {
8
8
  if (process.env.ANTHROPIC_API_KEY) return process.env.ANTHROPIC_API_KEY
9
9
 
10
+ // Check saved key from `handover key <your-key>`
11
+ const configPath = path.join(os.homedir(), '.handover', 'config.json')
12
+ if (fs.existsSync(configPath)) {
13
+ try {
14
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
15
+ if (config?.apiKey) return config.apiKey
16
+ } catch {
17
+ // ignore malformed config file
18
+ }
19
+ }
20
+
10
21
  const credentialsPath = path.join(os.homedir(), '.claude', '.credentials.json')
11
22
  if (fs.existsSync(credentialsPath)) {
12
23
  try {
@@ -24,6 +35,13 @@ function resolveApiKey() {
24
35
  return null
25
36
  }
26
37
 
38
+ export function saveApiKey(key) {
39
+ const configDir = path.join(os.homedir(), '.handover')
40
+ const configPath = path.join(configDir, 'config.json')
41
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true })
42
+ fs.writeFileSync(configPath, JSON.stringify({ apiKey: key }, null, 2), 'utf-8')
43
+ }
44
+
27
45
  const apiKey = resolveApiKey()
28
46
  if (!apiKey) {
29
47
  console.error('\n❌ No API key found. Set ANTHROPIC_API_KEY or install Claude Code (code.visualstudio.com/download).\n')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "client-handover",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
4
4
  "description": "AI-powered handover document generator for frontend developers handing off client websites",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -16,10 +16,12 @@
16
16
  "deploy.js",
17
17
  "credentials.js",
18
18
  "license.js",
19
+ "postinstall.js",
19
20
  "README.md"
20
21
  ],
21
22
  "scripts": {
22
- "test": "node test.js"
23
+ "test": "node test.js",
24
+ "postinstall": "node postinstall.js"
23
25
  },
24
26
  "keywords": [
25
27
  "handover",
package/postinstall.js ADDED
@@ -0,0 +1,64 @@
1
+ #!/usr/bin/env node
2
+
3
+ import readline from 'readline'
4
+ import fs from 'fs'
5
+ import path from 'path'
6
+ import os from 'os'
7
+
8
+ const configDir = path.join(os.homedir(), '.handover')
9
+ const configPath = path.join(configDir, 'config.json')
10
+ const claudeCredsPath = path.join(os.homedir(), '.claude', '.credentials.json')
11
+
12
+ function alreadyConfigured() {
13
+ if (process.env.ANTHROPIC_API_KEY) return true
14
+
15
+ if (fs.existsSync(configPath)) {
16
+ try {
17
+ const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
18
+ if (config?.apiKey) return true
19
+ } catch {}
20
+ }
21
+
22
+ if (fs.existsSync(claudeCredsPath)) {
23
+ try {
24
+ const creds = JSON.parse(fs.readFileSync(claudeCredsPath, 'utf-8'))
25
+ const token = creds?.claudeAiOauth?.accessToken
26
+ const expiresAt = creds?.claudeAiOauth?.expiresAt
27
+ if (token && (!expiresAt || expiresAt > Date.now())) return true
28
+ } catch {}
29
+ }
30
+
31
+ return false
32
+ }
33
+
34
+ function saveKey(key) {
35
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true })
36
+ fs.writeFileSync(configPath, JSON.stringify({ apiKey: key }, null, 2), 'utf-8')
37
+ }
38
+
39
+ // Skip if already set up or not in an interactive terminal
40
+ if (alreadyConfigured() || !process.stdin.isTTY) {
41
+ process.exit(0)
42
+ }
43
+
44
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
45
+
46
+ console.log('\n──────────────────────────────────────────')
47
+ console.log(' client-handover setup')
48
+ console.log('──────────────────────────────────────────')
49
+ console.log(' To generate documents, you need an Anthropic API key.')
50
+ console.log(' Get one free at: https://console.anthropic.com\n')
51
+
52
+ rl.question(' Enter your Anthropic API key (or press Enter to skip): ', (answer) => {
53
+ rl.close()
54
+ const key = answer.trim()
55
+
56
+ if (!key) {
57
+ console.log('\n Skipped. Run "handover key <your-api-key>" at any time to set it.\n')
58
+ process.exit(0)
59
+ }
60
+
61
+ saveKey(key)
62
+ console.log('\n✅ API key saved. Run "handover handover" to get started.\n')
63
+ process.exit(0)
64
+ })