knoxis-helper 1.0.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.
@@ -0,0 +1,191 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * Knoxis Helper - First-time setup + local agent launcher
5
+ *
6
+ * Usage:
7
+ * npx knoxis-helper # Interactive setup (first time)
8
+ * npx knoxis-helper --backend wss://... # Connect to specific backend
9
+ * npx knoxis-helper --status # Check connection status
10
+ */
11
+
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+ const os = require('os');
15
+ const readline = require('readline');
16
+
17
+ const CONFIG_DIR = path.join(os.homedir(), '.knoxis');
18
+ const CONFIG_FILE = path.join(CONFIG_DIR, 'config.json');
19
+ const DEFAULT_BACKEND = 'wss://voice-backend.qig.ai';
20
+
21
+ function loadConfig() {
22
+ try {
23
+ if (fs.existsSync(CONFIG_FILE)) {
24
+ return JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8'));
25
+ }
26
+ } catch (e) {}
27
+ return {};
28
+ }
29
+
30
+ function saveConfig(config) {
31
+ if (!fs.existsSync(CONFIG_DIR)) {
32
+ fs.mkdirSync(CONFIG_DIR, { recursive: true });
33
+ }
34
+ fs.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2));
35
+ }
36
+
37
+ function parseArgs() {
38
+ const args = {};
39
+ for (let i = 2; i < process.argv.length; i++) {
40
+ const arg = process.argv[i];
41
+ if (arg === '--status') { args.status = true; continue; }
42
+ if (arg === '--reset') { args.reset = true; continue; }
43
+ if (arg.startsWith('--')) {
44
+ const key = arg.slice(2);
45
+ const next = process.argv[i + 1];
46
+ if (next && !next.startsWith('--')) {
47
+ args[key] = next;
48
+ i++;
49
+ } else {
50
+ args[key] = true;
51
+ }
52
+ }
53
+ }
54
+ return args;
55
+ }
56
+
57
+ function ask(rl, question) {
58
+ return new Promise(resolve => rl.question(question, resolve));
59
+ }
60
+
61
+ async function firstTimeSetup(args) {
62
+ const config = loadConfig();
63
+
64
+ console.log('');
65
+ console.log(' Knoxis Helper - First Time Setup');
66
+ console.log(' ================================');
67
+ console.log('');
68
+ console.log(' This connects your machine to Knoxis so it can');
69
+ console.log(' open terminals and run pair programming sessions.');
70
+ console.log('');
71
+
72
+ const rl = readline.createInterface({ input: process.stdin, output: process.stdout });
73
+
74
+ // Backend URL
75
+ let backend = args.backend || config.backendWsUrl;
76
+ if (!backend) {
77
+ const answer = await ask(rl, ` Backend URL [${DEFAULT_BACKEND}]: `);
78
+ backend = answer.trim() || DEFAULT_BACKEND;
79
+ }
80
+
81
+ // Normalize - ensure ws/wss protocol
82
+ if (backend.startsWith('http://')) {
83
+ backend = backend.replace('http://', 'ws://');
84
+ } else if (backend.startsWith('https://')) {
85
+ backend = backend.replace('https://', 'wss://');
86
+ } else if (!backend.startsWith('ws://') && !backend.startsWith('wss://')) {
87
+ backend = 'wss://' + backend;
88
+ }
89
+
90
+ // User ID
91
+ let userId = args.userId || args.user || config.userId;
92
+ if (!userId) {
93
+ console.log('');
94
+ console.log(' Your user ID is on your profile page at qig.ai/settings.');
95
+ const answer = await ask(rl, ' User ID: ');
96
+ userId = answer.trim();
97
+
98
+ if (!userId) {
99
+ console.error(' User ID is required. Find it at qig.ai/settings.');
100
+ rl.close();
101
+ process.exit(1);
102
+ }
103
+ }
104
+
105
+ rl.close();
106
+
107
+ // Save config
108
+ config.backendWsUrl = backend;
109
+ config.userId = userId;
110
+ config.configuredAt = new Date().toISOString();
111
+ saveConfig(config);
112
+
113
+ console.log('');
114
+ console.log(' Configuration saved to ~/.knoxis/config.json');
115
+ console.log(` Backend: ${backend}`);
116
+ console.log(` User: ${userId}`);
117
+ console.log('');
118
+
119
+ return config;
120
+ }
121
+
122
+ async function main() {
123
+ const args = parseArgs();
124
+
125
+ // Reset
126
+ if (args.reset) {
127
+ try { fs.unlinkSync(CONFIG_FILE); } catch (e) {}
128
+ console.log('Configuration cleared. Run again to set up.');
129
+ process.exit(0);
130
+ }
131
+
132
+ // Status check
133
+ if (args.status) {
134
+ const config = loadConfig();
135
+ if (!config.backendWsUrl || !config.userId) {
136
+ console.log('Not configured. Run: npx knoxis-helper');
137
+ } else {
138
+ console.log('Configured:');
139
+ console.log(` Backend: ${config.backendWsUrl}`);
140
+ console.log(` User: ${config.userId}`);
141
+ }
142
+ process.exit(0);
143
+ }
144
+
145
+ // Load or create config
146
+ let config = loadConfig();
147
+ const needsSetup = !config.backendWsUrl || !config.userId || args.backend || args.userId;
148
+
149
+ if (needsSetup) {
150
+ config = await firstTimeSetup(args);
151
+ } else {
152
+ console.log('');
153
+ console.log(` Knoxis Helper - Connecting to ${config.backendWsUrl}`);
154
+ console.log(` User: ${config.userId}`);
155
+ console.log('');
156
+ }
157
+
158
+ // Set environment variables for the local agent
159
+ process.env.KNOXIS_BACKEND_WS_URL = config.backendWsUrl;
160
+ process.env.KNOXIS_USER_ID = config.userId;
161
+
162
+ // Launch the local agent
163
+ // Try to find it in common locations
164
+ const agentLocations = [
165
+ path.join(__dirname, '..', 'lib', 'knoxis-local-agent.js'),
166
+ path.join(__dirname, '..', '..', 'knoxis-local-agent.js'),
167
+ path.join(process.cwd(), 'scripts', 'knoxis-local-agent.js'),
168
+ ];
169
+
170
+ let agentPath = null;
171
+ for (const loc of agentLocations) {
172
+ if (fs.existsSync(loc)) {
173
+ agentPath = loc;
174
+ break;
175
+ }
176
+ }
177
+
178
+ if (!agentPath) {
179
+ console.error('Could not find knoxis-local-agent.js.');
180
+ console.error('Expected in:', agentLocations.map(l => ' ' + l).join('\n'));
181
+ process.exit(1);
182
+ }
183
+
184
+ // Load and execute the agent in the same process
185
+ require(agentPath);
186
+ }
187
+
188
+ main().catch(err => {
189
+ console.error('Error:', err.message);
190
+ process.exit(1);
191
+ });