@factadev/cli 0.2.6 → 0.2.8

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 +59 -107
  2. package/bin/nest.cjs +70 -122
  3. package/package.json +20 -7
package/README.md CHANGED
@@ -1,145 +1,97 @@
1
- # nest CLI
1
+ # NEST CLI
2
2
 
3
- Run Claude Code, Codex, Cursor Agent, Gemini, or OpenCode sessions from your terminal and control them remotely through the NEST hub.
3
+ Run Claude Code, Codex, Cursor Agent, Gemini, or OpenCode in your terminal and control sessions remotely through the NEST server—from a browser, PWA, or Telegram.
4
4
 
5
5
  ## What it does
6
6
 
7
- - Starts Claude Code sessions and registers them with nest-hub.
8
- - Starts Codex mode for OpenAI-based sessions.
9
- - Starts Cursor Agent mode for Cursor CLI sessions.
10
- - Starts Gemini mode via ACP (Anthropic Code Plugins).
11
- - Starts OpenCode mode via ACP and its plugin hook system.
12
- - Provides an MCP stdio bridge for external tools.
13
- - Manages a background runner for long-running sessions.
14
- - Includes diagnostics and auth helpers.
7
+ - **Unified AI coding** — Start and manage Claude Code, Codex, Cursor Agent, Gemini, and OpenCode from one CLI. Sessions sync with the NEST server for remote access.
8
+ - **Remote control** Monitor and steer sessions from the web app or Telegram Mini App. Approve permissions, send messages, and run commands from your phone.
9
+ - **Background worker** Run a worker so sessions can be started remotely without keeping a terminal open. Your machine stays available in the NEST dashboard.
10
+ - **MCP bridge** Expose tools to external clients via the MCP stdio bridge.
11
+ - **Diagnostics and auth** Check connectivity, token, and agent setup with `nest diagnose`. Manage credentials with `nest auth login` / `logout`.
15
12
 
16
- ## Typical flow
13
+ ## Quick start
17
14
 
18
- 1. Start the hub and set env vars (see ../hub/README.md).
19
- 2. Set the same CLI_API_TOKEN on this machine or run `nest auth login`.
20
- 3. Run `nest` to start a session.
21
- 4. Use the web app or Telegram Mini App to monitor and control.
15
+ 1. Start the NEST server and set `CLI_API_TOKEN` (see server docs).
16
+ 2. On this machine: set the same `CLI_API_TOKEN` or run `nest auth login`.
17
+ 3. Run `nest` to start a Claude Code session.
18
+ 4. Open the web app or Telegram Mini App to monitor and control.
22
19
 
23
20
  ## Commands
24
21
 
25
- ### Session commands
22
+ ### Sessions
26
23
 
27
- - `nest` - Start a Claude Code session (passes through Claude CLI flags). See `src/index.ts`.
28
- - `nest codex` - Start Codex mode. See `src/codex/runCodex.ts`.
29
- - `nest codex resume <sessionId>` - Resume existing Codex session.
30
- - `nest cursor` - Start Cursor Agent mode. See `src/cursor/runCursor.ts`.
31
- Supports `nest cursor resume <chatId>`, `nest cursor --continue`, `--mode plan|ask`, `--yolo`, `--model`.
32
- Local and remote modes supported; remote uses `agent -p` with stream-json.
33
- - `nest gemini` - Start Gemini mode via ACP. See `src/agent/runners/runAgentSession.ts`.
34
- Note: Gemini runs in remote mode only; it waits for messages from the hub UI/Telegram.
35
- - `nest opencode` - Start OpenCode mode via ACP. See `src/opencode/runOpencode.ts`.
36
- Note: OpenCode supports local and remote modes; local mode streams via OpenCode plugins.
24
+ - `nest` Start a Claude Code session (forwards Claude CLI flags).
25
+ - `nest codex` Codex mode (OpenAI). Use `nest codex resume <sessionId>` to resume.
26
+ - `nest cursor` — Cursor Agent mode. Supports resume, `--continue`, `--mode plan|ask`, `--yolo`, `--model`. Local and remote.
27
+ - `nest gemini` Gemini via ACP (remote mode; receives messages from server UI/Telegram).
28
+ - `nest opencode` OpenCode via ACP. Local and remote modes.
37
29
 
38
- ### Authentication
30
+ ### Auth
39
31
 
40
- - `nest auth status` - Show authentication configuration and token source.
41
- - `nest auth login` - Interactively enter and save CLI_API_TOKEN.
42
- - `nest auth logout` - Clear saved credentials.
32
+ - `nest auth status` Show auth config and token source.
33
+ - `nest auth login` Save `CLI_API_TOKEN` interactively.
34
+ - `nest auth logout` Clear saved credentials.
43
35
 
44
- See `src/commands/auth.ts`.
36
+ ### Worker
45
37
 
46
- ### Worker management
47
-
48
- - `nest worker start` - Start worker as detached process.
49
- - `nest worker stop` - Stop worker gracefully.
50
- - `nest worker status` - Show worker diagnostics.
51
- - `nest worker list` - List active sessions managed by worker.
52
- - `nest worker stop-session <sessionId>` - Terminate specific session.
53
- - `nest worker logs` - Print path to latest worker log file.
54
-
55
- See `src/runner/run.ts`.
56
-
57
- ### Diagnostics
58
-
59
- - `nest diagnose` - Show full diagnostics (version, worker status, logs, processes).
60
- - `nest diagnose clean` - Kill runaway NEST processes.
61
-
62
- See `src/ui/doctor.ts`.
38
+ - `nest worker start` — Start worker (detached).
39
+ - `nest worker stop` — Stop worker.
40
+ - `nest worker status` Worker diagnostics.
41
+ - `nest worker list` Active sessions.
42
+ - `nest worker stop-session <sessionId>` End a session.
43
+ - `nest worker logs` Path to latest worker log.
63
44
 
64
45
  ### Other
65
46
 
66
- - `nest mcp` - Start MCP stdio bridge. See `src/codex/happyMcpStdioBridge.ts`.
67
- - `nest server` - Start the bundled server (single binary workflow).
47
+ - `nest diagnose` Full diagnostics (version, worker, logs, processes).
48
+ - `nest diagnose clean` Kill runaway NEST processes.
49
+ - `nest mcp` — Start MCP stdio bridge.
50
+ - `nest server` — Start the bundled server (single-binary workflow).
68
51
 
69
52
  ## Configuration
70
53
 
71
- See `src/configuration.ts` for all options.
72
-
73
- ### Required
54
+ **Required**
74
55
 
75
- - `CLI_API_TOKEN` - Shared secret; must match the server. Can be set via env or `~/.nest/settings.json` (env wins).
76
- - `NEST_API_URL` - Server base URL (default: http://localhost:3006).
56
+ - `CLI_API_TOKEN` Shared secret; must match the server. Env or `~/.nest/settings.json` (env wins).
57
+ - `NEST_API_URL` Server URL (default: `http://localhost:3006`).
77
58
 
78
- ### Optional
59
+ **Optional**
79
60
 
80
- - `NEST_HOME` - Config/data directory (default: ~/.nest).
81
- - `NEST_EXPERIMENTAL` - Enable experimental features (true/1/yes).
82
- - `NEST_CLAUDE_PATH` - Path to a specific `claude` executable.
83
- - `NEST_HTTP_MCP_URL` - Default MCP target for `nest mcp`.
61
+ - `NEST_HOME` Config directory (default: `~/.nest`).
62
+ - `NEST_EXPERIMENTAL` Enable experimental features (`true` / `1` / `yes`).
63
+ - `NEST_CLAUDE_PATH` Path to `claude` executable.
64
+ - `NEST_HTTP_MCP_URL` Default MCP target for `nest mcp`.
84
65
 
85
- ### Runner
66
+ **Worker**
86
67
 
87
- - `NEST_RUNNER_HEARTBEAT_INTERVAL` - Heartbeat interval in ms (default: 60000).
88
- - `NEST_RUNNER_HTTP_TIMEOUT` - HTTP timeout for runner control in ms (default: 10000).
68
+ - `NEST_RUNNER_HEARTBEAT_INTERVAL` Heartbeat ms (default: 60000).
69
+ - `NEST_RUNNER_HTTP_TIMEOUT` HTTP timeout for worker control ms (default: 10000).
89
70
 
90
- ### Worktree (set by runner)
71
+ **Worktree** (set by worker when spawning in a worktree)
91
72
 
92
- - `NEST_WORKTREE_BASE_PATH` - Base repository path.
93
- - `NEST_WORKTREE_BRANCH` - Current branch name.
94
- - `NEST_WORKTREE_NAME` - Worktree name.
95
- - `NEST_WORKTREE_PATH` - Full worktree path.
96
- - `NEST_WORKTREE_CREATED_AT` - Creation timestamp (ms).
73
+ - `NEST_WORKTREE_BASE_PATH`, `NEST_WORKTREE_BRANCH`, `NEST_WORKTREE_NAME`, `NEST_WORKTREE_PATH`, `NEST_WORKTREE_CREATED_AT`.
97
74
 
98
75
  ## Storage
99
76
 
100
- Data is stored in `~/.nest/` (or `$NEST_HOME`):
77
+ Under `~/.nest/` (or `$NEST_HOME`):
101
78
 
102
- - `settings.json` - User settings (machineId, token, onboarding flag). See `src/persistence.ts`.
103
- - `runner.state.json` - Runner state (pid, port, version, heartbeat).
104
- - `logs/` - Log files.
79
+ - `settings.json` Machine id, token, onboarding.
80
+ - `runner.state.json` Worker state (pid, port, version, heartbeat).
81
+ - `logs/` Log files.
105
82
 
106
83
  ## Requirements
107
84
 
108
- - Claude CLI installed and logged in (`claude` on PATH).
109
- - Cursor Agent CLI installed (`agent` on PATH) for `nest cursor`. Install: `curl https://cursor.com/install -fsS | bash` (macOS/Linux), `irm 'https://cursor.com/install?win32=true' | iex` (Windows).
110
- - OpenCode CLI installed (`opencode` on PATH).
111
- - Bun for building from source.
112
-
113
- ## Build from source
114
-
115
- From the repo root:
116
-
117
- ```bash
118
- bun install
119
- bun run build:cli
120
- bun run build:cli:exe
121
- ```
122
-
123
- For an all-in-one binary that also embeds the web app:
124
-
125
- ```bash
126
- bun run build:single-exe
127
- ```
85
+ - Claude CLI on PATH (for `nest`).
86
+ - Cursor Agent CLI on PATH for `nest cursor`: `curl https://cursor.com/install -fsS | bash` (macOS/Linux), or Windows install from Cursor.
87
+ - OpenCode CLI on PATH for `nest opencode`.
128
88
 
129
- ## Source structure
89
+ ## License
130
90
 
131
- - `src/api/` - Bot communication (Socket.IO + REST).
132
- - `src/claude/` - Claude Code integration.
133
- - `src/codex/` - Codex mode integration.
134
- - `src/cursor/` - Cursor Agent integration.
135
- - `src/agent/` - Multi-agent support (Gemini via ACP).
136
- - `src/opencode/` - OpenCode ACP + hook integration.
137
- - `src/runner/` - Background service.
138
- - `src/commands/` - CLI command handlers.
139
- - `src/ui/` - User interface and diagnostics.
140
- - `src/modules/` - Tool implementations (ripgrep, difftastic, git).
91
+ AGPL-3.0-only. See [LICENSE](https://github.com/Facta-Dev/ctx0_nest_terminal/blob/main/LICENSE) in the repository.
141
92
 
142
- ## Related docs
93
+ ## Links
143
94
 
144
- - `../hub/README.md`
145
- - `../web/README.md`
95
+ - [Server and setup](https://github.com/Facta-Dev/ctx0_nest_terminal)
96
+ - [Web app](https://github.com/Facta-Dev/ctx0_nest_terminal)
97
+ - [Issues](https://github.com/Facta-Dev/ctx0_nest_terminal/issues)
package/bin/nest.cjs CHANGED
@@ -1,46 +1,30 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const { execFileSync } = require('child_process');
3
+ const { execFileSync, execSync } = require('child_process');
4
4
  const path = require('path');
5
+ const fs = require('fs');
5
6
 
6
7
  const platform = process.platform;
7
8
  const arch = process.arch;
8
- const RELEASE_URL = 'https://github.com/ctx0/nest/releases';
9
- const OFFICIAL_NPM_REGISTRY = 'https://registry.npmjs.org';
9
+ const RELEASE_URL = 'https://github.com/Facta-Dev/ctx0_nest/releases';
10
10
  const SUPPORTED_PLATFORMS = [
11
- {
12
- key: 'darwin-arm64',
13
- label: 'darwin-arm64 (macOS Apple Silicon)',
14
- },
15
- {
16
- key: 'darwin-x64',
17
- label: 'darwin-x64 (macOS Intel)',
18
- },
19
- {
20
- key: 'linux-arm64',
21
- label: 'linux-arm64',
22
- },
23
- {
24
- key: 'linux-x64',
25
- label: 'linux-x64',
26
- },
27
- {
28
- key: 'win32-x64',
29
- label: 'win32-x64',
30
- },
11
+ { key: 'darwin-arm64', label: 'darwin-arm64 (macOS Apple Silicon)' },
12
+ { key: 'darwin-x64', label: 'darwin-x64 (macOS Intel)' },
13
+ { key: 'linux-arm64', label: 'linux-arm64' },
14
+ { key: 'linux-x64', label: 'linux-x64' },
15
+ { key: 'win32-x64', label: 'win32-x64' },
31
16
  ];
32
17
 
33
- function getPlatformKey(platformName = platform, archName = arch) {
34
- return `${platformName}-${archName}`;
18
+ function getPlatformKey(p = platform, a = arch) {
19
+ return `${p}-${a}`;
35
20
  }
36
21
 
37
- function isSupportedPlatform(platformName = platform, archName = arch) {
38
- return SUPPORTED_PLATFORMS.some((item) => item.key === getPlatformKey(platformName, archName));
22
+ function isSupportedPlatform(p = platform, a = arch) {
23
+ return SUPPORTED_PLATFORMS.some(item => item.key === getPlatformKey(p, a));
39
24
  }
40
25
 
41
26
  function getBinaryPath(platformName = platform, archName = arch) {
42
27
  const pkgName = `@factadev/cli-${platformName}-${archName}`;
43
-
44
28
  try {
45
29
  const pkgPath = require.resolve(`${pkgName}/package.json`);
46
30
  const binName = platformName === 'win32' ? 'nest.exe' : 'nest';
@@ -50,6 +34,38 @@ function getBinaryPath(platformName = platform, archName = arch) {
50
34
  }
51
35
  }
52
36
 
37
+ function installPlatformPackage(platformName = platform, archName = arch) {
38
+ const pkgName = `@factadev/cli-${platformName}-${archName}`;
39
+ console.log(`Installing ${pkgName}...`);
40
+ try {
41
+ execSync(`npm install -g ${pkgName}`, { stdio: 'inherit' });
42
+ return true;
43
+ } catch (e) {
44
+ return false;
45
+ }
46
+ }
47
+
48
+ function getInstalledVersion(platformName = platform, archName = arch) {
49
+ const pkgName = `@factadev/cli-${platformName}-${archName}`;
50
+ try {
51
+ const pkgPath = require.resolve(`${pkgName}/package.json`);
52
+ const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
53
+ return pkg.version;
54
+ } catch (e) {
55
+ return null;
56
+ }
57
+ }
58
+
59
+ function getLatestVersion(platformName = platform, archName = arch) {
60
+ const pkgName = `@factadev/cli-${platformName}-${archName}`;
61
+ try {
62
+ const result = execSync(`npm view ${pkgName} version`, { encoding: 'utf8' });
63
+ return result.trim();
64
+ } catch (e) {
65
+ return null;
66
+ }
67
+ }
68
+
53
69
  function getBunPath() {
54
70
  const bunPaths = [
55
71
  path.join(__dirname, '..', 'node_modules', '.bin', 'bun'),
@@ -58,124 +74,56 @@ function getBunPath() {
58
74
  '/usr/local/bin/bun',
59
75
  '/opt/homebrew/bin/bun',
60
76
  ];
61
-
62
77
  for (const p of bunPaths) {
63
- try {
64
- require('fs').accessSync(p, require('fs').constants.X_OK);
65
- return p;
66
- } catch {}
78
+ try { fs.accessSync(p, fs.constants.X_OK); return p; } catch {}
67
79
  }
68
-
69
80
  return 'bun';
70
81
  }
71
82
 
72
- function formatCommand(binPath, args) {
73
- return [binPath, ...args].map((arg) => JSON.stringify(String(arg))).join(' ');
74
- }
75
-
76
- function normalizeExecError(error) {
77
- return {
78
- status: typeof error?.status === 'number' ? error.status : null,
79
- signal: typeof error?.signal === 'string' ? error.signal : null,
80
- message: error?.message ? String(error.message) : null,
81
- };
82
- }
83
-
84
- function reportExecutionFailure(error, binPath, args, log = console.error) {
85
- const { status, signal, message } = normalizeExecError(error);
86
-
87
- log(`Failed to execute: ${formatCommand(binPath, args)}`);
88
-
89
- if (signal) {
90
- log(`Binary terminated by signal ${signal}.`);
91
- }
92
-
93
- if (status !== null) {
94
- log(`Binary exited with status ${status}.`);
95
- }
96
-
97
- if (message) {
98
- log(message);
99
- }
100
-
101
- return { status, signal };
102
- }
103
-
104
- function reportUnsupportedPlatform(platformName = platform, archName = arch, log = console.error) {
105
- log(`Unsupported platform: ${platformName}-${archName}`);
106
- log('');
107
- log('Supported platforms:');
108
- for (const item of SUPPORTED_PLATFORMS) {
109
- log(` - ${item.label}`);
110
- }
111
- log('');
112
- log('You can download the binary manually from:');
113
- log(` ${RELEASE_URL}`);
114
- }
115
-
116
- function reportMissingPlatformPackage(platformName = platform, archName = arch, log = console.error) {
117
- const platformPackage = `@factadev/cli-${platformName}-${archName}`;
118
- log(`Missing platform package: ${platformPackage}`);
119
- log('');
120
- log(`Detected platform ${platformName}-${archName} is supported, but the platform binary package was not installed.`);
121
- log('The CLI will attempt to fall back to using bun to run directly.');
122
- log('');
123
- log('To ensure fastest startup, try reinstalling with the official npm registry:');
124
- log(` npm install -g @factadev/cli --registry=${OFFICIAL_NPM_REGISTRY}`);
125
- log('');
126
- log('Or install bun and the CLI will use it as fallback:');
127
- log(' curl -fsSL https://bun.sh/install | bash');
128
- log('');
129
- log('You can also download binaries manually from:');
130
- log(` ${RELEASE_URL}`);
131
- }
132
-
133
83
  function main() {
134
84
  if (!isSupportedPlatform()) {
135
- reportUnsupportedPlatform();
85
+ console.error(`Unsupported platform: ${platform}-${arch}`);
136
86
  process.exit(1);
137
87
  }
138
88
 
89
+ const platformKey = getPlatformKey();
139
90
  let binPath = getBinaryPath();
140
- let useBun = !binPath;
141
91
 
142
- if (useBun) {
92
+ // Check if platform package needs update or install
93
+ if (!binPath) {
94
+ console.log('No platform binary found. Installing...');
95
+ installPlatformPackage();
96
+ binPath = getBinaryPath();
97
+ } else {
98
+ // Check version and update if needed
99
+ const currentVer = getInstalledVersion();
100
+ const latestVer = getLatestVersion();
101
+ if (currentVer && latestVer && currentVer !== latestVer) {
102
+ console.log(`Updating from v${currentVer} to v${latestVer}...`);
103
+ installPlatformPackage();
104
+ binPath = getBinaryPath();
105
+ }
106
+ }
107
+
108
+ // Fallback to bun if no binary
109
+ if (!binPath) {
143
110
  const bunPath = getBunPath();
144
111
  const cliPath = path.join(__dirname, '..', 'src', 'index.ts');
145
- console.log('No pre-built binary for this platform. Using bun to run CLI...\n');
146
-
112
+ console.log('No pre-built binary. Using bun...\n');
147
113
  try {
148
- execFileSync(bunPath, [cliPath, ...process.argv.slice(2)], {
149
- stdio: 'inherit',
150
- env: {
151
- ...process.env,
152
- npm_lifecycle_event: 'nest',
153
- npm_package_name: '@factadev/cli',
154
- },
155
- });
114
+ execFileSync(bunPath, [cliPath, ...process.argv.slice(2)], { stdio: 'inherit' });
156
115
  return;
157
116
  } catch (error) {
158
117
  console.error(`Failed to run with bun: ${error.message}`);
159
- console.error('\nPlease install bun:');
160
- console.error(' curl -fsSL https://bun.sh/install | bash');
161
118
  process.exit(1);
162
119
  }
163
120
  }
164
121
 
165
- const args = process.argv.slice(2);
166
-
122
+ // Run the binary
167
123
  try {
168
- execFileSync(binPath, args, {
169
- stdio: 'inherit',
170
- env: {
171
- ...process.env,
172
- npm_lifecycle_event: 'nest',
173
- npm_package_name: '@factadev/cli',
174
- },
175
- });
124
+ execFileSync(binPath, process.argv.slice(2), { stdio: 'inherit' });
176
125
  } catch (error) {
177
- const { status, signal } = reportExecutionFailure(error, binPath, args);
178
- process.exit(status ?? (signal ? 1 : 1));
126
+ process.exit(error.status || 1);
179
127
  }
180
128
  }
181
129
 
package/package.json CHANGED
@@ -1,9 +1,22 @@
1
1
  {
2
2
  "name": "@factadev/cli",
3
- "version": "0.2.6",
3
+ "version": "0.2.8",
4
4
  "description": "NEST CLI - Enterprise AI coding agent control center. Run Claude Code, Codex, Cursor, Gemini, OpenCode locally and control remotely via web.",
5
5
  "author": "Carlos Matias Baglieri",
6
- "license": "UNLICENSED",
6
+ "license": "AGPL-3.0-only",
7
+ "keywords": [
8
+ "nest",
9
+ "claude",
10
+ "codex",
11
+ "cursor",
12
+ "gemini",
13
+ "opencode",
14
+ "ai",
15
+ "coding",
16
+ "agent",
17
+ "remote",
18
+ "cli"
19
+ ],
7
20
  "type": "module",
8
21
  "homepage": "https://github.com/Facta-Dev/ctx0_nest_terminal",
9
22
  "bugs": "https://github.com/Facta-Dev/ctx0_nest_terminal/issues",
@@ -77,10 +90,10 @@
77
90
  },
78
91
  "packageManager": "bun@1.3.5",
79
92
  "optionalDependencies": {
80
- "@factadev/cli-darwin-arm64": "0.2.6",
81
- "@factadev/cli-darwin-x64": "0.2.6",
82
- "@factadev/cli-linux-arm64": "0.2.6",
83
- "@factadev/cli-linux-x64": "0.2.6",
84
- "@factadev/cli-win32-x64": "0.2.6"
93
+ "@factadev/cli-darwin-arm64": "0.2.8",
94
+ "@factadev/cli-darwin-x64": "0.2.8",
95
+ "@factadev/cli-linux-arm64": "0.2.8",
96
+ "@factadev/cli-linux-x64": "0.2.8",
97
+ "@factadev/cli-win32-x64": "0.2.8"
85
98
  }
86
99
  }