bortexcode 1.5.0 → 1.6.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/bortex.js +55 -1
- package/package.json +1 -1
package/bin/bortex.js
CHANGED
|
@@ -4752,6 +4752,7 @@ function assessRemoteControlPromptPermission(opts, line) {
|
|
|
4752
4752
|
const mode = getRemoteControlPermissionMode(opts);
|
|
4753
4753
|
const text = String(line || '').trim();
|
|
4754
4754
|
if (!text) return { ok: false, mode, reason: 'empty prompt' };
|
|
4755
|
+
if (opts._remoteControlApprovalBypass) return { ok: true, mode, approved: true };
|
|
4755
4756
|
if (mode === 'full') return { ok: true, mode };
|
|
4756
4757
|
if (!text.startsWith('/')) return { ok: true, mode, skipNaturalActions: true };
|
|
4757
4758
|
if (mode === 'read-only') {
|
|
@@ -4855,6 +4856,24 @@ async function postCloudRemoteChunk(state, commandId, stream, text) {
|
|
|
4855
4856
|
}, 12000);
|
|
4856
4857
|
}
|
|
4857
4858
|
|
|
4859
|
+
async function postCloudRemoteApprovalRequest(state, commandId, permission, text) {
|
|
4860
|
+
const approvalUrl = withRemoteControlQuery(
|
|
4861
|
+
state.approvalUrl || `${state.baseUrl}/api/bortex-code/remote/session/${encodeURIComponent(state.sessionId)}/approval-request`,
|
|
4862
|
+
state.baseUrl,
|
|
4863
|
+
{ agentToken: state.agentToken }
|
|
4864
|
+
);
|
|
4865
|
+
await fetchRemoteControlJson(approvalUrl, {
|
|
4866
|
+
method: 'POST',
|
|
4867
|
+
headers: { 'Content-Type': 'application/json' },
|
|
4868
|
+
body: JSON.stringify({
|
|
4869
|
+
commandId,
|
|
4870
|
+
text: String(text || ''),
|
|
4871
|
+
mode: permission?.mode || state.permission || 'balanced',
|
|
4872
|
+
reason: permission?.reason || 'This command requires explicit approval.'
|
|
4873
|
+
})
|
|
4874
|
+
}, 12000);
|
|
4875
|
+
}
|
|
4876
|
+
|
|
4858
4877
|
function createCloudRemoteChunkStreamer(state, commandId) {
|
|
4859
4878
|
const queue = [];
|
|
4860
4879
|
let timer = null;
|
|
@@ -4972,10 +4991,32 @@ async function pollCloudRemoteControlLoop(opts, state) {
|
|
|
4972
4991
|
if (!text) continue;
|
|
4973
4992
|
state.cancelRequested = false;
|
|
4974
4993
|
state.cancelCommandId = null;
|
|
4994
|
+
const approved = !!command.approved;
|
|
4995
|
+
const permission = assessRemoteControlPromptPermission(opts, text);
|
|
4996
|
+
if (!permission.ok && !approved) {
|
|
4997
|
+
state.busy = true;
|
|
4998
|
+
opts._remoteControlExecutionState = state;
|
|
4999
|
+
try {
|
|
5000
|
+
await postCloudRemoteApprovalRequest(state, commandId, permission, text);
|
|
5001
|
+
console.log(`Cloud Remote Control approval requested for command #${commandId}: ${permission.reason}.`);
|
|
5002
|
+
} catch (err) {
|
|
5003
|
+
const message = err.message || String(err);
|
|
5004
|
+
await postCloudRemoteResult(state, commandId, {
|
|
5005
|
+
ok: false,
|
|
5006
|
+
output: `Approval request failed: ${message}`
|
|
5007
|
+
}).catch(() => {});
|
|
5008
|
+
} finally {
|
|
5009
|
+
state.busy = false;
|
|
5010
|
+
delete opts._remoteControlExecutionState;
|
|
5011
|
+
}
|
|
5012
|
+
continue;
|
|
5013
|
+
}
|
|
4975
5014
|
state.busy = true;
|
|
4976
5015
|
opts._remoteControlExecutionState = state;
|
|
4977
5016
|
const streamer = createCloudRemoteChunkStreamer(state, commandId);
|
|
4978
5017
|
let result;
|
|
5018
|
+
const previousApprovalBypass = opts._remoteControlApprovalBypass;
|
|
5019
|
+
if (approved) opts._remoteControlApprovalBypass = true;
|
|
4979
5020
|
try {
|
|
4980
5021
|
result = await runRemoteControlPrompt(opts, text, (stream, chunk) => streamer.push(stream, chunk));
|
|
4981
5022
|
} catch (err) {
|
|
@@ -4984,6 +5025,8 @@ async function pollCloudRemoteControlLoop(opts, state) {
|
|
|
4984
5025
|
await streamer.flush().catch(() => {});
|
|
4985
5026
|
state.busy = false;
|
|
4986
5027
|
delete opts._remoteControlExecutionState;
|
|
5028
|
+
if (previousApprovalBypass === undefined) delete opts._remoteControlApprovalBypass;
|
|
5029
|
+
else opts._remoteControlApprovalBypass = previousApprovalBypass;
|
|
4987
5030
|
}
|
|
4988
5031
|
if (state.cancelRequested && result.ok) {
|
|
4989
5032
|
result = { ok: false, output: 'Canceled by remote request.' };
|
|
@@ -5032,6 +5075,11 @@ async function startCloudRemoteControlSession(opts, overrides = {}) {
|
|
|
5032
5075
|
const name = getRemoteControlDisplayName(opts, overrides);
|
|
5033
5076
|
const permission = getRemoteControlPermissionMode(opts, overrides);
|
|
5034
5077
|
opts.remoteControlPermission = permission;
|
|
5078
|
+
const sharedSettings = loadSharedSettings();
|
|
5079
|
+
const registerCookie = getCookieHeaderFromSharedSettings();
|
|
5080
|
+
const registerApiKey = String(
|
|
5081
|
+
opts.apiKey || process.env.BORTEX_API_KEY || sharedSettings?.llmSettings?.apiKey || ''
|
|
5082
|
+
).trim();
|
|
5035
5083
|
const payload = {
|
|
5036
5084
|
name,
|
|
5037
5085
|
cwd: opts.cwd,
|
|
@@ -5042,9 +5090,12 @@ async function startCloudRemoteControlSession(opts, overrides = {}) {
|
|
|
5042
5090
|
mode: opts.agent ? 'agent' : 'chat',
|
|
5043
5091
|
permission
|
|
5044
5092
|
};
|
|
5093
|
+
const registerHeaders = { 'Content-Type': 'application/json' };
|
|
5094
|
+
if (registerCookie) registerHeaders.Cookie = registerCookie;
|
|
5095
|
+
if (registerApiKey) registerHeaders['x-api-key'] = registerApiKey;
|
|
5045
5096
|
const data = await fetchRemoteControlJson(`${baseUrl}/api/bortex-code/remote/register`, {
|
|
5046
5097
|
method: 'POST',
|
|
5047
|
-
headers:
|
|
5098
|
+
headers: registerHeaders,
|
|
5048
5099
|
body: JSON.stringify(payload)
|
|
5049
5100
|
}, 30000);
|
|
5050
5101
|
|
|
@@ -5068,6 +5119,7 @@ async function startCloudRemoteControlSession(opts, overrides = {}) {
|
|
|
5068
5119
|
pollUrl: data.pollUrl || `${baseUrl}/api/bortex-code/remote/session/${encodeURIComponent(sessionId)}/poll`,
|
|
5069
5120
|
resultUrl: data.resultUrl || `${baseUrl}/api/bortex-code/remote/session/${encodeURIComponent(sessionId)}/result`,
|
|
5070
5121
|
chunkUrl: data.chunkUrl || `${baseUrl}/api/bortex-code/remote/session/${encodeURIComponent(sessionId)}/chunk`,
|
|
5122
|
+
approvalUrl: data.approvalUrl || `${baseUrl}/api/bortex-code/remote/session/${encodeURIComponent(sessionId)}/approval-request`,
|
|
5071
5123
|
heartbeatUrl: data.heartbeatUrl || `${baseUrl}/api/bortex-code/remote/session/${encodeURIComponent(sessionId)}/heartbeat`,
|
|
5072
5124
|
controlUrl: data.controlUrl || `${baseUrl}/api/bortex-code/remote/session/${encodeURIComponent(sessionId)}/control`,
|
|
5073
5125
|
lastCommandId: 0,
|
|
@@ -5088,6 +5140,8 @@ async function startCloudRemoteControlSession(opts, overrides = {}) {
|
|
|
5088
5140
|
|
|
5089
5141
|
console.log(`Cloud Remote Control active: ${state.name}`);
|
|
5090
5142
|
console.log(`URL: ${state.url}`);
|
|
5143
|
+
if (data.accountUrl) console.log(`Account URL: ${data.accountUrl}`);
|
|
5144
|
+
if (data.sessionsUrl) console.log(`Sessions: ${data.sessionsUrl}`);
|
|
5091
5145
|
console.log(`Permission: ${state.permission}`);
|
|
5092
5146
|
console.log('No inbound port required. Keep this process running.');
|
|
5093
5147
|
console.log('Security: keep this tokenized URL private. Anyone with the URL can control this Bortex Code session.');
|