Skip to content

Commit fe12ebf

Browse files
committed
1.6.5: Add shell shortcuts for Claude Code and fix CTRL+C error handling
1 parent acd651d commit fe12ebf

File tree

9 files changed

+283
-7
lines changed

9 files changed

+283
-7
lines changed

bin/lt

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,19 @@
33

44
/* tslint:disable */
55

6+
// Handle CTRL+C gracefully (enquirer throws ERR_USE_AFTER_CLOSE when readline is closed)
7+
function handleCtrlCError(e) {
8+
if (!e || (e && e.code === 'ERR_USE_AFTER_CLOSE')) {
9+
console.log('Goodbye ✌️');
10+
process.exit(0);
11+
} else {
12+
console.error(e);
13+
process.exit(1);
14+
}
15+
}
16+
process.on('unhandledRejection', handleCtrlCError);
17+
process.on('uncaughtException', handleCtrlCError);
18+
619
// Handle case where current working directory no longer exists
720
try {
821
process.cwd();

docs/commands.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -886,6 +886,39 @@ lt claude plugins lt-dev --uninstall
886886

887887
---
888888

889+
### `lt claude shortcuts`
890+
891+
Installs Claude Code shell shortcuts (aliases) for quick access to common commands.
892+
893+
**Usage:**
894+
```bash
895+
lt claude shortcuts
896+
```
897+
898+
**Alias:** `lt claude s`
899+
900+
**Shortcuts installed:**
901+
| Alias | Command | Description |
902+
|-------|---------|-------------|
903+
| `c` | `claude --dangerously-skip-permissions` | Start new Claude Code session |
904+
| `cc` | `claude --dangerously-skip-permissions --continue` | Continue last session |
905+
| `cr` | `claude --dangerously-skip-permissions --resume` | Select and resume previous session |
906+
907+
**Note:** These shortcuts use `--dangerously-skip-permissions` which enables autonomous operation by bypassing permission prompts. Ensure you have proper data backups before using them.
908+
909+
**Examples:**
910+
```bash
911+
# Install shortcuts to ~/.zshrc (or detected shell config)
912+
lt claude shortcuts
913+
914+
# After installation, use:
915+
c # Start new session
916+
cc # Continue last session
917+
cr # Resume a previous session
918+
```
919+
920+
---
921+
889922
## Blocks & Components
890923

891924
### `lt blocks add`

package-lock.json

Lines changed: 17 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@lenne.tech/cli",
3-
"version": "1.6.4",
3+
"version": "1.6.5",
44
"description": "lenne.Tech CLI: lt",
55
"keywords": [
66
"lenne.Tech",

src/commands/claude/plugins.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ import {
2020
readPluginContents,
2121
setupPermissions,
2222
} from '../../lib/plugin-utils';
23+
import { getPreferredShellConfig } from '../../lib/shell-config';
2324

2425
/**
2526
* Install a single plugin (marketplace must already be added and updated)
@@ -353,7 +354,9 @@ const PluginsCommand: GluegunCommand = {
353354
info(' 1. Set required environment variables (see above)');
354355
info(' 2. Restart Claude Code to activate the plugins');
355356
} else if (envVarsResult.configured || allMissingEnvVars.size > 0) {
356-
info(' 1. Restart your terminal or run source command');
357+
const shellConfig = getPreferredShellConfig();
358+
const sourceCmd = shellConfig ? `source ${shellConfig.path}` : 'source your shell config';
359+
info(` 1. Restart your terminal or run: ${sourceCmd}`);
357360
info(' 2. Restart Claude Code to activate the plugins');
358361
} else {
359362
info(' Restart Claude Code to activate the plugins');

src/commands/claude/shortcuts.ts

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { GluegunCommand } from 'gluegun';
2+
3+
import { ExtendedGluegunToolbox } from '../../interfaces/extended-gluegun-toolbox';
4+
import {
5+
addAliasBlockToShellConfig,
6+
checkAliasInFile,
7+
getPreferredShellConfig,
8+
ShellAlias,
9+
} from '../../lib/shell-config';
10+
11+
/**
12+
* Claude Code shortcuts (shell aliases)
13+
* See: https://docs.lennetech.app/claude-code/installation
14+
*/
15+
const CLAUDE_SHORTCUTS: ShellAlias[] = [
16+
{
17+
alias: 'c',
18+
command: 'claude --dangerously-skip-permissions',
19+
description: 'Start new Claude Code session',
20+
},
21+
{
22+
alias: 'cc',
23+
command: 'claude --dangerously-skip-permissions --continue',
24+
description: 'Continue last session',
25+
},
26+
{
27+
alias: 'cr',
28+
command: 'claude --dangerously-skip-permissions --resume',
29+
description: 'Select and resume previous session',
30+
},
31+
];
32+
33+
/**
34+
* Install Claude Code shell shortcuts
35+
*/
36+
const ShortcutsCommand: GluegunCommand = {
37+
alias: ['s'],
38+
description: 'Install shell shortcuts',
39+
name: 'shortcuts',
40+
run: async (toolbox: ExtendedGluegunToolbox) => {
41+
const {
42+
print: { error, info, success },
43+
} = toolbox;
44+
45+
// Get preferred shell config
46+
const shellConfig = getPreferredShellConfig();
47+
48+
if (!shellConfig) {
49+
error('Could not detect shell configuration file.');
50+
info('Supported shells: zsh, bash');
51+
52+
if (!toolbox.parameters.options.fromGluegunMenu) {
53+
process.exit(1);
54+
}
55+
return 'shortcuts: no shell config found';
56+
}
57+
58+
info(`Shell: ${shellConfig.shell}`);
59+
info(`Config: ${shellConfig.path}`);
60+
info('');
61+
62+
// Check which shortcuts are already installed
63+
const existingAliases: ShellAlias[] = [];
64+
const missingAliases: ShellAlias[] = [];
65+
66+
for (const shortcut of CLAUDE_SHORTCUTS) {
67+
if (checkAliasInFile(shellConfig.path, shortcut.alias)) {
68+
existingAliases.push(shortcut);
69+
} else {
70+
missingAliases.push(shortcut);
71+
}
72+
}
73+
74+
// Show status
75+
if (existingAliases.length > 0) {
76+
info('Already installed:');
77+
for (const { alias, description } of existingAliases) {
78+
info(` ${alias} - ${description}`);
79+
}
80+
info('');
81+
}
82+
83+
if (missingAliases.length === 0) {
84+
success('All Claude Code shortcuts are already installed!');
85+
info('');
86+
info('Available shortcuts:');
87+
for (const { alias, command, description } of CLAUDE_SHORTCUTS) {
88+
info(` ${alias} - ${description}`);
89+
info(` ${command}`);
90+
}
91+
92+
if (!toolbox.parameters.options.fromGluegunMenu) {
93+
process.exit(0);
94+
}
95+
return 'shortcuts: already installed';
96+
}
97+
98+
// Add missing aliases
99+
const added = addAliasBlockToShellConfig(shellConfig.path, missingAliases);
100+
101+
if (added) {
102+
info('');
103+
success(`Added ${missingAliases.length} shortcut${missingAliases.length > 1 ? 's' : ''} to ${shellConfig.path}`);
104+
info('');
105+
info(`Run: source ${shellConfig.path}`);
106+
info('Or restart your terminal to apply changes.');
107+
} else {
108+
error(`Failed to write to ${shellConfig.path}`);
109+
info('');
110+
info('To add manually, add these lines to your shell config:');
111+
info('');
112+
for (const { alias, command } of missingAliases) {
113+
info(`alias ${alias}='${command}'`);
114+
}
115+
116+
if (!toolbox.parameters.options.fromGluegunMenu) {
117+
process.exit(1);
118+
}
119+
return 'shortcuts: write failed';
120+
}
121+
122+
if (!toolbox.parameters.options.fromGluegunMenu) {
123+
process.exit(0);
124+
}
125+
return `shortcuts: ${missingAliases.length} added`;
126+
},
127+
};
128+
129+
export default ShortcutsCommand;

src/lib/claude-cli.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,6 @@ export function runClaudeCommand(cli: string, args: string): ClaudeCommandResult
8686
try {
8787
const result = spawnSync(cli, args.split(' '), {
8888
encoding: 'utf-8',
89-
shell: true,
9089
stdio: ['pipe', 'pipe', 'pipe'],
9190
});
9291
return {

src/lib/plugin-utils.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ export async function handleMissingEnvVars(
182182
success: (msg: string) => void;
183183
warning: (msg: string) => void;
184184
};
185-
prompt: { confirm: (msg: string) => Promise<boolean> };
185+
prompt: { confirm: (msg: string, initial?: boolean) => Promise<boolean> };
186186
},
187187
): Promise<EnvVarsHandlingResult> {
188188
const {
@@ -236,7 +236,8 @@ export async function handleMissingEnvVars(
236236
if (targetConfig) {
237237
// Ask user if they want to add the env vars automatically
238238
const shouldAdd = await prompt.confirm(
239-
`Add ${envVarsToAdd.length > 1 ? 'these variables' : envVarsToAdd[0].name} to ${targetConfig.path}?`
239+
`Add ${envVarsToAdd.length > 1 ? 'these variables' : envVarsToAdd[0].name} to ${targetConfig.path}?`,
240+
true
240241
);
241242

242243
if (shouldAdd) {

0 commit comments

Comments
 (0)