@cmdctrl/cursor-cli 0.1.1

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 (57) hide show
  1. package/dist/adapter/cursor-cli.d.ts +36 -0
  2. package/dist/adapter/cursor-cli.d.ts.map +1 -0
  3. package/dist/adapter/cursor-cli.js +332 -0
  4. package/dist/adapter/cursor-cli.js.map +1 -0
  5. package/dist/adapter/events.d.ts +33 -0
  6. package/dist/adapter/events.d.ts.map +1 -0
  7. package/dist/adapter/events.js +53 -0
  8. package/dist/adapter/events.js.map +1 -0
  9. package/dist/client/messages.d.ts +50 -0
  10. package/dist/client/messages.d.ts.map +1 -0
  11. package/dist/client/messages.js +6 -0
  12. package/dist/client/messages.js.map +1 -0
  13. package/dist/client/websocket.d.ts +69 -0
  14. package/dist/client/websocket.d.ts.map +1 -0
  15. package/dist/client/websocket.js +272 -0
  16. package/dist/client/websocket.js.map +1 -0
  17. package/dist/commands/register.d.ts +10 -0
  18. package/dist/commands/register.d.ts.map +1 -0
  19. package/dist/commands/register.js +173 -0
  20. package/dist/commands/register.js.map +1 -0
  21. package/dist/commands/start.d.ts +9 -0
  22. package/dist/commands/start.d.ts.map +1 -0
  23. package/dist/commands/start.js +49 -0
  24. package/dist/commands/start.js.map +1 -0
  25. package/dist/commands/status.d.ts +5 -0
  26. package/dist/commands/status.d.ts.map +1 -0
  27. package/dist/commands/status.js +39 -0
  28. package/dist/commands/status.js.map +1 -0
  29. package/dist/commands/stop.d.ts +5 -0
  30. package/dist/commands/stop.d.ts.map +1 -0
  31. package/dist/commands/stop.js +42 -0
  32. package/dist/commands/stop.js.map +1 -0
  33. package/dist/commands/update.d.ts +2 -0
  34. package/dist/commands/update.d.ts.map +1 -0
  35. package/dist/commands/update.js +72 -0
  36. package/dist/commands/update.js.map +1 -0
  37. package/dist/config/config.d.ts +60 -0
  38. package/dist/config/config.d.ts.map +1 -0
  39. package/dist/config/config.js +176 -0
  40. package/dist/config/config.js.map +1 -0
  41. package/dist/index.d.ts +3 -0
  42. package/dist/index.d.ts.map +1 -0
  43. package/dist/index.js +50 -0
  44. package/dist/index.js.map +1 -0
  45. package/package.json +38 -0
  46. package/src/adapter/cursor-cli.ts +370 -0
  47. package/src/adapter/events.ts +77 -0
  48. package/src/client/messages.ts +75 -0
  49. package/src/client/websocket.ts +308 -0
  50. package/src/commands/register.ts +199 -0
  51. package/src/commands/start.ts +64 -0
  52. package/src/commands/status.ts +46 -0
  53. package/src/commands/stop.ts +47 -0
  54. package/src/commands/update.ts +73 -0
  55. package/src/config/config.ts +146 -0
  56. package/src/index.ts +56 -0
  57. package/tsconfig.json +19 -0
@@ -0,0 +1,73 @@
1
+ import { execSync } from 'child_process';
2
+ import { readFileSync } from 'fs';
3
+ import { join } from 'path';
4
+
5
+ // Get the current version from package.json
6
+ function getCurrentVersion(): string {
7
+ try {
8
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', '..', 'package.json'), 'utf-8'));
9
+ return pkg.version;
10
+ } catch {
11
+ try {
12
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
13
+ return pkg.version;
14
+ } catch {
15
+ return 'unknown';
16
+ }
17
+ }
18
+ }
19
+
20
+ // Fetch the latest version from npm registry
21
+ async function getLatestVersion(packageName: string): Promise<string | null> {
22
+ try {
23
+ const response = await fetch(`https://registry.npmjs.org/${packageName}/latest`);
24
+ if (!response.ok) return null;
25
+ const data = await response.json() as { version: string };
26
+ return data.version;
27
+ } catch {
28
+ return null;
29
+ }
30
+ }
31
+
32
+ export async function update(): Promise<void> {
33
+ const packageName = '@cmdctrl/cursor-cli';
34
+ const currentVersion = getCurrentVersion();
35
+
36
+ console.log(`Current version: ${currentVersion}`);
37
+ console.log(`Checking for updates...`);
38
+
39
+ const latestVersion = await getLatestVersion(packageName);
40
+
41
+ if (!latestVersion) {
42
+ console.error('Failed to check for updates. Check your internet connection.');
43
+ process.exit(1);
44
+ }
45
+
46
+ if (currentVersion === latestVersion) {
47
+ console.log(`Already up to date (v${currentVersion}).`);
48
+ return;
49
+ }
50
+
51
+ console.log(`Updating ${packageName}: v${currentVersion} → v${latestVersion}`);
52
+
53
+ try {
54
+ execSync(`npm install -g ${packageName}@latest`, {
55
+ stdio: 'inherit',
56
+ });
57
+ } catch {
58
+ console.error('\nUpdate failed. You may need to run with sudo:');
59
+ console.error(` sudo npm install -g ${packageName}@latest`);
60
+ process.exit(1);
61
+ }
62
+
63
+ // Verify the update
64
+ try {
65
+ const result = execSync(`cmdctrl-cursor-cli --version`, { encoding: 'utf-8' }).trim();
66
+ console.log(`\nUpdated successfully to v${result}`);
67
+ } catch {
68
+ console.log(`\nUpdate installed. Run 'cmdctrl-cursor-cli --version' to verify.`);
69
+ }
70
+
71
+ console.log('\nIf the daemon is running, restart it:');
72
+ console.log(' cmdctrl-cursor-cli stop && cmdctrl-cursor-cli start');
73
+ }
@@ -0,0 +1,146 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import * as os from 'os';
4
+
5
+ export interface CmdCtrlConfig {
6
+ serverUrl: string;
7
+ deviceId: string;
8
+ deviceName: string;
9
+ }
10
+
11
+ export interface Credentials {
12
+ accessToken: string;
13
+ refreshToken: string;
14
+ expiresAt: number; // Unix timestamp
15
+ }
16
+
17
+ const CONFIG_DIR = path.join(os.homedir(), '.cmdctrl-cursor-cli');
18
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
19
+ const CREDENTIALS_FILE = path.join(CONFIG_DIR, 'credentials');
20
+ const PID_FILE = path.join(CONFIG_DIR, 'daemon.pid');
21
+
22
+ /**
23
+ * Ensure the config directory exists with proper permissions
24
+ */
25
+ export function ensureConfigDir(): void {
26
+ if (!fs.existsSync(CONFIG_DIR)) {
27
+ fs.mkdirSync(CONFIG_DIR, { mode: 0o700 });
28
+ }
29
+ }
30
+
31
+ /**
32
+ * Read the config file
33
+ */
34
+ export function readConfig(): CmdCtrlConfig | null {
35
+ try {
36
+ if (!fs.existsSync(CONFIG_FILE)) {
37
+ return null;
38
+ }
39
+ const content = fs.readFileSync(CONFIG_FILE, 'utf-8');
40
+ return JSON.parse(content) as CmdCtrlConfig;
41
+ } catch {
42
+ return null;
43
+ }
44
+ }
45
+
46
+ /**
47
+ * Write the config file
48
+ */
49
+ export function writeConfig(config: CmdCtrlConfig): void {
50
+ ensureConfigDir();
51
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), { mode: 0o600 });
52
+ }
53
+
54
+ /**
55
+ * Read credentials (access/refresh tokens)
56
+ */
57
+ export function readCredentials(): Credentials | null {
58
+ try {
59
+ if (!fs.existsSync(CREDENTIALS_FILE)) {
60
+ return null;
61
+ }
62
+ const content = fs.readFileSync(CREDENTIALS_FILE, 'utf-8');
63
+ return JSON.parse(content) as Credentials;
64
+ } catch {
65
+ return null;
66
+ }
67
+ }
68
+
69
+ /**
70
+ * Write credentials with restrictive permissions (600)
71
+ */
72
+ export function writeCredentials(creds: Credentials): void {
73
+ ensureConfigDir();
74
+ fs.writeFileSync(CREDENTIALS_FILE, JSON.stringify(creds, null, 2), { mode: 0o600 });
75
+ }
76
+
77
+ /**
78
+ * Delete credentials (for logout/revoke)
79
+ */
80
+ export function deleteCredentials(): void {
81
+ if (fs.existsSync(CREDENTIALS_FILE)) {
82
+ fs.unlinkSync(CREDENTIALS_FILE);
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Check if device is registered
88
+ */
89
+ export function isRegistered(): boolean {
90
+ const config = readConfig();
91
+ const creds = readCredentials();
92
+ return config !== null && creds !== null && config.deviceId !== '';
93
+ }
94
+
95
+ /**
96
+ * Write daemon PID file
97
+ */
98
+ export function writePidFile(pid: number): void {
99
+ ensureConfigDir();
100
+ fs.writeFileSync(PID_FILE, pid.toString(), { mode: 0o600 });
101
+ }
102
+
103
+ /**
104
+ * Read daemon PID
105
+ */
106
+ export function readPidFile(): number | null {
107
+ try {
108
+ if (!fs.existsSync(PID_FILE)) {
109
+ return null;
110
+ }
111
+ const content = fs.readFileSync(PID_FILE, 'utf-8');
112
+ return parseInt(content, 10);
113
+ } catch {
114
+ return null;
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Delete PID file
120
+ */
121
+ export function deletePidFile(): void {
122
+ if (fs.existsSync(PID_FILE)) {
123
+ fs.unlinkSync(PID_FILE);
124
+ }
125
+ }
126
+
127
+ /**
128
+ * Check if daemon is running
129
+ */
130
+ export function isDaemonRunning(): boolean {
131
+ const pid = readPidFile();
132
+ if (pid === null) {
133
+ return false;
134
+ }
135
+ try {
136
+ // Signal 0 doesn't kill, just checks if process exists
137
+ process.kill(pid, 0);
138
+ return true;
139
+ } catch {
140
+ // Process doesn't exist, clean up stale PID file
141
+ deletePidFile();
142
+ return false;
143
+ }
144
+ }
145
+
146
+ export { CONFIG_DIR, CONFIG_FILE, CREDENTIALS_FILE, PID_FILE };
package/src/index.ts ADDED
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from 'commander';
4
+ import { readFileSync } from 'fs';
5
+ import { join } from 'path';
6
+ import { register } from './commands/register';
7
+ import { start } from './commands/start';
8
+ import { status } from './commands/status';
9
+ import { stop } from './commands/stop';
10
+ import { update } from './commands/update';
11
+
12
+ // Read version from package.json
13
+ let version = '0.0.0';
14
+ try {
15
+ const pkg = JSON.parse(readFileSync(join(__dirname, '..', 'package.json'), 'utf-8'));
16
+ version = pkg.version;
17
+ } catch {
18
+ // Fallback for development
19
+ }
20
+
21
+ const program = new Command();
22
+
23
+ program
24
+ .name('cmdctrl-cursor-cli')
25
+ .description('Cursor CLI daemon - connects your workstation to the CmdCtrl orchestration server')
26
+ .version(version);
27
+
28
+ program
29
+ .command('register')
30
+ .description('Register this device with a CmdCtrl server')
31
+ .option('-s, --server <url>', 'CmdCtrl server URL', 'http://localhost:4000')
32
+ .option('-n, --name <name>', 'Device name (defaults to hostname-cursor)')
33
+ .action(register);
34
+
35
+ program
36
+ .command('start')
37
+ .description('Start the daemon and connect to the CmdCtrl server')
38
+ .option('-f, --foreground', 'Run in foreground (don\'t daemonize)')
39
+ .action(start);
40
+
41
+ program
42
+ .command('status')
43
+ .description('Check daemon connection status')
44
+ .action(status);
45
+
46
+ program
47
+ .command('stop')
48
+ .description('Stop the running daemon')
49
+ .action(stop);
50
+
51
+ program
52
+ .command('update')
53
+ .description('Update the daemon to the latest version')
54
+ .action(update);
55
+
56
+ program.parse();
package/tsconfig.json ADDED
@@ -0,0 +1,19 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "commonjs",
5
+ "lib": ["ES2022"],
6
+ "outDir": "./dist",
7
+ "rootDir": "./src",
8
+ "strict": true,
9
+ "esModuleInterop": true,
10
+ "skipLibCheck": true,
11
+ "forceConsistentCasingInFileNames": true,
12
+ "resolveJsonModule": true,
13
+ "declaration": true,
14
+ "declarationMap": true,
15
+ "sourceMap": true
16
+ },
17
+ "include": ["src/**/*"],
18
+ "exclude": ["node_modules", "dist"]
19
+ }