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.
Files changed (2) hide show
  1. package/bin/bortex.js +55 -1
  2. 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: { 'Content-Type': 'application/json' },
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.');
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "bortexcode",
3
- "version": "1.5.0",
3
+ "version": "1.6.0",
4
4
  "description": "Bortex Code CLI - AI coding assistant powered by bortex.site",
5
5
  "homepage": "https://bortex.site",
6
6
  "license": "UNLICENSED",