knoxis-helper 1.3.1 → 1.3.3
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/lib/knoxis-local-agent.js +61 -26
- package/package.json +1 -1
|
@@ -657,6 +657,23 @@ async function handleRequest(req, res) {
|
|
|
657
657
|
|
|
658
658
|
// Start pair programming session (opens terminal)
|
|
659
659
|
if (pathname === '/pair/start' && method === 'POST') {
|
|
660
|
+
// Build CLAUDE.md content from task when backend doesn't provide claudeMdContent
|
|
661
|
+
function buildClaudeMdFromTask(taskText, workspacePath) {
|
|
662
|
+
const lines = [];
|
|
663
|
+
lines.push('# Project Instructions\n');
|
|
664
|
+
lines.push('## Current Task');
|
|
665
|
+
lines.push(taskText);
|
|
666
|
+
lines.push('');
|
|
667
|
+
lines.push('## Working Agreement');
|
|
668
|
+
lines.push('- Work autonomously. Do not ask clarifying questions - make your best engineering judgment and proceed.');
|
|
669
|
+
lines.push('- Read and understand existing code before making changes.');
|
|
670
|
+
lines.push('- Follow existing patterns in the codebase.');
|
|
671
|
+
lines.push('- Keep changes minimal and focused on the task.');
|
|
672
|
+
lines.push('- Verify your work compiles/runs where possible.');
|
|
673
|
+
lines.push('- Be direct and concise in any output.');
|
|
674
|
+
return lines.join('\n');
|
|
675
|
+
}
|
|
676
|
+
|
|
660
677
|
try {
|
|
661
678
|
const body = await parseBody(req);
|
|
662
679
|
const { workspace, task, file, provider, headless, sessionId, claudeMdContent } = body;
|
|
@@ -675,18 +692,25 @@ async function handleRequest(req, res) {
|
|
|
675
692
|
}
|
|
676
693
|
}
|
|
677
694
|
|
|
678
|
-
// Write CLAUDE.md
|
|
679
|
-
|
|
695
|
+
// Write CLAUDE.md for supplementary context.
|
|
696
|
+
// If claudeMdContent was provided (from backend relay), use it directly.
|
|
697
|
+
// Otherwise, build it from the task field.
|
|
698
|
+
const effectiveClaudeMd = claudeMdContent || buildClaudeMdFromTask(task, workspace);
|
|
699
|
+
if (effectiveClaudeMd && fs.existsSync(workspaceDir)) {
|
|
680
700
|
try {
|
|
681
|
-
fs.writeFileSync(path.join(workspaceDir, 'CLAUDE.md'),
|
|
682
|
-
console.log(`📄 Wrote CLAUDE.md to ${workspaceDir}`);
|
|
701
|
+
fs.writeFileSync(path.join(workspaceDir, 'CLAUDE.md'), effectiveClaudeMd, 'utf8');
|
|
702
|
+
console.log(`📄 Wrote CLAUDE.md to ${workspaceDir} (${effectiveClaudeMd.length} chars)`);
|
|
683
703
|
} catch (e) {
|
|
684
704
|
console.warn(`⚠️ Failed to write CLAUDE.md: ${e.message}`);
|
|
685
705
|
}
|
|
686
706
|
}
|
|
687
707
|
|
|
688
|
-
//
|
|
689
|
-
|
|
708
|
+
// Write the actual task to a temp file and pipe it to Claude via stdin.
|
|
709
|
+
// This avoids shell escaping issues with quotes/backticks/etc in the task text.
|
|
710
|
+
const promptFile = path.join(os.tmpdir(), `knoxis-task-${sessionId || Date.now()}.txt`);
|
|
711
|
+
const promptText = file ? `Working on file: ${file}\n\nTask: ${task}` : task;
|
|
712
|
+
fs.writeFileSync(promptFile, promptText, 'utf8');
|
|
713
|
+
const command = `cat "${promptFile}" | claude --dangerously-skip-permissions`;
|
|
690
714
|
|
|
691
715
|
if (headless) {
|
|
692
716
|
const result = await runHeadlessProcess({
|
|
@@ -999,35 +1023,39 @@ function connectRelayWebSocket() {
|
|
|
999
1023
|
if (msg.type === 'execute_command') {
|
|
1000
1024
|
console.log(`📥 Relay command received: ${msg.requestId}`);
|
|
1001
1025
|
console.log(` 📂 Dir: ${msg.workingDir}`);
|
|
1002
|
-
console.log(` 📝
|
|
1026
|
+
console.log(` 📝 Prompt: ${msg.prompt ? msg.prompt.substring(0, 120) + '...' : '(none)'}`);
|
|
1003
1027
|
|
|
1004
1028
|
const workspace = msg.workingDir || process.cwd();
|
|
1005
|
-
const
|
|
1029
|
+
const wsDir = workspace.startsWith('~')
|
|
1030
|
+
? path.join(os.homedir(), workspace.slice(1))
|
|
1031
|
+
: workspace;
|
|
1006
1032
|
|
|
1007
|
-
// Write CLAUDE.md
|
|
1008
|
-
|
|
1009
|
-
if (msg.claudeMdContent && workspace && workspace !== '~') {
|
|
1033
|
+
// Write CLAUDE.md for supplementary context (developer brief, working agreement, etc.)
|
|
1034
|
+
if (msg.claudeMdContent && fs.existsSync(wsDir)) {
|
|
1010
1035
|
try {
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
: workspace;
|
|
1014
|
-
if (fs.existsSync(wsDir)) {
|
|
1015
|
-
const claudeMdPath = path.join(wsDir, 'CLAUDE.md');
|
|
1016
|
-
fs.writeFileSync(claudeMdPath, msg.claudeMdContent, 'utf8');
|
|
1017
|
-
console.log(` 📄 Wrote CLAUDE.md to ${claudeMdPath} (${msg.claudeMdContent.length} chars)`);
|
|
1018
|
-
} else {
|
|
1019
|
-
console.warn(` ⚠️ Workspace does not exist, skipping CLAUDE.md write: ${wsDir}`);
|
|
1020
|
-
}
|
|
1036
|
+
fs.writeFileSync(path.join(wsDir, 'CLAUDE.md'), msg.claudeMdContent, 'utf8');
|
|
1037
|
+
console.log(` 📄 Wrote CLAUDE.md (${msg.claudeMdContent.length} chars)`);
|
|
1021
1038
|
} catch (writeErr) {
|
|
1022
1039
|
console.warn(` ⚠️ Failed to write CLAUDE.md: ${writeErr.message}`);
|
|
1023
1040
|
}
|
|
1024
1041
|
}
|
|
1025
1042
|
|
|
1043
|
+
// Build the actual command. If a prompt was sent, write it to a temp file
|
|
1044
|
+
// and pipe it to Claude via stdin — avoids all shell escaping issues.
|
|
1045
|
+
let command = msg.command || '';
|
|
1046
|
+
let promptFile = null;
|
|
1047
|
+
if (msg.prompt) {
|
|
1048
|
+
promptFile = path.join(os.tmpdir(), `knoxis-task-${msg.requestId || Date.now()}.txt`);
|
|
1049
|
+
fs.writeFileSync(promptFile, msg.prompt, 'utf8');
|
|
1050
|
+
command = `cat "${promptFile}" | claude --dangerously-skip-permissions`;
|
|
1051
|
+
console.log(` 📝 Task written to ${promptFile} (${msg.prompt.length} chars)`);
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1026
1054
|
let result;
|
|
1027
1055
|
try {
|
|
1028
1056
|
if (msg.headless) {
|
|
1029
1057
|
result = await runHeadlessProcess({
|
|
1030
|
-
workspace,
|
|
1058
|
+
workspace: wsDir,
|
|
1031
1059
|
command,
|
|
1032
1060
|
prompt: msg.prompt,
|
|
1033
1061
|
sessionLabel: msg.requestId || 'relay'
|
|
@@ -1035,11 +1063,11 @@ function connectRelayWebSocket() {
|
|
|
1035
1063
|
} else {
|
|
1036
1064
|
const platform = os.platform();
|
|
1037
1065
|
if (platform === 'darwin') {
|
|
1038
|
-
await openMacTerminal(
|
|
1066
|
+
await openMacTerminal(wsDir, command);
|
|
1039
1067
|
} else if (platform === 'win32') {
|
|
1040
|
-
await openWindowsTerminal(
|
|
1068
|
+
await openWindowsTerminal(wsDir, command);
|
|
1041
1069
|
} else {
|
|
1042
|
-
await openLinuxTerminal(
|
|
1070
|
+
await openLinuxTerminal(wsDir, command);
|
|
1043
1071
|
}
|
|
1044
1072
|
result = { success: true, message: 'Terminal opened via relay' };
|
|
1045
1073
|
}
|
|
@@ -1047,6 +1075,13 @@ function connectRelayWebSocket() {
|
|
|
1047
1075
|
result = { success: false, error: err.message };
|
|
1048
1076
|
}
|
|
1049
1077
|
|
|
1078
|
+
// Clean up temp prompt file (Claude already read it)
|
|
1079
|
+
if (promptFile) {
|
|
1080
|
+
setTimeout(() => {
|
|
1081
|
+
try { fs.unlinkSync(promptFile); } catch (e) {}
|
|
1082
|
+
}, 5000); // Delay to ensure cat has finished piping
|
|
1083
|
+
}
|
|
1084
|
+
|
|
1050
1085
|
// Send result back to backend
|
|
1051
1086
|
const response = JSON.stringify({
|
|
1052
1087
|
type: 'command_result',
|
|
@@ -1187,7 +1222,7 @@ server.listen(serverMeta.port, () => {
|
|
|
1187
1222
|
const scheme = serverMeta.secure ? 'https' : 'http';
|
|
1188
1223
|
console.log('');
|
|
1189
1224
|
console.log('╔══════════════════════════════════════════════════════════════╗');
|
|
1190
|
-
console.log('║ 🚀 KNOXIS LOCAL AGENT v2.
|
|
1225
|
+
console.log('║ 🚀 KNOXIS LOCAL AGENT v2.3.0 (Prompt Pipe Fix) ║');
|
|
1191
1226
|
console.log('╚══════════════════════════════════════════════════════════════╝');
|
|
1192
1227
|
console.log('');
|
|
1193
1228
|
console.log(`🔒 Mode: ${serverMeta.secure ? 'HTTPS (Secure)' : 'HTTP (Insecure - see warning below)'}`);
|