codekin 0.3.1 → 0.3.4

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
@@ -14,7 +14,7 @@ Web UI for Claude Code sessions — multi-session support, WebSocket streaming,
14
14
  **One-liner:**
15
15
 
16
16
  ```bash
17
- curl -fsSL https://raw.githubusercontent.com/Multiplier-Labs/codekin/main/install.sh | bash
17
+ curl -fsSL codekin.ai/install.sh | bash
18
18
  ```
19
19
 
20
20
  This will:
@@ -31,11 +31,13 @@ Open the printed URL in your browser, enter your Codekin Web token when prompted
31
31
 
32
32
  ```bash
33
33
  codekin token # Print your access URL at any time
34
+ codekin config # Update API keys and settings
34
35
  codekin service status # Check whether the service is running
35
36
  codekin service install # (Re-)install the background service
36
37
  codekin service uninstall # Remove the background service
37
38
  codekin start # Run in foreground (for debugging)
38
39
  codekin setup --regenerate # Generate a new auth token
40
+ codekin uninstall # Remove Codekin entirely
39
41
  ```
40
42
 
41
43
  ## Features
@@ -51,7 +53,7 @@ codekin setup --regenerate # Generate a new auth token
51
53
  Re-run the install script — it's idempotent and will upgrade to the latest version:
52
54
 
53
55
  ```bash
54
- curl -fsSL https://raw.githubusercontent.com/Multiplier-Labs/codekin/main/install.sh | bash
56
+ curl -fsSL codekin.ai/install.sh | bash
55
57
  ```
56
58
 
57
59
  Or upgrade manually:
@@ -64,11 +66,11 @@ codekin service install
64
66
  ## Uninstall
65
67
 
66
68
  ```bash
67
- codekin service uninstall
68
- npm uninstall -g codekin
69
- rm -rf ~/.config/codekin ~/.codekin
69
+ codekin uninstall
70
70
  ```
71
71
 
72
+ This removes the background service, config files, and the npm package.
73
+
72
74
  ## Configuration
73
75
 
74
76
  All configuration lives in `~/.config/codekin/env`. Edit this file to override defaults, then restart the service with `codekin service install`.
package/bin/codekin.mjs CHANGED
@@ -8,11 +8,13 @@
8
8
  * codekin service install Install + start background service
9
9
  * codekin service uninstall Remove background service
10
10
  * codekin service status Show service status
11
+ * codekin config Update API keys and settings
11
12
  * codekin token Print access URL with auth token
13
+ * codekin uninstall Remove Codekin entirely
12
14
  */
13
15
 
14
16
  import { execSync, execFileSync, spawnSync } from 'child_process'
15
- import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync } from 'fs'
17
+ import { existsSync, mkdirSync, readFileSync, writeFileSync, chmodSync, createReadStream, rmSync } from 'fs'
16
18
  import { homedir, platform } from 'os'
17
19
  import { join, dirname } from 'path'
18
20
  import { fileURLToPath } from 'url'
@@ -62,13 +64,29 @@ function getPort() {
62
64
  return parseInt(env.PORT || String(DEFAULT_PORT), 10)
63
65
  }
64
66
 
67
+ function openTtyInput() {
68
+ // When piped (curl | bash), stdin is not a TTY — open /dev/tty directly
69
+ if (process.stdin.isTTY) return { input: process.stdin, cleanup: null }
70
+ try {
71
+ const tty = createReadStream('/dev/tty', { encoding: 'utf-8' })
72
+ return { input: tty, cleanup: () => tty.destroy() }
73
+ } catch {
74
+ // No TTY available (CI, headless) — fall back to stdin
75
+ return { input: process.stdin, cleanup: null }
76
+ }
77
+ }
78
+
65
79
  function prompt(question) {
66
- const rl = createInterface({ input: process.stdin, output: process.stdout })
80
+ const { input, cleanup } = openTtyInput()
81
+ const rl = createInterface({ input, output: process.stdout })
67
82
  return new Promise(resolve => {
68
83
  rl.question(question, answer => {
69
84
  rl.close()
85
+ if (cleanup) cleanup()
70
86
  resolve(answer.trim())
71
87
  })
88
+ // If input closes without an answer (non-interactive), resolve empty
89
+ rl.on('close', () => resolve(''))
72
90
  })
73
91
  }
74
92
 
@@ -113,7 +131,7 @@ async function cmdSetup({ regenerate = false } = {}) {
113
131
  if (existingToken && !regenerate) {
114
132
  console.log('Auth token: (already exists, use --regenerate to replace)')
115
133
  } else {
116
- const token = randomBytes(32).toString('hex')
134
+ const token = randomBytes(16).toString('base64url')
117
135
  writeFileSync(TOKEN_FILE, token + '\n', { mode: 0o600 })
118
136
  console.log('Auth token: generated')
119
137
  }
@@ -356,6 +374,45 @@ function serviceDispatch(action) {
356
374
  }
357
375
  }
358
376
 
377
+ // ---------------------------------------------------------------------------
378
+ // Uninstall
379
+ // ---------------------------------------------------------------------------
380
+
381
+ async function cmdUninstall() {
382
+ const answer = await prompt('This will remove Codekin entirely (service, config, npm package). Continue? [y/N] ')
383
+ if (answer.toLowerCase() !== 'y') {
384
+ console.log('Aborted.')
385
+ return
386
+ }
387
+
388
+ // 1. Stop and remove background service
389
+ console.log('\nRemoving background service...')
390
+ try {
391
+ serviceDispatch('uninstall')
392
+ } catch {
393
+ // Service may not be installed — that's fine
394
+ }
395
+
396
+ // 2. Remove config directories
397
+ const configDir = CONFIG_DIR
398
+ const codekinDir = join(homedir(), '.codekin')
399
+
400
+ if (existsSync(configDir)) {
401
+ rmSync(configDir, { recursive: true, force: true })
402
+ console.log(`Removed ${configDir}`)
403
+ }
404
+ if (existsSync(codekinDir)) {
405
+ rmSync(codekinDir, { recursive: true, force: true })
406
+ console.log(`Removed ${codekinDir}`)
407
+ }
408
+
409
+ // 3. Uninstall npm package
410
+ console.log('\nUninstalling codekin npm package...')
411
+ spawnSync('npm', ['uninstall', '-g', 'codekin'], { stdio: 'inherit' })
412
+
413
+ console.log('\nCodekin has been completely removed.')
414
+ }
415
+
359
416
  // ---------------------------------------------------------------------------
360
417
  // Entry point
361
418
  // ---------------------------------------------------------------------------
@@ -367,8 +424,12 @@ if (cmd === 'start') {
367
424
  cmdStart()
368
425
  } else if (cmd === 'setup') {
369
426
  await cmdSetup({ regenerate: args.includes('--regenerate') })
427
+ } else if (cmd === 'config') {
428
+ await cmdSetup()
370
429
  } else if (cmd === 'token') {
371
430
  cmdToken()
431
+ } else if (cmd === 'uninstall') {
432
+ await cmdUninstall()
372
433
  } else if (cmd === 'service') {
373
434
  const action = args[1]
374
435
  if (!['install', 'uninstall', 'status'].includes(action)) {
@@ -383,9 +444,11 @@ Usage:
383
444
  codekin start Run server in foreground
384
445
  codekin setup First-time setup wizard
385
446
  codekin setup --regenerate Regenerate auth token
447
+ codekin config Update API keys and settings
386
448
  codekin service install Install + start background service
387
449
  codekin service uninstall Remove background service
388
450
  codekin service status Show service status
389
451
  codekin token Print access URL with auth token
452
+ codekin uninstall Remove Codekin entirely
390
453
  `)
391
454
  }