runsignal 0.1.3 → 0.1.5

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.
Files changed (3) hide show
  1. package/README.md +26 -10
  2. package/bin/runsignal.js +174 -11
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -16,22 +16,31 @@ npx runsignal --help
16
16
 
17
17
  ## Commands
18
18
 
19
- - `runsignal login`
19
+ - `runsignal login`
20
20
  - `runsignal init`
21
- - `runsignal wrap -- <command>`
21
+ - `runsignal setup`
22
+ - `runsignal wrap -- <command>`
22
23
  - `runsignal send --message "..."`
23
24
  - `runsignal status <eventId>`
24
25
  - `runsignal logout`
25
- - `runsignal hooks install --shell powershell`
26
- - `runsignal hooks doctor --shell powershell`
27
- - `runsignal hooks uninstall --shell powershell`
26
+ - `runsignal hooks install`
27
+ - `runsignal hooks doctor`
28
+ - `runsignal hooks uninstall`
28
29
 
29
30
  ## Quickstart
30
31
 
32
+ Canonical zero-friction onboarding:
33
+
34
+ ```bash
35
+ npx --yes runsignal@latest setup
36
+ ```
37
+
38
+ Equivalent manual flow:
39
+
31
40
  ```bash
32
- npx runsignal@latest login
33
- npx runsignal@latest init
34
- npx runsignal@latest wrap -- claude "refactor auth flow"
41
+ npx --yes runsignal@latest login
42
+ npx --yes runsignal@latest init
43
+ npx --yes runsignal@latest hooks install
35
44
  ```
36
45
 
37
46
  ## Environment
@@ -43,12 +52,19 @@ npx runsignal@latest wrap -- claude "refactor auth flow"
43
52
  To keep using `claude ...` / `codex ...` normally while routing through RunSignal:
44
53
 
45
54
  ```bash
46
- runsignal hooks install --shell powershell
55
+ runsignal hooks install
47
56
  ```
48
57
 
49
58
  Then restart terminal and verify:
50
59
 
51
60
  ```bash
52
- runsignal hooks doctor --shell powershell
61
+ runsignal hooks doctor
62
+ ```
63
+
64
+ After that, use your CLI agents normally:
65
+
66
+ ```bash
67
+ claude
68
+ codex
53
69
  ```
54
70
 
package/bin/runsignal.js CHANGED
@@ -120,21 +120,100 @@ function stripHookBlock(content) {
120
120
  function buildHookBlock(shellKind) {
121
121
  if (shellKind === 'powershell') {
122
122
  return `${HOOK_START}
123
- function claude { runsignal wrap -- claude @args }
124
- function codex { runsignal wrap -- codex @args }
125
- function cursor { runsignal wrap -- cursor @args }
126
- function gemini { runsignal wrap -- gemini @args }
127
- function aider { runsignal wrap -- aider @args }
123
+ function RunSignal-Resolve-NativeCommand {
124
+ param([string]$Name)
125
+ $cmd = Get-Command $Name -CommandType Application -ErrorAction SilentlyContinue | Select-Object -First 1
126
+ if (-not $cmd) { return $null }
127
+ return $cmd.Source
128
+ }
129
+ function claude {
130
+ $native = RunSignal-Resolve-NativeCommand "claude"
131
+ if (-not $native) {
132
+ $home = [Environment]::GetFolderPath("UserProfile")
133
+ $fallback = Join-Path $home ".local\\bin\\claude.exe"
134
+ if (Test-Path $fallback) { $native = $fallback }
135
+ }
136
+ if (-not $native) { Write-Error "RunSignal hook: native claude executable not found. Add your native installer path to PATH (example: %USERPROFILE%\\.local\\bin)."; return }
137
+ if ($args.Count -eq 0) { & $native; return }
138
+ runsignal wrap -- $native @args
139
+ }
140
+ function codex {
141
+ $native = RunSignal-Resolve-NativeCommand "codex"
142
+ if (-not $native) { Write-Error "RunSignal hook: native codex executable not found."; return }
143
+ if ($args.Count -eq 0) { & $native; return }
144
+ runsignal wrap -- $native @args
145
+ }
146
+ function cursor {
147
+ $native = RunSignal-Resolve-NativeCommand "cursor"
148
+ if (-not $native) { Write-Error "RunSignal hook: native cursor executable not found."; return }
149
+ if ($args.Count -eq 0) { & $native; return }
150
+ runsignal wrap -- $native @args
151
+ }
152
+ function gemini {
153
+ $native = RunSignal-Resolve-NativeCommand "gemini"
154
+ if (-not $native) { Write-Error "RunSignal hook: native gemini executable not found."; return }
155
+ if ($args.Count -eq 0) { & $native; return }
156
+ runsignal wrap -- $native @args
157
+ }
158
+ function aider {
159
+ $native = RunSignal-Resolve-NativeCommand "aider"
160
+ if (-not $native) { Write-Error "RunSignal hook: native aider executable not found."; return }
161
+ if ($args.Count -eq 0) { & $native; return }
162
+ runsignal wrap -- $native @args
163
+ }
128
164
  ${HOOK_END}
129
165
  `;
130
166
  }
131
167
 
132
168
  return `${HOOK_START}
133
- claude() { runsignal wrap -- claude "$@"; }
134
- codex() { runsignal wrap -- codex "$@"; }
135
- cursor() { runsignal wrap -- cursor "$@"; }
136
- gemini() { runsignal wrap -- gemini "$@"; }
137
- aider() { runsignal wrap -- aider "$@"; }
169
+ runsignal_resolve_native() {
170
+ local name
171
+ name="$1"
172
+ if type -P "$name" >/dev/null 2>&1; then
173
+ type -P "$name"
174
+ return 0
175
+ fi
176
+ if [ -x "$HOME/.local/bin/$name" ]; then
177
+ printf '%s\n' "$HOME/.local/bin/$name"
178
+ return 0
179
+ fi
180
+ return 1
181
+ }
182
+ claude() {
183
+ local native
184
+ native="$(runsignal_resolve_native claude)"
185
+ if [ -z "$native" ]; then echo "RunSignal hook: native claude executable not found." >&2; return 127; fi
186
+ if [ "$#" -eq 0 ]; then "$native"; return $?; fi
187
+ runsignal wrap -- "$native" "$@"
188
+ }
189
+ codex() {
190
+ local native
191
+ native="$(runsignal_resolve_native codex)"
192
+ if [ -z "$native" ]; then echo "RunSignal hook: native codex executable not found." >&2; return 127; fi
193
+ if [ "$#" -eq 0 ]; then "$native"; return $?; fi
194
+ runsignal wrap -- "$native" "$@"
195
+ }
196
+ cursor() {
197
+ local native
198
+ native="$(runsignal_resolve_native cursor)"
199
+ if [ -z "$native" ]; then echo "RunSignal hook: native cursor executable not found." >&2; return 127; fi
200
+ if [ "$#" -eq 0 ]; then "$native"; return $?; fi
201
+ runsignal wrap -- "$native" "$@"
202
+ }
203
+ gemini() {
204
+ local native
205
+ native="$(runsignal_resolve_native gemini)"
206
+ if [ -z "$native" ]; then echo "RunSignal hook: native gemini executable not found." >&2; return 127; fi
207
+ if [ "$#" -eq 0 ]; then "$native"; return $?; fi
208
+ runsignal wrap -- "$native" "$@"
209
+ }
210
+ aider() {
211
+ local native
212
+ native="$(runsignal_resolve_native aider)"
213
+ if [ -z "$native" ]; then echo "RunSignal hook: native aider executable not found." >&2; return 127; fi
214
+ if [ "$#" -eq 0 ]; then "$native"; return $?; fi
215
+ runsignal wrap -- "$native" "$@"
216
+ }
138
217
  ${HOOK_END}
139
218
  `;
140
219
  }
@@ -256,6 +335,21 @@ async function runHooksDoctor(options) {
256
335
  }
257
336
  }
258
337
 
338
+ async function areHooksInstalled(shellOption) {
339
+ const targets = resolveHookTargets(shellOption);
340
+ if (!targets.length) {
341
+ throw new Error('hooks_shell_not_supported');
342
+ }
343
+ for (const target of targets) {
344
+ const existing = await readTextFile(target.path);
345
+ const hasHooks = existing.includes(HOOK_START) && existing.includes(HOOK_END);
346
+ if (!hasHooks) {
347
+ return false;
348
+ }
349
+ }
350
+ return true;
351
+ }
352
+
259
353
  function getMachineName() {
260
354
  return process.env.COMPUTERNAME || os.hostname() || 'machine';
261
355
  }
@@ -793,9 +887,78 @@ async function runLogout() {
793
887
  console.log('Logged out.');
794
888
  }
795
889
 
890
+ async function runSetup(options) {
891
+ const shell = String(options.shell || 'auto');
892
+ let config = await readConfig();
893
+ const baseUrl = String(options.appUrl || config.app_url || DEFAULT_APP_URL).replace(/\/$/, '');
894
+
895
+ if (config.app_url !== baseUrl) {
896
+ await writeConfig(mergeConfig(config, {app_url: baseUrl}));
897
+ config = await readConfig();
898
+ }
899
+
900
+ const summary = {
901
+ login: 'skipped',
902
+ init: 'skipped',
903
+ hooks: 'skipped'
904
+ };
905
+
906
+ if (!config.access_token) {
907
+ await runLogin({appUrl: baseUrl});
908
+ summary.login = 'ok';
909
+ config = await readConfig();
910
+ }
911
+
912
+ if (!config.machine_api_key) {
913
+ await runInit({
914
+ appUrl: baseUrl,
915
+ machineName: options.machineName,
916
+ provider: options.provider,
917
+ botToken: options.botToken,
918
+ chatId: options.chatId,
919
+ webhookUrl: options.webhookUrl
920
+ });
921
+ summary.init = 'ok';
922
+ }
923
+
924
+ const hooksInstalled = await areHooksInstalled(shell);
925
+ if (!hooksInstalled) {
926
+ await runHooksInstall({shell});
927
+ summary.hooks = 'ok';
928
+ }
929
+
930
+ console.log(
931
+ JSON.stringify(
932
+ {
933
+ setup: 'ok',
934
+ login: summary.login,
935
+ init: summary.init,
936
+ hooks: summary.hooks,
937
+ next: 'Open a new terminal, then run claude or codex normally.'
938
+ },
939
+ null,
940
+ 2
941
+ )
942
+ );
943
+ }
944
+
796
945
  const program = new Command();
797
946
 
798
- program.name('runsignal').description('RunSignal CLI').version('0.1.3');
947
+ program.name('runsignal').description('RunSignal CLI').version('0.1.5');
948
+
949
+ program
950
+ .command('setup')
951
+ .description('Zero-friction onboarding: login + init + hooks install')
952
+ .option('--app-url <url>', 'RunSignal app base URL')
953
+ .option('--shell <shell>', 'auto|powershell|bash|zsh|all', 'auto')
954
+ .option('--provider <provider>', 'telegram or slack (optional)')
955
+ .option('--machine-name <name>', 'Machine name override')
956
+ .option('--bot-token <token>', 'Telegram bot token')
957
+ .option('--chat-id <id>', 'Telegram chat id')
958
+ .option('--webhook-url <url>', 'Slack webhook URL')
959
+ .action(async (options) => {
960
+ await runSetup(options);
961
+ });
799
962
 
800
963
  program
801
964
  .command('login')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "runsignal",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "RunSignal CLI for wrapping AI agent runs and handling approvals",
5
5
  "type": "module",
6
6
  "license": "MIT",