client-handover 1.0.5 → 1.1.0

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
@@ -200,6 +200,17 @@ client-handover/
200
200
 
201
201
  ## Changelog
202
202
 
203
+ ### 1.1.0
204
+ - Complete CLI redesign: all section commands replaced with a single `handover /create` command
205
+ - Now generates two separate documents per run — a technical handover (for the incoming developer) and a non-technical client guide (for the business owner)
206
+ - First-run developer info prompt — saves your name, company, email, and phone to config so every document is personalised
207
+ - CSS colour detection — automatically extracts hex colours and CSS custom properties from `.css`, `.scss`, `.less` files and Tailwind config
208
+
209
+ ### 1.0.6
210
+ - Auto-scans your actual project files on every run — reads package.json, config files, env variable keys, deploy configs, folder structure, and more
211
+ - Generated documents are now tailored to your real project, not generic templates
212
+ - Extra notes file still supported as optional additional context
213
+
203
214
  ### 1.0.5
204
215
  - Interactive API key setup prompt on install — no manual config needed
205
216
  - Added `handover key <api-key>` command to save key at any time
package/cli.js CHANGED
@@ -1,72 +1,103 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { setup } from './setup.js'
4
- import { deploy } from './deploy.js'
5
- import { credentials } from './credentials.js'
6
- import { handover } from './handover.js'
7
- import { license } from './license.js'
8
- import { generateDoc, saveApiKey } from './generator.js'
3
+ import { generateDoc, loadDeveloperInfo, saveApiKey } from './generator.js'
4
+ import { technicalHandoverPrompt, nonTechnicalHandoverPrompt } from './prompts.js'
5
+ import { scanProject } from './scanner.js'
9
6
  import chalk from 'chalk'
7
+ import readline from 'readline'
10
8
  import fs from 'fs'
11
9
  import path from 'path'
12
-
13
- const COMMANDS = {
14
- 'setup': { fn: setup, label: 'Project Setup & Dependencies' },
15
- 'deploy': { fn: deploy, label: 'Deployment & Hosting' },
16
- 'credentials': { fn: credentials, label: 'Credentials & Access' },
17
- 'handover': { fn: handover, label: 'Full Handover Document' },
18
- 'license': { fn: license, label: 'Licensing & Attribution' },
19
- }
10
+ import os from 'os'
20
11
 
21
12
  function normalizeCommand(cmd) {
22
- // Git Bash converts /handover → C:\Program Files\Git\handover before Node sees it
23
- // path.basename extracts just the last segment regardless of what form it arrives in
24
13
  return path.basename(cmd).replace(/^\/+/, '')
25
14
  }
26
15
 
27
16
  function printHelp() {
28
- console.log(chalk.bold('\n🚀 handover-cliFrontend Website Handover - by Scott AK (sabrkei)\n'))
17
+ console.log(chalk.bold('\n handover — Website Handover Document Generator\n'))
29
18
  console.log(chalk.dim('Usage:'))
30
- console.log(' handover <command> [project-info-file] [output-name]\n')
31
- console.log(chalk.dim('Commands:'))
32
- Object.entries(COMMANDS).forEach(([cmd, { label }]) => {
33
- console.log(` ${chalk.cyan(cmd.padEnd(16))} ${label}`)
34
- })
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)`)
37
- console.log('\n' + chalk.dim('Examples:'))
38
- console.log(' handover handover # Full doc with placeholders')
39
- console.log(' handover setup project-info.txt # Setup section using your notes')
40
- console.log(' handover handover project-info.txt my-client # Full doc, custom filename')
41
- console.log(' handover all project-info.txt acme-client # Every section in output/acme-client/')
19
+ console.log(' handover /create Generate technical & non-technical handover documents')
20
+ console.log(' handover key <key> Save your Anthropic API key\n')
21
+ console.log(chalk.dim('Example:'))
22
+ console.log(' cd my-client-project')
23
+ console.log(' handover /create\n')
24
+ }
25
+
26
+ function ask(rl, question) {
27
+ return new Promise(resolve => rl.question(question, answer => resolve(answer.trim())))
28
+ }
29
+
30
+ async function ensureDeveloperInfo() {
31
+ const configDir = path.join(os.homedir(), '.handover')
32
+ const configPath = path.join(configDir, 'config.json')
33
+
34
+ let config = {}
35
+ try {
36
+ if (fs.existsSync(configPath)) config = JSON.parse(fs.readFileSync(configPath, 'utf-8'))
37
+ } catch {}
38
+
39
+ if (config.developerName) {
40
+ return {
41
+ name: config.developerName,
42
+ company: config.developerCompany || '',
43
+ email: config.developerEmail || '',
44
+ phone: config.developerPhone || '',
45
+ }
46
+ }
47
+
48
+ console.log(chalk.bold('\n Your developer details will appear in the handover documents.\n'))
49
+
50
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout })
51
+ const name = await ask(rl, ' Your full name: ')
52
+ const company = await ask(rl, ' Your company name (or press Enter if not applicable): ')
53
+ const email = await ask(rl, ' Your email address: ')
54
+ const phone = await ask(rl, ' Your phone number (optional): ')
55
+ rl.close()
56
+
57
+ if (name) config.developerName = name
58
+ if (company) config.developerCompany = company
59
+ if (email) config.developerEmail = email
60
+ if (phone) config.developerPhone = phone
61
+
62
+ if (!fs.existsSync(configDir)) fs.mkdirSync(configDir, { recursive: true })
63
+ fs.writeFileSync(configPath, JSON.stringify(config, null, 2), 'utf-8')
42
64
  console.log()
65
+
66
+ return { name: name || '', company: company || '', email: email || '', phone: phone || '' }
43
67
  }
44
68
 
45
- async function runAll(projectInfo, folderName) {
46
- const sections = [
47
- { key: 'handover', fn: handover, label: 'Full Handover Document' },
48
- { key: 'setup', fn: setup, label: 'Project Setup & Dependencies' },
49
- { key: 'deploy', fn: deploy, label: 'Deployment & Hosting' },
50
- { key: 'credentials', fn: credentials, label: 'Credentials & Access' },
51
- { key: 'license', fn: license, label: 'Licensing & Attribution' },
52
- ]
69
+ async function runCreate() {
70
+ const developerInfo = await ensureDeveloperInfo()
53
71
 
54
- const outputDir = `./output/${folderName}`
72
+ console.log(chalk.dim(' Scanning project files...'))
73
+ const projectInfo = scanProject(process.cwd())
55
74
 
56
- console.log(chalk.bold(`\n📁 Generating all sections into: ${outputDir}\n`))
75
+ const techDir = './technical-handover'
76
+ const clientDir = './handover'
57
77
 
58
- for (const section of sections) {
59
- console.log(chalk.bold(`📝 Generating: ${section.label}`))
60
- const prompt = section.fn(projectInfo)
61
- await generateDoc(prompt, section.key, outputDir)
62
- console.log()
63
- }
78
+ console.log(chalk.bold('\n Generating Technical Handover Document...'))
79
+ const techPrompt = technicalHandoverPrompt(projectInfo, developerInfo)
80
+ await generateDoc(techPrompt, 'technical-handover', techDir)
81
+
82
+ console.log(chalk.bold('\n Generating Client Handover Document...'))
83
+ const nonTechPrompt = nonTechnicalHandoverPrompt(projectInfo, developerInfo)
84
+ await generateDoc(nonTechPrompt, 'handover', clientDir)
64
85
 
65
- console.log(chalk.green.bold(`✅ All sections saved to ${outputDir}\n`))
86
+ console.log(chalk.green.bold('\n Handover documents created successfully!\n'))
87
+ console.log(` ${chalk.cyan('./technical-handover/')}`)
88
+ console.log(` technical-handover.md`)
89
+ console.log(` technical-handover.txt`)
90
+ console.log(` technical-handover.docx`)
91
+ console.log()
92
+ console.log(` ${chalk.cyan('./handover/')}`)
93
+ console.log(` handover.md`)
94
+ console.log(` handover.txt`)
95
+ console.log(` handover.docx`)
96
+ console.log()
66
97
  }
67
98
 
68
99
  async function main() {
69
- const [,, rawCommand, infoFile, outputName] = process.argv
100
+ const [,, rawCommand, secondArg] = process.argv
70
101
 
71
102
  if (!rawCommand || rawCommand === '--help' || rawCommand === '-h') {
72
103
  printHelp()
@@ -76,62 +107,28 @@ async function main() {
76
107
  const command = normalizeCommand(rawCommand)
77
108
 
78
109
  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'))
110
+ if (!secondArg) {
111
+ console.error(chalk.red('\n ❌ Usage: handover key <your-api-key>\n'))
82
112
  process.exit(1)
83
113
  }
84
- saveApiKey(key)
85
- console.log(chalk.green('\n✅ API key saved. You\'re all set run any handover command.\n'))
114
+ saveApiKey(secondArg)
115
+ console.log(chalk.green('\n ✅ API key saved. Run "handover /create" to get started.\n'))
86
116
  process.exit(0)
87
117
  }
88
118
 
89
- // Read optional project info file
90
- let projectInfo = ''
91
- if (infoFile) {
92
- if (!fs.existsSync(infoFile)) {
93
- console.error(chalk.red(`\n❌ File not found: ${infoFile}\n`))
94
- process.exit(1)
95
- }
96
- projectInfo = fs.readFileSync(infoFile, 'utf-8')
97
- console.log(chalk.green(`\n📄 Loaded project info from: ${infoFile}`))
98
- }
99
-
100
- if (command === 'all') {
101
- const folderName = outputName || 'all'
102
- try {
103
- await runAll(projectInfo, folderName)
104
- } catch (err) {
105
- if (err.status === 401) {
106
- console.error(chalk.red('\n❌ Authentication failed. Set ANTHROPIC_API_KEY or install Claude Code.\n'))
107
- } else {
108
- console.error(chalk.red(`\n❌ Error: ${err.message}\n`))
109
- }
110
- process.exit(1)
111
- }
112
- return
113
- }
114
-
115
- const entry = COMMANDS[command]
116
- if (!entry) {
117
- console.error(chalk.red(`\n❌ Unknown command: ${rawCommand}\n`))
119
+ if (command !== 'create') {
120
+ console.error(chalk.red(`\n Unknown command: ${rawCommand}\n`))
118
121
  printHelp()
119
122
  process.exit(1)
120
123
  }
121
124
 
122
- const docName = outputName || command
123
- const prompt = entry.fn(projectInfo)
124
-
125
- console.log(chalk.bold(`\n📝 Generating: ${entry.label}`))
126
- console.log(chalk.dim(` Output: ./output/${docName}.{md,txt,html}\n`))
127
-
128
125
  try {
129
- await generateDoc(prompt, docName, './output')
126
+ await runCreate()
130
127
  } catch (err) {
131
128
  if (err.status === 401) {
132
- console.error(chalk.red('\n❌ Authentication failed. Set ANTHROPIC_API_KEY or install Claude Code.\n'))
129
+ console.error(chalk.red('\n ❌ Authentication failed. Run "handover key <your-api-key>" to set your API key.\n'))
133
130
  } else {
134
- console.error(chalk.red(`\n❌ Error: ${err.message}\n`))
131
+ console.error(chalk.red(`\n ❌ Error: ${err.message}\n`))
135
132
  }
136
133
  process.exit(1)
137
134
  }