cli-setu 0.1.0 → 0.2.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/README.md +12 -12
- package/bin/setu.js +25 -19
- package/package.json +2 -2
- package/src/cli-adapters/index.js +2 -2
- package/src/cli-adapters/shell.js +4 -4
- package/src/config.js +2 -2
- package/src/hooks.js +5 -5
- package/src/pair.js +15 -14
- package/src/status.js +6 -6
- package/src/stop.js +4 -4
- package/src/supervisor.js +22 -19
- package/src/update.js +10 -10
package/README.md
CHANGED
|
@@ -11,29 +11,29 @@ npm install -g cli-setu
|
|
|
11
11
|
## Usage
|
|
12
12
|
|
|
13
13
|
```bash
|
|
14
|
-
setu # bridges the current folder as a plain shell session
|
|
15
|
-
setu --cli claude # same, but runs Claude Code inside the bridged session
|
|
16
|
-
setu --cli codex # or Codex
|
|
14
|
+
cli-setu # bridges the current folder as a plain shell session
|
|
15
|
+
cli-setu --cli claude # same, but runs Claude Code inside the bridged session
|
|
16
|
+
cli-setu --cli codex # or Codex
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
The first time you run it, `setu` prints a QR code (and an 8-digit fallback code) - scan it with the CLIसेतु app to pair this computer and start watching the session live.
|
|
19
|
+
The first time you run it, `cli-setu` prints a QR code (and an 8-digit fallback code) - scan it with the CLIसेतु app to pair this computer and start watching the session live.
|
|
20
20
|
|
|
21
|
-
Once paired, running `setu` in any folder just works - no QR code needed again, unless this is a device you haven't paired before.
|
|
21
|
+
Once paired, running `cli-setu` in any folder just works - no QR code needed again, unless this is a device you haven't paired before.
|
|
22
22
|
|
|
23
23
|
## Other commands
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
|
-
setu pair # pair this computer, without starting a session
|
|
27
|
-
setu status # show pairing status and any sessions currently running
|
|
28
|
-
setu stop # stop a running session
|
|
29
|
-
setu --update # check for and install the latest version
|
|
30
|
-
setu --version # print the installed version
|
|
31
|
-
setu --help # show all commands
|
|
26
|
+
cli-setu pair # pair this computer, without starting a session
|
|
27
|
+
cli-setu status # show pairing status and any sessions currently running
|
|
28
|
+
cli-setu stop # stop a running session
|
|
29
|
+
cli-setu --update # check for and install the latest version
|
|
30
|
+
cli-setu --version # print the installed version
|
|
31
|
+
cli-setu --help # show all commands
|
|
32
32
|
```
|
|
33
33
|
|
|
34
34
|
## How it works
|
|
35
35
|
|
|
36
|
-
`setu` spawns your real terminal (or Claude Code/Codex) inside a PTY, same as any terminal emulator. Every byte it produces streams live to the CLIसेतु app over a secure relay; anything you type on the phone writes back into that same PTY, exactly like a local keystroke. Permission prompts (file edits, shell commands, etc.) are detected and relayed as structured approve/reject cards instead of raw text, when the adapter for your CLI supports it.
|
|
36
|
+
`cli-setu` spawns your real terminal (or Claude Code/Codex) inside a PTY, same as any terminal emulator. Every byte it produces streams live to the CLIसेतु app over a secure relay; anything you type on the phone writes back into that same PTY, exactly like a local keystroke. Permission prompts (file edits, shell commands, etc.) are detected and relayed as structured approve/reject cards instead of raw text, when the adapter for your CLI supports it.
|
|
37
37
|
|
|
38
38
|
## License
|
|
39
39
|
|
package/bin/setu.js
CHANGED
|
@@ -1,20 +1,26 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Command dispatcher for the `setu` CLI. Kept deliberately thin - each
|
|
2
|
+
// Command dispatcher for the `cli-setu` CLI. Kept deliberately thin - each
|
|
3
3
|
// real subcommand's logic lives in src/, this file only parses argv and
|
|
4
4
|
// calls the right one.
|
|
5
|
-
|
|
5
|
+
//
|
|
6
|
+
// TEMPORARY: defaults to the DEV server (dev-api.clisetu.com), not
|
|
7
|
+
// production, because only dev-api is live right now. MUST switch back to
|
|
8
|
+
// https://api.clisetu.com and republish before announcing this package to
|
|
9
|
+
// real users as "production ready" - see clisetuapp/backend's deployment
|
|
10
|
+
// guide for when production actually goes live.
|
|
11
|
+
const AUTH_SERVER = process.env.CLI_SETU_SERVER || 'https://dev-api.clisetu.com';
|
|
6
12
|
const AUTH_SERVER_PUBLIC = process.env.CLI_SETU_SERVER_PUBLIC || AUTH_SERVER;
|
|
7
13
|
|
|
8
14
|
// Real bug found by testing: this used to switch on process.argv[2]
|
|
9
15
|
// directly against the subcommand list (pair/status/stop), with any
|
|
10
|
-
// other value (including a real --flag, e.g. `setu --cli claude`)
|
|
16
|
+
// other value (including a real --flag, e.g. `cli-setu --cli claude`)
|
|
11
17
|
// falling through to "Unknown command" and exiting immediately - the
|
|
12
18
|
// whole multi-CLI feature (claude/codex/shell adapters) was unreachable
|
|
13
|
-
// through the real `setu` command this entire time, only ever testable
|
|
19
|
+
// through the real `cli-setu` command this entire time, only ever testable
|
|
14
20
|
// by calling node src/supervisor.js --cli claude directly. Flags
|
|
15
21
|
// (anything starting with "-") are no longer mistaken for subcommand
|
|
16
|
-
// names - they're checked first, and anything left over (bare `setu`, or
|
|
17
|
-
// `setu --cli claude`/other flags meant for the bridged session itself)
|
|
22
|
+
// names - they're checked first, and anything left over (bare `cli-setu`, or
|
|
23
|
+
// `cli-setu --cli claude`/other flags meant for the bridged session itself)
|
|
18
24
|
// falls through to the same "watch this session" path as before, which
|
|
19
25
|
// still parses --cli on its own further down the line (supervisor.js) -
|
|
20
26
|
// this dispatcher doesn't need to understand every flag supervisor.js
|
|
@@ -58,17 +64,17 @@ async function main() {
|
|
|
58
64
|
return;
|
|
59
65
|
}
|
|
60
66
|
default:
|
|
61
|
-
console.error(`[setu] Unknown command: ${firstArg}`);
|
|
67
|
+
console.error(`[cli-setu] Unknown command: ${firstArg}`);
|
|
62
68
|
printHelp();
|
|
63
69
|
process.exit(1);
|
|
64
70
|
}
|
|
65
71
|
}
|
|
66
72
|
|
|
67
|
-
// Bare `setu` (or `setu --cli <name>`, `setu --cli <name> <workingDir>`,
|
|
73
|
+
// Bare `cli-setu` (or `cli-setu --cli <name>`, `cli-setu --cli <name> <workingDir>`,
|
|
68
74
|
// etc. - real flags meant for the bridged session itself, parsed by
|
|
69
75
|
// supervisor.js) - watch the current directory as a session. Real
|
|
70
76
|
// product requirement: a brand-new user should be able to run just
|
|
71
|
-
// `setu` (no separate `setu pair` step to discover first) and see the
|
|
77
|
+
// `cli-setu` (no separate `cli-setu pair` step to discover first) and see the
|
|
72
78
|
// QR/8-digit code immediately, the same "first run pairs AND starts
|
|
73
79
|
// watching this session in one step" behavior the original
|
|
74
80
|
// proof-of-concept had. Only pairs if not already paired - an
|
|
@@ -83,22 +89,22 @@ async function main() {
|
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
function printHelp() {
|
|
86
|
-
console.log(`[setu] Bridge your terminal to your phone.
|
|
92
|
+
console.log(`[cli-setu] Bridge your terminal to your phone.
|
|
87
93
|
|
|
88
94
|
Usage:
|
|
89
|
-
setu Watch this folder as a session (pairs first if needed)
|
|
90
|
-
setu --cli <name> Same, but run a specific CLI inside the bridged
|
|
95
|
+
cli-setu Watch this folder as a session (pairs first if needed)
|
|
96
|
+
cli-setu --cli <name> Same, but run a specific CLI inside the bridged
|
|
91
97
|
session instead of the default plain shell
|
|
92
98
|
(e.g. --cli claude, --cli codex)
|
|
93
|
-
setu pair Pair this computer with your phone, nothing else
|
|
94
|
-
setu status Show pairing status and any sessions running now
|
|
95
|
-
setu stop Stop a running session
|
|
96
|
-
setu --version, -v Print the installed version
|
|
97
|
-
setu --update Check for and install the latest version
|
|
98
|
-
setu --help, -h Show this help`);
|
|
99
|
+
cli-setu pair Pair this computer with your phone, nothing else
|
|
100
|
+
cli-setu status Show pairing status and any sessions running now
|
|
101
|
+
cli-setu stop Stop a running session
|
|
102
|
+
cli-setu --version, -v Print the installed version
|
|
103
|
+
cli-setu --update Check for and install the latest version
|
|
104
|
+
cli-setu --help, -h Show this help`);
|
|
99
105
|
}
|
|
100
106
|
|
|
101
107
|
main().catch((err) => {
|
|
102
|
-
console.error('[setu] Error:', err.message);
|
|
108
|
+
console.error('[cli-setu] Error:', err.message);
|
|
103
109
|
process.exit(1);
|
|
104
110
|
});
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cli-setu",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "Bridge your terminal to your phone — run and approve Claude Code, Codex CLI and other AI coding agents from anywhere.",
|
|
5
5
|
"type": "commonjs",
|
|
6
6
|
"bin": {
|
|
7
|
-
"setu": "bin/setu.js"
|
|
7
|
+
"cli-setu": "bin/setu.js"
|
|
8
8
|
},
|
|
9
9
|
"main": "src/config.js",
|
|
10
10
|
"engines": {
|
|
@@ -13,11 +13,11 @@ const KNOWN_ADAPTERS = {
|
|
|
13
13
|
shell,
|
|
14
14
|
};
|
|
15
15
|
|
|
16
|
-
// Real product decision (confirmed directly by the PM): bare `setu` with
|
|
16
|
+
// Real product decision (confirmed directly by the PM): bare `cli-setu` with
|
|
17
17
|
// no --cli flag bridges the user's own plain terminal, not Claude Code
|
|
18
18
|
// specifically - the user decides what to run once it's open. Defaulting
|
|
19
19
|
// to 'claude' here silently assumed every user wanted an AI CLI running
|
|
20
|
-
// the instant they typed `setu`, which isn't actually the product's real
|
|
20
|
+
// the instant they typed `cli-setu`, which isn't actually the product's real
|
|
21
21
|
// intent (a genuine remote terminal, not an AI-agent-only bridge).
|
|
22
22
|
function getAdapter(cliName) {
|
|
23
23
|
const normalized = (cliName || 'shell').toLowerCase();
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
// The default adapter when a user runs plain `setu` with no --cli flag at
|
|
2
|
-
// all - a real gap in the earlier design: `setu` (bare) always launched
|
|
1
|
+
// The default adapter when a user runs plain `cli-setu` with no --cli flag at
|
|
2
|
+
// all - a real gap in the earlier design: `cli-setu` (bare) always launched
|
|
3
3
|
// Claude Code specifically, silently assuming that's what every user
|
|
4
4
|
// wants. The actual product intent (confirmed directly by the PM) is
|
|
5
|
-
// simpler and more honest: `setu` bridges the user's OWN real terminal to
|
|
5
|
+
// simpler and more honest: `cli-setu` bridges the user's OWN real terminal to
|
|
6
6
|
// their phone - a genuine remote shell, nothing AI-specific - and the
|
|
7
7
|
// user decides what to run inside it once it's open (`claude`, `codex`,
|
|
8
8
|
// `npm install`, `git status`, anything). Running an AI CLI inside this
|
|
@@ -43,7 +43,7 @@ module.exports = {
|
|
|
43
43
|
// INSIDE this shell, that CLI's own real adapter (claude.js/codex.js)
|
|
44
44
|
// still isn't active here, since supervisor.js picks exactly one
|
|
45
45
|
// adapter per process/session at startup - a real user wanting
|
|
46
|
-
// structured approvals for a specific CLI should run `setu --cli
|
|
46
|
+
// structured approvals for a specific CLI should run `cli-setu --cli
|
|
47
47
|
// claude` (or codex) directly, same as always. This adapter is
|
|
48
48
|
// specifically for "just give me my terminal, I'll decide what to run."
|
|
49
49
|
approvals: null,
|
package/src/config.js
CHANGED
|
@@ -15,7 +15,7 @@ function defaultDeviceName() {
|
|
|
15
15
|
return os.hostname() || 'My Computer';
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
// Saved once, on the first `setu pair`, so a later OS-level hostname
|
|
18
|
+
// Saved once, on the first `cli-setu pair`, so a later OS-level hostname
|
|
19
19
|
// change (renaming the machine, moving to a new user profile) doesn't
|
|
20
20
|
// silently rename an already-paired device out from under the user - the
|
|
21
21
|
// Devices tab's identity for this machine stays whatever it was when it
|
|
@@ -33,7 +33,7 @@ function writeConfig(config) {
|
|
|
33
33
|
fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
|
|
34
34
|
}
|
|
35
35
|
|
|
36
|
-
// Called by `setu pair` - creates the config the FIRST time, using the
|
|
36
|
+
// Called by `cli-setu pair` - creates the config the FIRST time, using the
|
|
37
37
|
// auto-detected hostname as the default device name. A config that
|
|
38
38
|
// already exists (this machine has paired before) is left untouched;
|
|
39
39
|
// re-pairing intentionally reuses the same device identity rather than
|
package/src/hooks.js
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
// that - every user's global install lives at a different path (varies by
|
|
5
5
|
// OS, by nvm/volta version manager, by whether it's a global or local
|
|
6
6
|
// install), and expecting someone to hand-edit JSON before their first
|
|
7
|
-
// `setu` run defeats the entire point of "npm install -g cli-setu" being
|
|
7
|
+
// `cli-setu` run defeats the entire point of "npm install -g cli-setu" being
|
|
8
8
|
// a real, ready-to-use install. This ensures the CURRENT project's
|
|
9
9
|
// .claude/settings.json has the right hook registered, pointing at
|
|
10
10
|
// wherever THIS running copy of cli-setu actually lives on disk right now
|
|
@@ -34,7 +34,7 @@ function alreadyRegistered(existingHooksForEvent) {
|
|
|
34
34
|
|
|
35
35
|
// Ensures the CURRENT working directory's .claude/settings.json has both
|
|
36
36
|
// hooks pointed at this package's real install location. Called once at
|
|
37
|
-
// the start of every `setu` (bare) run - cheap (a few small file reads/
|
|
37
|
+
// the start of every `cli-setu` (bare) run - cheap (a few small file reads/
|
|
38
38
|
// writes), and self-healing if the package is ever moved/reinstalled at a
|
|
39
39
|
// different path (a stale command string gets overwritten with today's
|
|
40
40
|
// real path automatically, no manual fix needed).
|
|
@@ -48,8 +48,8 @@ function ensureHooksRegistered(projectDir) {
|
|
|
48
48
|
} catch {
|
|
49
49
|
// No settings.json yet, or it's not valid JSON - start fresh rather
|
|
50
50
|
// than crash; an unreadable existing file is left untouched below by
|
|
51
|
-
// simply not being parsed further, but we still want `setu` itself
|
|
52
|
-
// keep working for this session's approval detection.
|
|
51
|
+
// simply not being parsed further, but we still want `cli-setu` itself
|
|
52
|
+
// to keep working for this session's approval detection.
|
|
53
53
|
}
|
|
54
54
|
|
|
55
55
|
settings.hooks = settings.hooks || {};
|
|
@@ -73,7 +73,7 @@ function ensureHooksRegistered(projectDir) {
|
|
|
73
73
|
if (changed) {
|
|
74
74
|
fs.mkdirSync(claudeDir, { recursive: true });
|
|
75
75
|
fs.writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
76
|
-
console.log('[setu] Registered the approval-detection hook in .claude/settings.json');
|
|
76
|
+
console.log('[cli-setu] Registered the approval-detection hook in .claude/settings.json');
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
package/src/pair.js
CHANGED
|
@@ -11,18 +11,19 @@ async function pair(authServer, authServerPublic) {
|
|
|
11
11
|
const config = loadOrCreateConfig();
|
|
12
12
|
|
|
13
13
|
if (config.deviceToken) {
|
|
14
|
-
console.log(`[setu] "${config.deviceName}" is already paired.`);
|
|
14
|
+
console.log(`[cli-setu] "${config.deviceName}" is already paired.`);
|
|
15
15
|
return config;
|
|
16
16
|
}
|
|
17
17
|
|
|
18
|
-
console.log(`[setu] Pairing as "${config.deviceName}"...`);
|
|
19
|
-
console.log('[setu] (This is your computer\'s name. Rename it in ~/.cli-setu/config.json before pairing if you want something else.)');
|
|
18
|
+
console.log(`[cli-setu] Pairing as "${config.deviceName}"...`);
|
|
19
|
+
console.log('[cli-setu] (This is your computer\'s name. Rename it in ~/.cli-setu/config.json before pairing if you want something else.)');
|
|
20
20
|
|
|
21
21
|
// qr-start also needs a sessionId up front (mirrors supervisor-qr.js's
|
|
22
22
|
// "the QR both pairs it AND jumps the phone straight to watching THIS
|
|
23
|
-
// session" behavior) - 'pairing' is a placeholder id here since
|
|
24
|
-
// pair` itself never streams a terminal; the real per-run
|
|
25
|
-
// generated fresh by supervisor.js on every `setu`
|
|
23
|
+
// session" behavior) - 'pairing' is a placeholder id here since
|
|
24
|
+
// `cli-setu pair` itself never streams a terminal; the real per-run
|
|
25
|
+
// session id is generated fresh by supervisor.js on every `cli-setu`
|
|
26
|
+
// (bare) invocation.
|
|
26
27
|
const startRes = await fetch(`${authServer}/device/pair/qr-start`, {
|
|
27
28
|
method: 'POST',
|
|
28
29
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -34,8 +35,8 @@ async function pair(authServer, authServerPublic) {
|
|
|
34
35
|
|
|
35
36
|
console.log('');
|
|
36
37
|
qrcode.generate(scanUrl, { small: true });
|
|
37
|
-
console.log('[setu] Scan this with your phone camera.');
|
|
38
|
-
console.log(`[setu] (Testing on one PC? Paste this URL into a browser tab instead: ${scanUrl})`);
|
|
38
|
+
console.log('[cli-setu] Scan this with your phone camera.');
|
|
39
|
+
console.log(`[cli-setu] (Testing on one PC? Paste this URL into a browser tab instead: ${scanUrl})`);
|
|
39
40
|
|
|
40
41
|
const codeRes = await fetch(`${authServer}/device/pair/start`, {
|
|
41
42
|
method: 'POST',
|
|
@@ -43,8 +44,8 @@ async function pair(authServer, authServerPublic) {
|
|
|
43
44
|
body: JSON.stringify({ deviceName: config.deviceName }),
|
|
44
45
|
});
|
|
45
46
|
const { code: typedCode, pairId: typedPairId } = await codeRes.json();
|
|
46
|
-
console.log(`[setu] Or type this code in the app's Devices tab: ${typedCode}`);
|
|
47
|
-
console.log('[setu] Waiting for scan or code entry...');
|
|
47
|
+
console.log(`[cli-setu] Or type this code in the app's Devices tab: ${typedCode}`);
|
|
48
|
+
console.log('[cli-setu] Waiting for scan or code entry...');
|
|
48
49
|
|
|
49
50
|
let confirmed = false;
|
|
50
51
|
while (!confirmed) {
|
|
@@ -56,13 +57,13 @@ async function pair(authServer, authServerPublic) {
|
|
|
56
57
|
confirmed = true;
|
|
57
58
|
config.deviceToken = status.deviceToken;
|
|
58
59
|
writeConfig(config);
|
|
59
|
-
console.log(`[setu] ✓ Paired via QR and saved to ~/.cli-setu/config.json`);
|
|
60
|
+
console.log(`[cli-setu] ✓ Paired via QR and saved to ~/.cli-setu/config.json`);
|
|
60
61
|
break;
|
|
61
62
|
} else if (status.status === 'EXPIRED') {
|
|
62
|
-
console.error('[setu] QR code expired. Run `setu pair` again to get a new one.');
|
|
63
|
+
console.error('[cli-setu] QR code expired. Run `cli-setu pair` again to get a new one.');
|
|
63
64
|
process.exit(1);
|
|
64
65
|
} else if (status.status === 'REJECTED') {
|
|
65
|
-
console.error(`[setu] Pairing rejected: ${status.rejectReason || 'the server declined this pairing.'}`);
|
|
66
|
+
console.error(`[cli-setu] Pairing rejected: ${status.rejectReason || 'the server declined this pairing.'}`);
|
|
66
67
|
process.exit(1);
|
|
67
68
|
}
|
|
68
69
|
|
|
@@ -72,7 +73,7 @@ async function pair(authServer, authServerPublic) {
|
|
|
72
73
|
confirmed = true;
|
|
73
74
|
config.deviceToken = typedStatus.deviceToken;
|
|
74
75
|
writeConfig(config);
|
|
75
|
-
console.log(`[setu] ✓ Paired via typed code and saved to ~/.cli-setu/config.json`);
|
|
76
|
+
console.log(`[cli-setu] ✓ Paired via typed code and saved to ~/.cli-setu/config.json`);
|
|
76
77
|
break;
|
|
77
78
|
}
|
|
78
79
|
}
|
package/src/status.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
// `setu status` - reports whether this computer is paired, and which
|
|
2
|
-
// sessions (if any) currently have a `setu` process running, using the
|
|
1
|
+
// `cli-setu status` - reports whether this computer is paired, and which
|
|
2
|
+
// sessions (if any) currently have a `cli-setu` process running, using the
|
|
3
3
|
// PID files supervisor.js writes/removes around its own lifetime (see
|
|
4
4
|
// its own comment on why - there was no way to answer this question at
|
|
5
5
|
// all before those existed).
|
|
@@ -21,10 +21,10 @@ function isProcessAlive(pid) {
|
|
|
21
21
|
async function status(authServer) {
|
|
22
22
|
const config = readConfig();
|
|
23
23
|
if (!config || !config.deviceToken) {
|
|
24
|
-
console.log('[setu] Not paired. Run `setu pair` to get started.');
|
|
24
|
+
console.log('[cli-setu] Not paired. Run `cli-setu pair` to get started.');
|
|
25
25
|
return;
|
|
26
26
|
}
|
|
27
|
-
console.log(`[setu] Paired as "${config.deviceName}".`);
|
|
27
|
+
console.log(`[cli-setu] Paired as "${config.deviceName}".`);
|
|
28
28
|
|
|
29
29
|
let files;
|
|
30
30
|
try {
|
|
@@ -52,11 +52,11 @@ async function status(authServer) {
|
|
|
52
52
|
}
|
|
53
53
|
|
|
54
54
|
if (running.length === 0) {
|
|
55
|
-
console.log('[setu] No sessions currently running. Run `setu` in a project folder to start one.');
|
|
55
|
+
console.log('[cli-setu] No sessions currently running. Run `cli-setu` in a project folder to start one.');
|
|
56
56
|
return;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
console.log(`[setu] ${running.length} session(s) running:`);
|
|
59
|
+
console.log(`[cli-setu] ${running.length} session(s) running:`);
|
|
60
60
|
for (const s of running) {
|
|
61
61
|
console.log(` - ${s.sessionId} · ${s.cwd} · started ${s.startedAt} (pid ${s.pid})`);
|
|
62
62
|
}
|
package/src/stop.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// `setu stop` - cleanly disconnects every session currently running on
|
|
1
|
+
// `cli-setu stop` - cleanly disconnects every session currently running on
|
|
2
2
|
// this computer. Real gap in the PoC this replaces: the only way to stop
|
|
3
3
|
// a supervisor was closing its terminal window (or Ctrl+C, which only
|
|
4
4
|
// reaches the one you're actually looking at) - this reaches every
|
|
@@ -15,7 +15,7 @@ async function stop() {
|
|
|
15
15
|
}
|
|
16
16
|
|
|
17
17
|
if (files.length === 0) {
|
|
18
|
-
console.log('[setu] No sessions currently running.');
|
|
18
|
+
console.log('[cli-setu] No sessions currently running.');
|
|
19
19
|
return;
|
|
20
20
|
}
|
|
21
21
|
|
|
@@ -35,7 +35,7 @@ async function stop() {
|
|
|
35
35
|
// PID file. A hard kill would skip all of that and leave the CLI
|
|
36
36
|
// process and the Azure connection to time out on their own.
|
|
37
37
|
process.kill(info.pid, 'SIGINT');
|
|
38
|
-
console.log(`[setu] Stopped ${info.sessionId} (${info.cwd})`);
|
|
38
|
+
console.log(`[cli-setu] Stopped ${info.sessionId} (${info.cwd})`);
|
|
39
39
|
stopped++;
|
|
40
40
|
} catch {
|
|
41
41
|
// Already dead - just clean up the stale file.
|
|
@@ -44,7 +44,7 @@ async function stop() {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
if (stopped === 0) {
|
|
47
|
-
console.log('[setu] Sessions were already stopped (stale state cleaned up).');
|
|
47
|
+
console.log('[cli-setu] Sessions were already stopped (stale state cleaned up).');
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
package/src/supervisor.js
CHANGED
|
@@ -74,24 +74,27 @@ function log(...args) {
|
|
|
74
74
|
}
|
|
75
75
|
|
|
76
76
|
// Real config, from pairing (src/pair.js, either via bin/setu.js's own
|
|
77
|
-
// bare-`setu` pairing check or the explicit `setu pair` command) -
|
|
78
|
-
// argv. bin/setu.js already guarantees this exists before requiring
|
|
79
|
-
// file for a normal `setu` run; this is a defensive fallback for
|
|
80
|
-
// requiring supervisor.js directly, so a null deviceToken fails
|
|
81
|
-
// clear message instead of a confusing crash deep in connectToAzure().
|
|
77
|
+
// bare-`cli-setu` pairing check or the explicit `cli-setu pair` command) -
|
|
78
|
+
// not argv. bin/setu.js already guarantees this exists before requiring
|
|
79
|
+
// this file for a normal `cli-setu` run; this is a defensive fallback for
|
|
80
|
+
// anyone requiring supervisor.js directly, so a null deviceToken fails
|
|
81
|
+
// with a clear message instead of a confusing crash deep in connectToAzure().
|
|
82
82
|
const config = readConfig();
|
|
83
83
|
if (!config || !config.deviceToken) {
|
|
84
|
-
console.error('[setu] This computer isn\'t paired yet. Run `setu` again, or run `setu pair` directly.');
|
|
84
|
+
console.error('[cli-setu] This computer isn\'t paired yet. Run `cli-setu` again, or run `cli-setu pair` directly.');
|
|
85
85
|
process.exit(1);
|
|
86
86
|
}
|
|
87
87
|
const DEVICE_NAME = config.deviceName;
|
|
88
88
|
|
|
89
|
-
|
|
89
|
+
// TEMPORARY: defaults to the DEV server, not production - see bin/setu.js's
|
|
90
|
+
// matching comment. Must switch back to https://api.clisetu.com before
|
|
91
|
+
// treating this package as production-ready for real users.
|
|
92
|
+
const AUTH_SERVER = process.env.CLI_SETU_SERVER || 'https://dev-api.clisetu.com';
|
|
90
93
|
|
|
91
|
-
// --cli still supported, e.g. `setu --cli codex`, for the same reason it
|
|
94
|
+
// --cli still supported, e.g. `cli-setu --cli codex`, for the same reason it
|
|
92
95
|
// existed before: one paired device can run more than one kind of CLI
|
|
93
96
|
// across different sessions/folders. Real product decision (confirmed
|
|
94
|
-
// directly by the PM): bare `setu` with no --cli flag bridges the user's
|
|
97
|
+
// directly by the PM): bare `cli-setu` with no --cli flag bridges the user's
|
|
95
98
|
// own plain terminal (see cli-adapters/shell.js), not Claude Code by
|
|
96
99
|
// default - the user decides what to run once it's open, same as
|
|
97
100
|
// getAdapter's own default (index.js) - kept in sync here rather than
|
|
@@ -105,7 +108,7 @@ const WORKING_DIR = process.cwd();
|
|
|
105
108
|
// plus the real working directory (not just the folder's basename, which
|
|
106
109
|
// collides the moment two different projects share a folder name like
|
|
107
110
|
// "app" on the same machine) plus a short random suffix so re-running
|
|
108
|
-
// `setu` in the same folder twice at once (e.g. two terminal tabs) never
|
|
111
|
+
// `cli-setu` in the same folder twice at once (e.g. two terminal tabs) never
|
|
109
112
|
// silently shares one session.
|
|
110
113
|
const dirHash = crypto.createHash('sha1').update(WORKING_DIR).digest('hex').slice(0, 8);
|
|
111
114
|
const SESSION_ID = `${os.hostname()}-${dirHash}-${crypto.randomBytes(3).toString('hex')}`;
|
|
@@ -121,7 +124,7 @@ console.log(`[supervisor] Using CLI adapter: ${adapter.displayName} (${adapter.i
|
|
|
121
124
|
log(`Using CLI adapter: ${adapter.displayName} (${adapter.id})`);
|
|
122
125
|
|
|
123
126
|
// Real bug found by testing: when the spawned adapter is 'shell' (the
|
|
124
|
-
// bare-`setu` default - see cli-adapters/shell.js), the user is expected
|
|
127
|
+
// bare-`cli-setu` default - see cli-adapters/shell.js), the user is expected
|
|
125
128
|
// to freely run `claude` INSIDE that bridged shell whenever they want to.
|
|
126
129
|
// Gating hook registration on "is the spawn-time adapter Claude" (as this
|
|
127
130
|
// used to) meant Claude Code's hooks never got installed into
|
|
@@ -141,21 +144,21 @@ const PROCESSED_FILE = path.join(CONFIG_DIR, `processed-requests.${SESSION_ID}.j
|
|
|
141
144
|
const POLL_INTERVAL_MS = 300;
|
|
142
145
|
|
|
143
146
|
// Always registered now (see QUEUE_FILE's comment above) - covers both
|
|
144
|
-
// `setu --cli claude` (adapter itself is Claude) and bare `setu` /
|
|
145
|
-
// `setu --cli shell` followed by the user manually running `claude`
|
|
147
|
+
// `cli-setu --cli claude` (adapter itself is Claude) and bare `cli-setu` /
|
|
148
|
+
// `cli-setu --cli shell` followed by the user manually running `claude`
|
|
146
149
|
// inside the bridged shell.
|
|
147
150
|
{
|
|
148
151
|
const { ensureHooksRegistered } = require('./hooks');
|
|
149
152
|
ensureHooksRegistered(WORKING_DIR);
|
|
150
153
|
}
|
|
151
154
|
|
|
152
|
-
// Real config, from `setu pair` (src/config.js) - not a per-device-name
|
|
153
|
-
// token file. Pairing is now a separate, one-time command (`setu pair`)
|
|
155
|
+
// Real config, from `cli-setu pair` (src/config.js) - not a per-device-name
|
|
156
|
+
// token file. Pairing is now a separate, one-time command (`cli-setu pair`)
|
|
154
157
|
// that must already have succeeded before this ever runs (checked above,
|
|
155
158
|
// where the process exits early if config.deviceToken is missing) - so
|
|
156
159
|
// unlike the PoC's ensurePaired(), there is no QR-pairing fallback here at
|
|
157
160
|
// all. A session watcher's job is to watch a session, not to also be the
|
|
158
|
-
// pairing flow; keeping them separate is what makes `setu` (bare) not
|
|
161
|
+
// pairing flow; keeping them separate is what makes `cli-setu` (bare) not
|
|
159
162
|
// need a QR code/camera every single run.
|
|
160
163
|
let deviceToken = config.deviceToken;
|
|
161
164
|
let deviceId = null;
|
|
@@ -585,7 +588,7 @@ function handleAzureDecision(msg) {
|
|
|
585
588
|
// right of the actual PTY content - not a phone-side rendering bug at
|
|
586
589
|
// all, a genuine laptop-side geometry mismatch. process.stdout.columns/
|
|
587
590
|
// rows reflect the REAL terminal's actual current size at the moment
|
|
588
|
-
// `setu` starts (falling back to the old 120x30 only if those aren't
|
|
591
|
+
// `cli-setu` starts (falling back to the old 120x30 only if those aren't
|
|
589
592
|
// available - e.g. output piped to a file, not a real TTY). Still a
|
|
590
593
|
// FIXED size after this point, same reasoning as before (not read back
|
|
591
594
|
// off ptyProcess after spawn, never resized again - see the
|
|
@@ -1236,8 +1239,8 @@ async function main() {
|
|
|
1236
1239
|
process.stdin.resume();
|
|
1237
1240
|
process.stdin.on('data', (data) => ptyProcess.write(data.toString()));
|
|
1238
1241
|
|
|
1239
|
-
// Real gap in the PoC this replaces: there was no way for `setu status`
|
|
1240
|
-
// or `setu stop` (both new - see src/status.js, src/stop.js) to know
|
|
1242
|
+
// Real gap in the PoC this replaces: there was no way for `cli-setu status`
|
|
1243
|
+
// or `cli-setu stop` (both new - see src/status.js, src/stop.js) to know
|
|
1241
1244
|
// whether a session watcher was even running, or on which PID, since
|
|
1242
1245
|
// supervisor-qr.js was always started and killed by hand in a visible
|
|
1243
1246
|
// terminal. One small PID file per running session (keyed by
|
package/src/update.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
// `setu --update` - checks the real npm registry for a newer published
|
|
1
|
+
// `cli-setu --update` - checks the real npm registry for a newer published
|
|
2
2
|
// version, and if one exists, runs the real upgrade command on the
|
|
3
3
|
// user's behalf (confirmed directly: don't just tell them what to run,
|
|
4
4
|
// actually run it) so they don't have to remember/type
|
|
@@ -35,24 +35,24 @@ function isNewer(latest, current) {
|
|
|
35
35
|
}
|
|
36
36
|
|
|
37
37
|
async function update() {
|
|
38
|
-
console.log(`[setu] Current version: ${pkg.version}`);
|
|
39
|
-
console.log('[setu] Checking for updates...');
|
|
38
|
+
console.log(`[cli-setu] Current version: ${pkg.version}`);
|
|
39
|
+
console.log('[cli-setu] Checking for updates...');
|
|
40
40
|
|
|
41
41
|
let latest;
|
|
42
42
|
try {
|
|
43
43
|
latest = await fetchLatestVersion();
|
|
44
44
|
} catch (err) {
|
|
45
|
-
console.error(`[setu] Could not check for updates: ${err.message}`);
|
|
45
|
+
console.error(`[cli-setu] Could not check for updates: ${err.message}`);
|
|
46
46
|
process.exit(1);
|
|
47
47
|
}
|
|
48
48
|
|
|
49
49
|
if (!isNewer(latest, pkg.version)) {
|
|
50
|
-
console.log(`[setu] Already on the latest version (${pkg.version}).`);
|
|
50
|
+
console.log(`[cli-setu] Already on the latest version (${pkg.version}).`);
|
|
51
51
|
return;
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
-
console.log(`[setu] A newer version is available: ${latest} (you have ${pkg.version}).`);
|
|
55
|
-
console.log(`[setu] Installing ${pkg.name}@${latest}...`);
|
|
54
|
+
console.log(`[cli-setu] A newer version is available: ${latest} (you have ${pkg.version}).`);
|
|
55
|
+
console.log(`[cli-setu] Installing ${pkg.name}@${latest}...`);
|
|
56
56
|
try {
|
|
57
57
|
// execFile (not exec) - no shell involved, consistent with this
|
|
58
58
|
// project's own established convention for anything that runs a
|
|
@@ -62,10 +62,10 @@ async function update() {
|
|
|
62
62
|
shell: process.platform === 'win32', // npm.cmd on Windows needs a shell to resolve; execFile alone can't find it otherwise
|
|
63
63
|
});
|
|
64
64
|
if (stdout) console.log(stdout.trim());
|
|
65
|
-
console.log(`[setu] ✓ Updated to ${latest}.`);
|
|
65
|
+
console.log(`[cli-setu] ✓ Updated to ${latest}.`);
|
|
66
66
|
} catch (err) {
|
|
67
|
-
console.error(`[setu] Update failed: ${err.message}`);
|
|
68
|
-
console.error(`[setu] You can try running it yourself: npm install -g ${pkg.name}@${latest}`);
|
|
67
|
+
console.error(`[cli-setu] Update failed: ${err.message}`);
|
|
68
|
+
console.error(`[cli-setu] You can try running it yourself: npm install -g ${pkg.name}@${latest}`);
|
|
69
69
|
process.exit(1);
|
|
70
70
|
}
|
|
71
71
|
}
|