clideck 1.30.6 → 1.30.7

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/config.js CHANGED
@@ -119,6 +119,9 @@ function migrate(cfg) {
119
119
  // Backfill and sync fields from presets
120
120
  for (const cmd of cfg.commands) {
121
121
  const preset = cmd.presetId ? PRESETS.find(p => p.presetId === cmd.presetId) : matchPreset(cmd);
122
+ if (preset?.presetId === 'shell' && (!cmd.command || (cmd.command === '/bin/zsh' && !existsSync('/bin/zsh')))) {
123
+ cmd.command = defaultShell;
124
+ }
122
125
  // Stamp presetId for reliable lookup
123
126
  if (preset && !cmd.presetId) cmd.presetId = preset.presetId;
124
127
  // Icon always syncs from preset — the preset is the source of truth for logos
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clideck",
3
- "version": "1.30.6",
3
+ "version": "1.30.7",
4
4
  "description": "One screen for all your AI coding agents — run, monitor, and manage multiple CLI agents from a single browser tab",
5
5
  "main": "server.js",
6
6
  "bin": {
package/public/js/app.js CHANGED
@@ -55,6 +55,9 @@ function connect() {
55
55
  state.resumable = msg.list;
56
56
  renderResumable();
57
57
  break;
58
+ case 'error':
59
+ showToast(msg.message || 'CliDeck action failed.', { type: 'error', title: 'CliDeck Error', duration: 5000 });
60
+ break;
58
61
  case 'sessions':
59
62
  {
60
63
  const liveIds = new Set(msg.list.map(s => s.id));
@@ -134,6 +134,33 @@ function ensureCommandForPreset(preset) {
134
134
  return cmd;
135
135
  }
136
136
 
137
+ function ensureShellCommand() {
138
+ let cmd = state.cfg.commands.find(c => c.presetId === 'shell' || (!c.isAgent && !c.presetId));
139
+ if (cmd) return cmd;
140
+ const shellPreset = state.presets.find(p => p.presetId === 'shell');
141
+ const command = shellPreset?.command || state.cfg.defaultShell;
142
+ if (!command) return null;
143
+ cmd = {
144
+ id: crypto.randomUUID(),
145
+ presetId: 'shell',
146
+ label: 'Shell',
147
+ icon: shellPreset?.icon || 'terminal',
148
+ command,
149
+ enabled: true,
150
+ defaultPath: '',
151
+ isAgent: false,
152
+ canResume: false,
153
+ resumeCommand: null,
154
+ sessionIdPattern: null,
155
+ outputMarker: null,
156
+ telemetryEnabled: false,
157
+ telemetryStatus: null,
158
+ };
159
+ state.cfg.commands.push(cmd);
160
+ send({ type: 'config.update', config: state.cfg });
161
+ return cmd;
162
+ }
163
+
137
164
  export function openCreator() {
138
165
  // Toggle off if already open
139
166
  if (document.getElementById('session-creator')) {
@@ -348,8 +375,11 @@ function showInstallToast(preset) {
348
375
  setTimeout(() => send({ type: 'telemetry.autosetup', presetId: preset.presetId }), 1000);
349
376
  }
350
377
  // Find or create the shell command, then spawn a session running the install
351
- const shellCmd = state.cfg.commands.find(c => c.presetId === 'shell' || (!c.isAgent && !c.presetId));
352
- if (!shellCmd) return;
378
+ const shellCmd = ensureShellCommand();
379
+ if (!shellCmd) {
380
+ showToast('Could not find a shell command to run the installer.', { type: 'error', title: 'Install Failed' });
381
+ return;
382
+ }
353
383
  const installId = crypto.randomUUID();
354
384
  send({ type: 'create', commandId: shellCmd.id, name: `Installing ${preset.name}`, installId, ...estimateSize() });
355
385
  const handler = (e) => {
package/server.js CHANGED
@@ -8,6 +8,10 @@ function terminalLink(url, text = url) {
8
8
  return `\u001B]8;;${url}\u0007${text}\u001B]8;;\u0007`;
9
9
  }
10
10
 
11
+ function openUrlHint() {
12
+ return process.platform === 'darwin' ? 'Cmd+click to open' : 'Ctrl+click to open';
13
+ }
14
+
11
15
  // --- Self-update check (runs before server starts) ---
12
16
  const currentVersion = require('./package.json').version;
13
17
  const { execFile, execSync } = require('child_process');
@@ -291,6 +295,7 @@ server.listen(PORT, HOST, () => {
291
295
  const v = require('./package.json').version;
292
296
  const url = `http://${HOST === '0.0.0.0' ? 'localhost' : HOST}:${PORT}`;
293
297
  const clickableUrl = terminalLink(url);
298
+ const urlHint = openUrlHint();
294
299
  console.log(`
295
300
  \x1b[38;5;105m ╺━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━╸\x1b[0m
296
301
 
@@ -305,7 +310,7 @@ server.listen(PORT, HOST, () => {
305
310
 
306
311
  \x1b[38;5;245m v${v}\x1b[0m
307
312
 
308
- \x1b[38;5;252m ▸ Ready at \x1b[38;5;44m${clickableUrl}\x1b[38;5;245m (Cmd+click to open)\x1b[0m
313
+ \x1b[38;5;252m ▸ Ready at \x1b[38;5;44m${clickableUrl}\x1b[38;5;245m (${urlHint})\x1b[0m
309
314
  \x1b[38;5;245m ▸ Stop with \x1b[38;5;252mCtrl+C\x1b[38;5;245m · Restart anytime with \x1b[38;5;252mclideck\x1b[0m
310
315
  ${HOST !== '127.0.0.1' ? '\x1b[38;5;208m ▸ Warning: listening on ' + HOST + ' — no authentication, anyone on the network can connect\x1b[0m\n' : ''}`);
311
316
  });
package/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- const { chmodSync, statSync, readdirSync } = require('fs');
1
+ const { chmodSync, existsSync, statSync, readdirSync } = require('fs');
2
2
  const { dirname, join } = require('path');
3
3
 
4
4
  function ensurePtyHelper() {
@@ -55,7 +55,13 @@ function listDirs(path, showHidden) {
55
55
  }
56
56
  }
57
57
 
58
- const defaultShell = process.platform === 'win32' ? (process.env.COMSPEC || 'cmd.exe') : '/bin/zsh';
58
+ function resolveDefaultShell() {
59
+ if (process.platform === 'win32') return process.env.COMSPEC || 'cmd.exe';
60
+ const candidates = [process.env.SHELL, '/bin/zsh', '/bin/bash', '/bin/sh'].filter(Boolean);
61
+ return candidates.find(shell => existsSync(shell)) || '/bin/sh';
62
+ }
63
+
64
+ const defaultShell = resolveDefaultShell();
59
65
 
60
66
  function binName(command) {
61
67
  const m = command.match(/^(['"])(.*?)\1/);