culater 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
@@ -1,16 +1,26 @@
1
1
  # culater
2
2
 
3
- Remote terminal for Claude Code - c(See) you later!
3
+ **Your AI terminal, anywhere.**
4
4
 
5
- Access Claude Code from your phone via a secure tunnel.
5
+ `culater` gives you fast phone access to your local Claude Code shell through a secure Cloudflare tunnel, so you can check output, unblock an agent, and keep moving when you're away from your desk.
6
6
 
7
- ## Quick Start
7
+ ## Demo
8
8
 
9
- ```bash
10
- npx culater mypassword
11
- ```
9
+ <p align="center">
10
+ <img src="assets/culater-demo.gif" alt="culater demo" width="720">
11
+ </p>
12
+
13
+ ## Why culater
14
+
15
+ - Agent-first remote terminal workflow from any mobile browser
16
+ - Session survives refreshes and temporary network drops
17
+ - Project-aware startup (recent folders remembered in `~/.culater/config.json`)
18
+ - Manual `AI` launch when you want Claude, no forced auto-start
19
+ - One command to start, no account setup
20
+
21
+ ## Quick Start
12
22
 
13
- ## Requirements
23
+ ### 1) Install requirements
14
24
 
15
25
  - Node.js 18+
16
26
  - [cloudflared](https://developers.cloudflare.com/cloudflare-one/connections/connect-apps/install-and-setup/installation/)
@@ -23,10 +33,39 @@ brew install cloudflared
23
33
  sudo apt install cloudflared
24
34
  ```
25
35
 
26
- ## Options
36
+ ### 2) Start culater
27
37
 
38
+ ```bash
39
+ npx culater mypassword
28
40
  ```
29
- -n, --ntfy <topic> ntfy.sh topic for push notifications (saved for next time)
41
+
42
+ ### 3) Open it on your phone
43
+
44
+ - Scan the terminal QR code
45
+ - Enter the password
46
+ - Start shell (or auto-start if no previous project history exists)
47
+
48
+ ## How It Works
49
+
50
+ 1. `culater` starts a local PTY shell.
51
+ 2. It creates a temporary Cloudflare tunnel URL.
52
+ 3. Your phone connects to the web terminal and controls that shell in real time.
53
+
54
+ ## Features
55
+
56
+ - Mobile-optimized terminal UI
57
+ - Touch scrolling with momentum
58
+ - Quick action buttons (`/`, `Esc`, `Enter`, cursor pad)
59
+ - Keyboard-aware controls that stay above the fold
60
+ - Auto-reconnect and persistent session resume
61
+ - Manual `AI` button to run Claude on demand
62
+ - Password gate before terminal access
63
+ - Optional ntfy push notifications for tunnel URL
64
+
65
+ ## CLI Options
66
+
67
+ ```txt
68
+ -n, --ntfy <topic> ntfy.sh topic for push notifications (saved)
30
69
  -d, --dir <path> Working directory (default: current)
31
70
  -h, --help Show help
32
71
  ```
@@ -37,27 +76,17 @@ sudo apt install cloudflared
37
76
  # Start with password
38
77
  npx culater mysecret
39
78
 
40
- # With push notifications (saved to /tmp/culater.json)
41
- npx culater mysecret -n my-ntfy-topic
42
-
43
- # Subsequent runs use saved ntfy topic automatically
44
- npx culater mysecret
45
-
46
- # Specific directory
79
+ # Use a specific directory
47
80
  npx culater mysecret -d ~/projects/myapp
81
+
82
+ # Enable ntfy notifications (saved for later runs)
83
+ npx culater mysecret -n my-ntfy-topic
48
84
  ```
49
85
 
50
- ## Features
86
+ ## Notes
51
87
 
52
- - Mobile-optimized terminal UI
53
- - Touch scrolling with momentum
54
- - Quick action buttons (/, Esc, ↓, Enter)
55
- - Auto-reconnect on disconnect
56
- - Keyboard-aware button positioning
57
- - Streaming indicator
58
- - Password protection
59
- - Secure cloudflare tunnel
60
- - Push notifications via ntfy.sh (remembers your topic)
88
+ - Config is stored at `~/.culater/config.json`.
89
+ - First tunnel open can briefly show Cloudflare `1033` while edge registration finishes.
61
90
 
62
91
  ## License
63
92
 
Binary file
package/bin/culater.js CHANGED
@@ -2,8 +2,13 @@
2
2
 
3
3
  const { execSync } = require('child_process');
4
4
  const fs = require('fs');
5
+ const os = require('os');
6
+ const path = require('path');
5
7
 
6
- const CONFIG_FILE = '/tmp/culater.json';
8
+ const CONFIG_DIR = path.join(os.homedir(), '.culater');
9
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
10
+ const LEGACY_CONFIG_FILE = '/tmp/culater.json';
11
+ const MAX_RECENT_DIRS = 12;
7
12
 
8
13
  // Check for cloudflared
9
14
  try {
@@ -19,13 +24,18 @@ function loadConfig() {
19
24
  try {
20
25
  return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
21
26
  } catch {
22
- return {};
27
+ try {
28
+ return JSON.parse(fs.readFileSync(LEGACY_CONFIG_FILE, 'utf8'));
29
+ } catch {
30
+ return {};
31
+ }
23
32
  }
24
33
  }
25
34
 
26
35
  // Save config
27
36
  function saveConfig(config) {
28
37
  try {
38
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
29
39
  fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
30
40
  } catch {}
31
41
  }
@@ -63,20 +73,31 @@ if (!password) {
63
73
  process.exit(1);
64
74
  }
65
75
 
76
+ workDir = path.resolve(workDir);
77
+
66
78
  // Load config and use saved ntfy if not provided
67
79
  const config = loadConfig();
68
80
  if (ntfyTopic) {
69
81
  // Save new ntfy topic
70
82
  config.ntfyTopic = ntfyTopic;
71
- saveConfig(config);
72
83
  } else if (config.ntfyTopic) {
73
84
  // Use saved ntfy topic
74
85
  ntfyTopic = config.ntfyTopic;
75
86
  }
76
87
 
88
+ const recentDirs = Array.isArray(config.recentDirs) ? config.recentDirs : [];
89
+ const normalizedRecent = recentDirs
90
+ .filter(dir => typeof dir === 'string' && dir.trim())
91
+ .map(dir => path.resolve(dir));
92
+ const previousRecentDirs = Array.from(new Set(normalizedRecent)).slice(0, MAX_RECENT_DIRS);
93
+ const nextRecentDirs = [workDir, ...previousRecentDirs.filter(dir => dir !== workDir)].slice(0, MAX_RECENT_DIRS);
94
+ config.recentDirs = nextRecentDirs;
95
+ saveConfig(config);
96
+
77
97
  // Set env and run server
78
98
  process.env.REMOTE_PASSWORD = password;
79
99
  process.env.NTFY_TOPIC = ntfyTopic || '';
80
100
  process.env.WORK_DIR = workDir;
101
+ process.env.RECENT_DIRS = JSON.stringify(previousRecentDirs);
81
102
 
82
103
  require('../lib/server.js');