trooper-cli 0.1.4 → 0.1.6

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
@@ -2,27 +2,28 @@
2
2
 
3
3
  Official command-line installer for Trooper's local desktop runtime.
4
4
 
5
- Trooper can run on your own Mac without a hosted cloud computer. This CLI installs the local bridge, starts the local AI gateway, and lets the Trooper desktop app pair the machine to your workspace.
5
+ Trooper can run on your own Mac without a hosted cloud computer. This CLI installs the local bridge, starts the local AI gateway, installs the Trooper desktop app when it is missing, and opens Trooper so the machine can pair to your workspace.
6
6
 
7
7
  ## Quick Start
8
8
 
9
9
  Install Trooper locally on this Mac:
10
10
 
11
11
  ```bash
12
- npx -y trooper-cli onboard --yes
12
+ npx -y trooper-cli
13
13
  ```
14
14
 
15
- Then open the Trooper desktop app to connect this computer to your workspace.
15
+ The command opens the Trooper desktop app when setup finishes.
16
16
 
17
17
  ## What It Sets Up
18
18
 
19
- On macOS, `trooper-cli onboard --yes` prepares:
19
+ On macOS, `npx -y trooper-cli` prepares:
20
20
 
21
21
  - A local Trooper bridge on `http://127.0.0.1:3002`
22
22
  - A local AI gateway on `http://127.0.0.1:18789`
23
23
  - LaunchAgents so the local host can keep running
24
24
  - A Docker-compatible runtime using existing Docker or Colima when needed
25
25
  - Local runtime files under `~/Library/Application Support/Trooper/runtime`
26
+ - Trooper.app in `~/Applications` when the desktop app is not already installed
26
27
 
27
28
  The local desktop plan does not require a Trooper cloud computer or Stripe checkout.
28
29
 
@@ -30,10 +31,22 @@ The local desktop plan does not require a Trooper cloud computer or Stripe check
30
31
 
31
32
  ### Install local runtime
32
33
 
34
+ ```bash
35
+ npx -y trooper-cli
36
+ ```
37
+
38
+ This is shorthand for:
39
+
33
40
  ```bash
34
41
  npx -y trooper-cli onboard --yes
35
42
  ```
36
43
 
44
+ Install only the runtime and skip desktop app install/open:
45
+
46
+ ```bash
47
+ npx -y trooper-cli --skip-app
48
+ ```
49
+
37
50
  ### Install with a Trooper setup token
38
51
 
39
52
  The Trooper app may generate a short-lived setup token for workspace pairing:
@@ -48,7 +61,7 @@ npx -y trooper-cli onboard --yes \
48
61
  ### Preview the installer command
49
62
 
50
63
  ```bash
51
- npx -y trooper-cli onboard --yes --dry-run
64
+ npx -y trooper-cli --dry-run
52
65
  ```
53
66
 
54
67
  ### Uninstall local runtime
@@ -79,7 +92,7 @@ npx -y --prefer-online trooper-cli@latest uninstall --yes --remove-app
79
92
 
80
93
  ## Desktop App
81
94
 
82
- Local desktop install is meant to be started from the Trooper Mac or Windows app. The web onboarding page shows the plan, but only the desktop app can safely launch the local helper installer.
95
+ The CLI installs and opens the Trooper Mac app automatically when it is missing. If the app is already installed in `~/Applications`, `/Applications`, or registered with Launch Services, the CLI opens the existing app instead of downloading it again.
83
96
 
84
97
  ## Links
85
98
 
package/bin/trooper.js CHANGED
@@ -5,6 +5,7 @@ import { randomBytes } from 'node:crypto';
5
5
 
6
6
  const DEFAULT_API_URL = 'https://trooper-production.up.railway.app';
7
7
  const LOCAL_MAC_SETUP_SCRIPT_URL = 'https://raw.githubusercontent.com/absurdfounder/trooper-bridge/main/setup-local-mac-host.sh';
8
+ const TROOPER_MAC_APP_DMG_URL = 'https://github.com/absurdfounder/trooper_landing/releases/download/macos-latest/Trooper.dmg';
8
9
  const LOCAL_MAC_LABELS = [
9
10
  'so.trooper.local-gateway',
10
11
  'so.trooper.local-bridge',
@@ -16,11 +17,13 @@ function printHelp() {
16
17
  console.log(`Trooper CLI
17
18
 
18
19
  Usage:
20
+ npx -y trooper-cli
19
21
  npx -y trooper-cli onboard --yes
20
22
  npx -y trooper-cli onboard --yes --token <setup-token>
21
23
  npx -y trooper-cli uninstall --yes
22
24
 
23
25
  Aliases:
26
+ no command Same as onboard --yes
24
27
  setup Same as onboard
25
28
  remove Same as uninstall
26
29
 
@@ -31,6 +34,7 @@ Options:
31
34
  --yes Run non-interactively with sensible defaults
32
35
  --keep-data Preserve local workspace/config data during uninstall
33
36
  --remove-app Also remove Trooper.app when uninstalling, if it is writable
37
+ --skip-app Install the local runtime only; do not install/open Trooper.app
34
38
  --print-command Print the installer command without running it
35
39
  --dry-run Same as --print-command
36
40
  -h, --help Show this help
@@ -47,7 +51,7 @@ function parseArgs(argv) {
47
51
  }
48
52
  const [key, inlineValue] = arg.split('=', 2);
49
53
  const name = key.replace(/^-+/, '');
50
- if (['help', 'h', 'dry-run', 'print-command', 'yes', 'y', 'keep-data', 'remove-app'].includes(name)) {
54
+ if (['help', 'h', 'dry-run', 'print-command', 'yes', 'y', 'keep-data', 'remove-app', 'skip-app'].includes(name)) {
51
55
  args[name] = true;
52
56
  continue;
53
57
  }
@@ -84,7 +88,67 @@ function localToken(prefix) {
84
88
  return `${prefix}_${randomBytes(24).toString('base64url')}`;
85
89
  }
86
90
 
87
- function buildLocalMacInstallCommand({ apiUrl }) {
91
+ function buildLocalMacAppInstallCommand() {
92
+ return `install_or_open_trooper_app() {
93
+ export PATH="/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin"
94
+ local app_path=""
95
+ for candidate in "$HOME/Applications/Trooper.app" "/Applications/Trooper.app"; do
96
+ if [[ -d "$candidate" ]]; then
97
+ app_path="$candidate"
98
+ break
99
+ fi
100
+ done
101
+
102
+ if [[ -z "$app_path" ]] && /usr/bin/open -Ra "Trooper" >/dev/null 2>&1; then
103
+ echo "Opening Trooper desktop app..."
104
+ /usr/bin/open -a "Trooper"
105
+ return 0
106
+ fi
107
+
108
+ if [[ -n "$app_path" ]]; then
109
+ echo "Opening Trooper desktop app..."
110
+ /usr/bin/open "$app_path"
111
+ return 0
112
+ fi
113
+
114
+ echo "Installing Trooper desktop app..."
115
+ local dmg_url="\${TROOPER_MAC_APP_DMG_URL:-${TROOPER_MAC_APP_DMG_URL}}"
116
+ local tmp_dmg mount_dir app_src install_root
117
+ tmp_dmg="$(/usr/bin/mktemp -t trooper-macos.XXXXXX).dmg"
118
+ mount_dir="$(/usr/bin/mktemp -d -t trooper-dmg.XXXXXX)"
119
+ install_root="$HOME/Applications"
120
+
121
+ cleanup_trooper_dmg() {
122
+ /usr/bin/hdiutil detach "$mount_dir" -quiet >/dev/null 2>&1 || true
123
+ /bin/rm -f "$tmp_dmg"
124
+ /bin/rm -rf "$mount_dir"
125
+ }
126
+ trap cleanup_trooper_dmg EXIT
127
+
128
+ /usr/bin/curl -fL --retry 3 --retry-delay 2 "$dmg_url" -o "$tmp_dmg"
129
+ /usr/bin/hdiutil attach "$tmp_dmg" -mountpoint "$mount_dir" -nobrowse -quiet
130
+ app_src="$(/usr/bin/find "$mount_dir" -maxdepth 1 -name "Trooper.app" -type d | /usr/bin/head -1)"
131
+ if [[ -z "$app_src" ]]; then
132
+ echo "Trooper.app was not found inside the downloaded DMG."
133
+ return 1
134
+ fi
135
+
136
+ /bin/mkdir -p "$install_root"
137
+ /bin/rm -rf "$install_root/Trooper.app"
138
+ /usr/bin/ditto "$app_src" "$install_root/Trooper.app"
139
+ /usr/bin/hdiutil detach "$mount_dir" -quiet >/dev/null 2>&1 || true
140
+ trap - EXIT
141
+ /bin/rm -f "$tmp_dmg"
142
+ /bin/rm -rf "$mount_dir"
143
+
144
+ echo "Trooper desktop app installed at: $install_root/Trooper.app"
145
+ /usr/bin/open "$install_root/Trooper.app"
146
+ }
147
+
148
+ install_or_open_trooper_app`;
149
+ }
150
+
151
+ function buildLocalMacInstallCommand({ apiUrl, installApp = true } = {}) {
88
152
  const hostSuffix = randomBytes(6).toString('hex');
89
153
  const env = {
90
154
  TROOPER_LOCAL_HOST: '1',
@@ -99,10 +163,12 @@ function buildLocalMacInstallCommand({ apiUrl }) {
99
163
  TUNNEL_PROVIDER: 'local',
100
164
  };
101
165
  return [
166
+ 'set -euo pipefail',
102
167
  buildExportCommand(env),
103
168
  `curl -fsSL ${shellSingleQuote(LOCAL_MAC_SETUP_SCRIPT_URL)} -o /tmp/trooper-local-mac-host.sh`,
104
169
  'chmod +x /tmp/trooper-local-mac-host.sh',
105
170
  'bash /tmp/trooper-local-mac-host.sh',
171
+ installApp ? buildLocalMacAppInstallCommand() : '',
106
172
  ].join('\n');
107
173
  }
108
174
 
@@ -218,7 +284,7 @@ function runShellCommand(command, platform, { failureLabel = 'Command', successM
218
284
 
219
285
  async function main() {
220
286
  const args = parseArgs(process.argv.slice(2));
221
- const command = args._[0] || 'help';
287
+ const command = args._[0] || 'onboard';
222
288
  if (args.help || args.h || command === 'help') {
223
289
  printHelp();
224
290
  return;
@@ -259,7 +325,7 @@ async function main() {
259
325
  console.error('Tokenless local install is currently available for macOS. Open Trooper to prepare a paired installer for this platform.');
260
326
  process.exit(1);
261
327
  }
262
- const installCommand = buildLocalMacInstallCommand({ apiUrl });
328
+ const installCommand = buildLocalMacInstallCommand({ apiUrl, installApp: !args['skip-app'] });
263
329
  console.log('Starting Trooper local host setup on this Mac...');
264
330
  if (args['print-command'] || args['dry-run']) {
265
331
  console.log('\n' + installCommand);
@@ -267,7 +333,9 @@ async function main() {
267
333
  }
268
334
  runShellCommand(installCommand, platform, {
269
335
  failureLabel: 'Installer',
270
- successMessage: '\nTrooper local host is installed. Open Trooper to connect this Mac to your workspace.',
336
+ successMessage: args['skip-app']
337
+ ? '\nTrooper local host is installed. Open Trooper to connect this Mac to your workspace.'
338
+ : '\nTrooper local host is installed. Trooper desktop app is ready.',
271
339
  });
272
340
  return;
273
341
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "trooper-cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Official Trooper CLI for installing and managing the local desktop AI runtime.",
5
5
  "type": "module",
6
6
  "bin": {