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.
- package/bin/knoxis-helper.js +191 -0
- package/lib/knoxis-local-agent.js +1137 -0
- package/lib/knoxis-pair-program.js +513 -0
- package/package.json +17 -0
|
@@ -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
|
+
});
|