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 +24 -1
- package/cli.js +13 -1
- package/generator.js +18 -0
- package/package.json +4 -2
- package/postinstall.js +64 -0
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
|
-
-
|
|
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.
|
|
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
|
+
})
|