claude-threads 0.12.1 → 0.13.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/CHANGELOG.md +21 -0
- package/README.md +66 -11
- package/dist/index.js +9 -3
- package/dist/onboarding.d.ts +1 -1
- package/dist/onboarding.js +96 -19
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,27 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.13.0] - 2025-12-29
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
- **`--setup` flag** - Re-run interactive setup wizard to reconfigure settings
|
|
14
|
+
- Existing .env values are used as defaults (press Enter to keep)
|
|
15
|
+
- Token field allows keeping existing token without re-entering
|
|
16
|
+
- New settings added since initial setup are presented with built-in defaults
|
|
17
|
+
- Config saved back to original location
|
|
18
|
+
- **Chrome and worktree settings in onboarding** - New setup prompts for:
|
|
19
|
+
- Chrome integration (yes/no)
|
|
20
|
+
- Git worktree mode (prompt/off/require)
|
|
21
|
+
|
|
22
|
+
### Changed
|
|
23
|
+
- **Improved README** - New tagline and improved intro section
|
|
24
|
+
- **Worktree documentation** - Added comprehensive Git Worktrees section to README
|
|
25
|
+
- **Updated CLI options** - Added `--chrome`, `--no-chrome`, `--worktree-mode`, `--setup` to README
|
|
26
|
+
|
|
27
|
+
### Fixed
|
|
28
|
+
- **Warning icon alignment** - Fixed spacing of ⚠️ icon in CLI startup output
|
|
29
|
+
- **WORKTREE_MODE documentation** - Fixed incorrect values in README (was `always`/`never`, now correctly `off`/`prompt`/`require`)
|
|
30
|
+
|
|
10
31
|
## [0.12.1] - 2025-12-29
|
|
11
32
|
|
|
12
33
|
### Fixed
|
package/README.md
CHANGED
|
@@ -9,7 +9,9 @@
|
|
|
9
9
|
[](https://www.npmjs.com/package/claude-threads)
|
|
10
10
|
[](https://opensource.org/licenses/MIT)
|
|
11
11
|
|
|
12
|
-
|
|
12
|
+
**Bring Claude Code to your team.** Run Claude Code on your machine, share it live in Mattermost. Colleagues can watch, collaborate, and run their own sessions—all from chat.
|
|
13
|
+
|
|
14
|
+
> 💡 *Think of it as screen-sharing for AI pair programming, but everyone can type.*
|
|
13
15
|
|
|
14
16
|
## Features
|
|
15
17
|
|
|
@@ -101,16 +103,20 @@ In Mattermost, mention the bot:
|
|
|
101
103
|
claude-threads [options]
|
|
102
104
|
|
|
103
105
|
Options:
|
|
104
|
-
--url <url>
|
|
105
|
-
--token <token>
|
|
106
|
-
--channel <id>
|
|
107
|
-
--bot-name <name>
|
|
108
|
-
--allowed-users <list>
|
|
109
|
-
--skip-permissions
|
|
110
|
-
--no-skip-permissions
|
|
111
|
-
--
|
|
112
|
-
--
|
|
113
|
-
--
|
|
106
|
+
--url <url> Mattermost server URL
|
|
107
|
+
--token <token> Bot token
|
|
108
|
+
--channel <id> Channel ID
|
|
109
|
+
--bot-name <name> Bot mention name (default: claude-code)
|
|
110
|
+
--allowed-users <list> Comma-separated allowed usernames
|
|
111
|
+
--skip-permissions Skip permission prompts (auto-approve)
|
|
112
|
+
--no-skip-permissions Enable permission prompts (override env)
|
|
113
|
+
--chrome Enable Chrome integration
|
|
114
|
+
--no-chrome Disable Chrome integration
|
|
115
|
+
--worktree-mode <mode> Git worktree mode: off, prompt, require
|
|
116
|
+
--setup Re-run setup wizard (reconfigure settings)
|
|
117
|
+
--debug Enable debug logging
|
|
118
|
+
--version Show version
|
|
119
|
+
--help Show help
|
|
114
120
|
```
|
|
115
121
|
|
|
116
122
|
CLI options override environment variables.
|
|
@@ -123,11 +129,17 @@ Type `!help` in any session thread to see available commands:
|
|
|
123
129
|
|:--------|:------------|
|
|
124
130
|
| `!help` | Show available commands |
|
|
125
131
|
| `!release-notes` | Show release notes for current version |
|
|
132
|
+
| `!context` | Show context usage (tokens used/remaining) |
|
|
133
|
+
| `!cost` | Show token usage and cost for this session |
|
|
134
|
+
| `!compact` | Compress context to free up space |
|
|
126
135
|
| `!cd <path>` | Change working directory (restarts Claude) |
|
|
136
|
+
| `!worktree <branch>` | Create and switch to a git worktree |
|
|
127
137
|
| `!invite @user` | Invite a user to this session |
|
|
128
138
|
| `!kick @user` | Remove an invited user |
|
|
129
139
|
| `!permissions interactive` | Enable interactive permissions |
|
|
140
|
+
| `!escape` | Interrupt current task (keeps session active) |
|
|
130
141
|
| `!stop` | Stop this session |
|
|
142
|
+
| `!kill` | Emergency shutdown (kills ALL sessions, exits bot) |
|
|
131
143
|
|
|
132
144
|
> **Note:** Commands use `!` prefix instead of `/` to avoid conflicts with Mattermost's slash commands.
|
|
133
145
|
|
|
@@ -176,6 +188,47 @@ If the bot is running with `--skip-permissions` (auto mode), you can enable inte
|
|
|
176
188
|
|
|
177
189
|
This allows collaboration by requiring approval for Claude's actions. Note: you can only downgrade (auto → interactive), not upgrade - this ensures security.
|
|
178
190
|
|
|
191
|
+
## Git Worktrees
|
|
192
|
+
|
|
193
|
+
When working on a task that requires code changes, Claude can work in an isolated git worktree. This keeps your main branch clean while Claude works on a feature branch in a separate directory.
|
|
194
|
+
|
|
195
|
+
### Starting a Session with a Worktree
|
|
196
|
+
|
|
197
|
+
Specify a branch when starting:
|
|
198
|
+
|
|
199
|
+
```
|
|
200
|
+
@claude-code on branch feature/add-auth implement user authentication
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
Or use the worktree command:
|
|
204
|
+
|
|
205
|
+
```
|
|
206
|
+
@claude-code !worktree feature/add-auth implement user authentication
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Worktree Commands
|
|
210
|
+
|
|
211
|
+
| Command | Description |
|
|
212
|
+
|:--------|:------------|
|
|
213
|
+
| `!worktree <branch>` | Create worktree and switch to it |
|
|
214
|
+
| `!worktree list` | List all worktrees for this repo |
|
|
215
|
+
| `!worktree switch <branch>` | Switch to an existing worktree |
|
|
216
|
+
| `!worktree remove <branch>` | Remove a worktree |
|
|
217
|
+
| `!worktree off` | Disable worktree prompts for this session |
|
|
218
|
+
|
|
219
|
+
### How It Works
|
|
220
|
+
|
|
221
|
+
1. Creates a new worktree at `../<repo>-worktrees/<branch>/`
|
|
222
|
+
2. Creates or checks out the specified branch
|
|
223
|
+
3. Claude works in the worktree directory
|
|
224
|
+
4. Your main working directory stays untouched
|
|
225
|
+
|
|
226
|
+
### Environment Variable
|
|
227
|
+
|
|
228
|
+
| Variable | Description |
|
|
229
|
+
|----------|-------------|
|
|
230
|
+
| `WORKTREE_MODE` | `prompt` (ask on new sessions), `require` (always require branch), `off` (disable) |
|
|
231
|
+
|
|
179
232
|
## Interactive Features
|
|
180
233
|
|
|
181
234
|
### Permission Approval
|
|
@@ -258,6 +311,8 @@ ALLOWED_USERS=alice,bob,carol
|
|
|
258
311
|
| `MATTERMOST_BOT_NAME` | Mention name (default: `claude-code`) |
|
|
259
312
|
| `ALLOWED_USERS` | Comma-separated usernames |
|
|
260
313
|
| `SKIP_PERMISSIONS` | `true` to auto-approve actions |
|
|
314
|
+
| `CLAUDE_CHROME` | `true` to enable Chrome integration |
|
|
315
|
+
| `WORKTREE_MODE` | `off`, `prompt`, or `require` (default: `prompt`) |
|
|
261
316
|
| `MAX_SESSIONS` | Max concurrent sessions (default: `5`) |
|
|
262
317
|
| `SESSION_TIMEOUT_MS` | Idle timeout in ms (default: `1800000` = 30 min) |
|
|
263
318
|
| `NO_UPDATE_NOTIFIER` | Set to `1` to disable update checks |
|
package/dist/index.js
CHANGED
|
@@ -29,6 +29,8 @@ program
|
|
|
29
29
|
.option('--no-skip-permissions', 'Enable interactive permission prompts (override env)')
|
|
30
30
|
.option('--chrome', 'Enable Claude in Chrome integration')
|
|
31
31
|
.option('--no-chrome', 'Disable Claude in Chrome integration')
|
|
32
|
+
.option('--worktree-mode <mode>', 'Git worktree mode: off, prompt, require (default: prompt)')
|
|
33
|
+
.option('--setup', 'Run interactive setup wizard (reconfigure existing settings)')
|
|
32
34
|
.option('--debug', 'Enable debug logging')
|
|
33
35
|
.parse();
|
|
34
36
|
const opts = program.opts();
|
|
@@ -52,10 +54,14 @@ async function main() {
|
|
|
52
54
|
allowedUsers: opts.allowedUsers,
|
|
53
55
|
skipPermissions: opts.skipPermissions,
|
|
54
56
|
chrome: opts.chrome,
|
|
57
|
+
worktreeMode: opts.worktreeMode,
|
|
55
58
|
};
|
|
56
59
|
// Check if we need onboarding
|
|
57
|
-
if (
|
|
58
|
-
await runOnboarding();
|
|
60
|
+
if (opts.setup) {
|
|
61
|
+
await runOnboarding(true); // reconfigure mode
|
|
62
|
+
}
|
|
63
|
+
else if (!configExists() && !hasRequiredCliArgs(opts)) {
|
|
64
|
+
await runOnboarding(false); // first-time mode
|
|
59
65
|
}
|
|
60
66
|
const workingDir = process.cwd();
|
|
61
67
|
const config = loadConfig(cliArgs);
|
|
@@ -68,7 +74,7 @@ async function main() {
|
|
|
68
74
|
console.log(` 💬 ${cyan('@' + config.mattermost.botName)}`);
|
|
69
75
|
console.log(` 🌐 ${dim(config.mattermost.url)}`);
|
|
70
76
|
if (config.skipPermissions) {
|
|
71
|
-
console.log(` ⚠️
|
|
77
|
+
console.log(` ⚠️ ${dim('Permissions disabled')}`);
|
|
72
78
|
}
|
|
73
79
|
else {
|
|
74
80
|
console.log(` 🔐 ${dim('Interactive permissions')}`);
|
package/dist/onboarding.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function runOnboarding(): Promise<void>;
|
|
1
|
+
export declare function runOnboarding(reconfigure?: boolean): Promise<void>;
|
package/dist/onboarding.js
CHANGED
|
@@ -1,16 +1,47 @@
|
|
|
1
1
|
import prompts from 'prompts';
|
|
2
|
-
import { writeFileSync, mkdirSync } from 'fs';
|
|
2
|
+
import { writeFileSync, mkdirSync, readFileSync, existsSync } from 'fs';
|
|
3
3
|
import { homedir } from 'os';
|
|
4
|
-
import { resolve } from 'path';
|
|
4
|
+
import { resolve, dirname } from 'path';
|
|
5
|
+
import { parse } from 'dotenv';
|
|
5
6
|
const bold = (s) => `\x1b[1m${s}\x1b[0m`;
|
|
6
7
|
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
7
8
|
const green = (s) => `\x1b[32m${s}\x1b[0m`;
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
// Paths to search for .env files (in order of priority)
|
|
10
|
+
const ENV_PATHS = [
|
|
11
|
+
resolve(process.cwd(), '.env'),
|
|
12
|
+
resolve(homedir(), '.config', 'claude-threads', '.env'),
|
|
13
|
+
resolve(homedir(), '.claude-threads.env'),
|
|
14
|
+
];
|
|
15
|
+
function loadExistingConfig() {
|
|
16
|
+
for (const envPath of ENV_PATHS) {
|
|
17
|
+
if (existsSync(envPath)) {
|
|
18
|
+
try {
|
|
19
|
+
const content = readFileSync(envPath, 'utf-8');
|
|
20
|
+
return { path: envPath, values: parse(content) };
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return { path: null, values: {} };
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return { path: null, values: {} };
|
|
28
|
+
}
|
|
29
|
+
export async function runOnboarding(reconfigure = false) {
|
|
30
|
+
const { path: existingPath, values: existing } = reconfigure ? loadExistingConfig() : { path: null, values: {} };
|
|
31
|
+
const hasExisting = Object.keys(existing).length > 0;
|
|
12
32
|
console.log('');
|
|
13
|
-
|
|
33
|
+
if (reconfigure && hasExisting) {
|
|
34
|
+
console.log(bold(' Reconfiguring claude-threads'));
|
|
35
|
+
console.log(dim(' ─────────────────────────────────'));
|
|
36
|
+
console.log('');
|
|
37
|
+
console.log(dim(' Press Enter to keep existing values.'));
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
console.log(bold(' Welcome to claude-threads!'));
|
|
41
|
+
console.log(dim(' ─────────────────────────────────'));
|
|
42
|
+
console.log('');
|
|
43
|
+
console.log(' No configuration found. Let\'s set things up.');
|
|
44
|
+
}
|
|
14
45
|
console.log('');
|
|
15
46
|
console.log(dim(' You\'ll need:'));
|
|
16
47
|
console.log(dim(' • A Mattermost bot account with a token'));
|
|
@@ -23,25 +54,41 @@ export async function runOnboarding() {
|
|
|
23
54
|
console.log(dim(' Setup cancelled.'));
|
|
24
55
|
process.exit(0);
|
|
25
56
|
};
|
|
57
|
+
// Helper to get worktree mode index
|
|
58
|
+
const worktreeModeIndex = (mode) => {
|
|
59
|
+
if (mode === 'off')
|
|
60
|
+
return 1;
|
|
61
|
+
if (mode === 'require')
|
|
62
|
+
return 2;
|
|
63
|
+
return 0; // default to 'prompt'
|
|
64
|
+
};
|
|
26
65
|
const response = await prompts([
|
|
27
66
|
{
|
|
28
67
|
type: 'text',
|
|
29
68
|
name: 'url',
|
|
30
69
|
message: 'Mattermost URL',
|
|
31
|
-
initial: 'https://your-mattermost-server.com',
|
|
70
|
+
initial: existing.MATTERMOST_URL || 'https://your-mattermost-server.com',
|
|
32
71
|
validate: (v) => v.startsWith('http') ? true : 'URL must start with http:// or https://',
|
|
33
72
|
},
|
|
34
73
|
{
|
|
35
74
|
type: 'password',
|
|
36
75
|
name: 'token',
|
|
37
76
|
message: 'Bot token',
|
|
38
|
-
hint:
|
|
39
|
-
|
|
77
|
+
hint: existing.MATTERMOST_TOKEN
|
|
78
|
+
? 'Enter to keep existing, or type new token'
|
|
79
|
+
: 'Create at: Integrations > Bot Accounts > Add Bot Account',
|
|
80
|
+
validate: (v) => {
|
|
81
|
+
// Allow empty if we have an existing token (user wants to keep it)
|
|
82
|
+
if (!v && existing.MATTERMOST_TOKEN)
|
|
83
|
+
return true;
|
|
84
|
+
return v.length > 0 ? true : 'Token is required';
|
|
85
|
+
},
|
|
40
86
|
},
|
|
41
87
|
{
|
|
42
88
|
type: 'text',
|
|
43
89
|
name: 'channelId',
|
|
44
90
|
message: 'Channel ID',
|
|
91
|
+
initial: existing.MATTERMOST_CHANNEL_ID || '',
|
|
45
92
|
hint: 'Click channel name > View Info > copy ID from URL',
|
|
46
93
|
validate: (v) => v.length > 0 ? true : 'Channel ID is required',
|
|
47
94
|
},
|
|
@@ -49,26 +96,48 @@ export async function runOnboarding() {
|
|
|
49
96
|
type: 'text',
|
|
50
97
|
name: 'botName',
|
|
51
98
|
message: 'Bot mention name',
|
|
52
|
-
initial: 'claude-code',
|
|
99
|
+
initial: existing.MATTERMOST_BOT_NAME || 'claude-code',
|
|
53
100
|
hint: 'Users will @mention this name',
|
|
54
101
|
},
|
|
55
102
|
{
|
|
56
103
|
type: 'text',
|
|
57
104
|
name: 'allowedUsers',
|
|
58
105
|
message: 'Allowed usernames',
|
|
59
|
-
initial: '',
|
|
106
|
+
initial: existing.ALLOWED_USERS || '',
|
|
60
107
|
hint: 'Comma-separated, or empty for all users',
|
|
61
108
|
},
|
|
62
109
|
{
|
|
63
110
|
type: 'confirm',
|
|
64
111
|
name: 'skipPermissions',
|
|
65
112
|
message: 'Skip permission prompts?',
|
|
66
|
-
initial:
|
|
113
|
+
initial: existing.SKIP_PERMISSIONS !== undefined
|
|
114
|
+
? existing.SKIP_PERMISSIONS === 'true'
|
|
115
|
+
: true,
|
|
67
116
|
hint: 'If no, you\'ll approve each action via emoji reactions',
|
|
68
117
|
},
|
|
118
|
+
{
|
|
119
|
+
type: 'confirm',
|
|
120
|
+
name: 'chrome',
|
|
121
|
+
message: 'Enable Chrome integration?',
|
|
122
|
+
initial: existing.CLAUDE_CHROME === 'true',
|
|
123
|
+
hint: 'Requires Claude in Chrome extension',
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
type: 'select',
|
|
127
|
+
name: 'worktreeMode',
|
|
128
|
+
message: 'Git worktree mode',
|
|
129
|
+
hint: 'Isolate changes in separate worktrees',
|
|
130
|
+
choices: [
|
|
131
|
+
{ title: 'Prompt', value: 'prompt', description: 'Ask when starting new sessions' },
|
|
132
|
+
{ title: 'Off', value: 'off', description: 'Never use worktrees' },
|
|
133
|
+
{ title: 'Require', value: 'require', description: 'Always require a branch name' },
|
|
134
|
+
],
|
|
135
|
+
initial: worktreeModeIndex(existing.WORKTREE_MODE),
|
|
136
|
+
},
|
|
69
137
|
], { onCancel });
|
|
70
|
-
// Check if user cancelled
|
|
71
|
-
|
|
138
|
+
// Check if user cancelled - token can be empty if keeping existing
|
|
139
|
+
const finalToken = response.token || existing.MATTERMOST_TOKEN;
|
|
140
|
+
if (!response.url || !finalToken || !response.channelId) {
|
|
72
141
|
console.log('');
|
|
73
142
|
console.log(dim(' Setup incomplete. Run claude-threads again to retry.'));
|
|
74
143
|
process.exit(1);
|
|
@@ -81,7 +150,7 @@ export async function runOnboarding() {
|
|
|
81
150
|
MATTERMOST_URL=${response.url}
|
|
82
151
|
|
|
83
152
|
# Bot token (from Integrations > Bot Accounts)
|
|
84
|
-
MATTERMOST_TOKEN=${
|
|
153
|
+
MATTERMOST_TOKEN=${finalToken}
|
|
85
154
|
|
|
86
155
|
# Channel ID where the bot listens
|
|
87
156
|
MATTERMOST_CHANNEL_ID=${response.channelId}
|
|
@@ -94,10 +163,18 @@ ALLOWED_USERS=${response.allowedUsers || ''}
|
|
|
94
163
|
|
|
95
164
|
# Skip permission prompts (true = auto-approve, false = require emoji approval)
|
|
96
165
|
SKIP_PERMISSIONS=${response.skipPermissions ? 'true' : 'false'}
|
|
166
|
+
|
|
167
|
+
# Chrome integration (requires Claude in Chrome extension)
|
|
168
|
+
CLAUDE_CHROME=${response.chrome ? 'true' : 'false'}
|
|
169
|
+
|
|
170
|
+
# Git worktree mode (off, prompt, require)
|
|
171
|
+
WORKTREE_MODE=${response.worktreeMode || 'prompt'}
|
|
97
172
|
`;
|
|
98
|
-
// Save to
|
|
99
|
-
const
|
|
100
|
-
const
|
|
173
|
+
// Save to same location if reconfiguring, otherwise default location
|
|
174
|
+
const defaultConfigDir = resolve(homedir(), '.config', 'claude-threads');
|
|
175
|
+
const defaultEnvPath = resolve(defaultConfigDir, '.env');
|
|
176
|
+
const envPath = existingPath || defaultEnvPath;
|
|
177
|
+
const configDir = dirname(envPath);
|
|
101
178
|
try {
|
|
102
179
|
mkdirSync(configDir, { recursive: true });
|
|
103
180
|
writeFileSync(envPath, envContent, { mode: 0o600 }); // Secure permissions
|