Skip to content

Commit b12499c

Browse files
sestinjcubic-dev-ai[bot]github-advanced-security[bot]
authored
feat: show remote sessions in cn ls (#7694)
* feat: /title slash command * fix: /title slash command should be able to be submitted with text * test: add tests for last commit's changes * fix: EOF in action.yml * feat: list remote sessions in cn ls and /resume * feat: load more sessions and make them scrollable * chore: format * improv: debug script builds automatically for cli * feat: load remote session * fix: wrap entrypoint in function so it doesn't run at import-time * feat: /diff and /apply slash commands for cn remote * feat: full screen diff viewer * feat: status message for /apply slash command * Update extensions/cli/src/ui/UserInput.tsx Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> * fix: remove console.logs * Potential fix for code scanning alert no. 60: Uncontrolled command line Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * Potential fix for code scanning alert no. 61: Uncontrolled command line Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> * fix: build.js * feat: list remote sessions in history of extensions * feat: open remote agents in browser * chore: fix tests and lint * fix: import Text * fix: small bug * fix: address feedback * fix: adjust extension gui for compatibility with cli session history * feat: load session history from remote * feat: open remote session in browser * fix: tests, linting, formatting * fix: don't use any * address nitpicks --------- Co-authored-by: cubic-dev-ai[bot] <191113872+cubic-dev-ai[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
1 parent c5d202c commit b12499c

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+1412
-258
lines changed

.vscode/launch.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,7 @@
153153
"${workspaceFolder}/**",
154154
"!**/node_modules/**"
155155
],
156-
"preLaunchTask": "watch-logs",
156+
"preLaunchTask": "cli:build-and-watch-logs",
157157
"cwd": "${workspaceFolder}/extensions/cli"
158158
},
159159
{

.vscode/tasks.json

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,26 @@
330330
"cwd": "${workspaceFolder}/extensions/cli"
331331
}
332332
},
333+
{
334+
"label": "cli:build-no-minify",
335+
"type": "shell",
336+
"command": "npm",
337+
"args": ["run", "build:bundle", "--", "--no-minify"],
338+
"group": "build",
339+
"presentation": {
340+
"echo": true,
341+
"reveal": "silent",
342+
"focus": false,
343+
"panel": "shared",
344+
"showReuseMessage": true,
345+
"clear": false,
346+
"close": true
347+
},
348+
"problemMatcher": ["$tsc"],
349+
"options": {
350+
"cwd": "${workspaceFolder}/extensions/cli"
351+
}
352+
},
333353
{
334354
"label": "cli:test",
335355
"type": "npm",
@@ -373,6 +393,21 @@
373393
"options": {
374394
"cwd": "${workspaceFolder}/extensions/cli"
375395
}
396+
},
397+
{
398+
"label": "cli:build-and-watch-logs",
399+
"dependsOn": ["cli:build-no-minify", "watch-logs"],
400+
"dependsOrder": "sequence",
401+
"type": "shell",
402+
"command": "echo",
403+
"args": ["Build and watch logs completed"],
404+
"presentation": {
405+
"group": "build-tasks",
406+
"panel": "shared",
407+
"reveal": "silent",
408+
"close": true,
409+
"focus": false
410+
}
376411
}
377412
]
378413
}

actions/general-review/action.yml

Lines changed: 42 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,20 @@
1-
name: 'Continue PR Review'
2-
description: 'Automated code review for pull requests using Continue CLI'
3-
author: 'Continue Dev, Inc.'
1+
name: "Continue PR Review"
2+
description: "Automated code review for pull requests using Continue CLI"
3+
author: "Continue Dev, Inc."
44

55
inputs:
66
continue-api-key:
7-
description: 'API key for Continue service'
7+
description: "API key for Continue service"
88
required: true
99
continue-org:
10-
description: 'Organization for Continue config'
10+
description: "Organization for Continue config"
1111
required: true
1212
continue-config:
1313
description: 'Config path to use (e.g., "myorg/review-bot")'
1414
required: true
1515

1616
runs:
17-
using: 'composite'
17+
using: "composite"
1818
steps:
1919
- name: Checkout Repository
2020
uses: actions/checkout@v4
@@ -27,7 +27,7 @@ runs:
2727
run: |
2828
# Check if this action should run based on event type and user permissions
2929
SHOULD_RUN="false"
30-
30+
3131
if [ "${{ github.event_name }}" = "pull_request" ]; then
3232
# Check if PR is a draft
3333
if [ "${{ github.event.pull_request.draft }}" = "true" ]; then
@@ -56,7 +56,7 @@ runs:
5656
else
5757
echo "::notice::Skipping review - Unsupported event type: ${{ github.event_name }}"
5858
fi
59-
59+
6060
echo "SHOULD_RUN=$SHOULD_RUN" >> $GITHUB_ENV
6161
6262
- name: Setup Node.js
@@ -162,14 +162,14 @@ runs:
162162
echo "Warning: CONTINUE_API_KEY environment variable is not set"
163163
# Create fallback review and continue
164164
cat > code_review.md << 'EOF'
165-
## Code Review Summary
165+
## Code Review Summary
166166
167-
⚠️ AI review skipped: CONTINUE_API_KEY not configured.
167+
⚠️ AI review skipped: CONTINUE_API_KEY not configured.
168168
169-
### Configuration Required
170-
- Please set the CONTINUE_API_KEY secret in repository settings
171-
- Verify that the organization and config path are valid
172-
EOF
169+
### Configuration Required
170+
- Please set the CONTINUE_API_KEY secret in repository settings
171+
- Verify that the organization and config path are valid
172+
EOF
173173
echo "SKIP_CLI=true" >> $GITHUB_ENV
174174
else
175175
echo "SKIP_CLI=false" >> $GITHUB_ENV
@@ -180,7 +180,7 @@ EOF
180180
echo "Error: Invalid organization name. Must contain only alphanumeric characters, hyphens, and underscores."
181181
exit 1
182182
fi
183-
183+
184184
if [[ ! "$CONTINUE_CONFIG" =~ ^[a-zA-Z0-9_/-]+$ ]]; then
185185
echo "Error: Invalid config path. Must contain only alphanumeric characters, hyphens, underscores, and forward slashes."
186186
exit 1
@@ -192,14 +192,14 @@ EOF
192192
if ! cn --version; then
193193
echo "Warning: Continue CLI not found or not working"
194194
cat > code_review.md << 'EOF'
195-
## Code Review Summary
195+
## Code Review Summary
196196
197-
⚠️ AI review skipped: Continue CLI installation failed.
197+
⚠️ AI review skipped: Continue CLI installation failed.
198198
199-
### Troubleshooting
200-
- Check that npm installation succeeded
201-
- Verify @continuedev/cli package is available
202-
EOF
199+
### Troubleshooting
200+
- Check that npm installation succeeded
201+
- Verify @continuedev/cli package is available
202+
EOF
203203
echo "SKIP_CLI=true" >> $GITHUB_ENV
204204
else
205205
echo "Continue CLI version: $(cn --version)"
@@ -213,27 +213,27 @@ EOF
213213
# Write prompt to temp file for better handling
214214
PROMPT_FILE="/tmp/continue-prompt-$.txt"
215215
cp review_prompt.txt "$PROMPT_FILE"
216+
217+
# Use timeout to prevent hanging (240 seconds = 4 minutes)
218+
if ! timeout 240 cn --config "$CONTINUE_ORG/$CONTINUE_CONFIG" -p "@$PROMPT_FILE" --allow Bash > code_review.md 2>cli_error.log; then
219+
echo "Error: Continue CLI command failed"
220+
echo "CLI error log:"
221+
cat cli_error.log
222+
223+
# Create fallback review
224+
cat > code_review.md << 'EOF'
225+
## Code Review Summary
216226
217-
# Use timeout to prevent hanging (240 seconds = 4 minutes)
218-
if ! timeout 240 cn --config "$CONTINUE_ORG/$CONTINUE_CONFIG" -p "@$PROMPT_FILE" --allow Bash > code_review.md 2>cli_error.log; then
219-
echo "Error: Continue CLI command failed"
220-
echo "CLI error log:"
221-
cat cli_error.log
222-
223-
# Create fallback review
224-
cat > code_review.md << 'EOF'
225-
## Code Review Summary
226-
227-
⚠️ AI review failed due to service initialization issues. Please check the Continue API key and configuration.
227+
⚠️ AI review failed due to service initialization issues. Please check the Continue API key and configuration.
228228
229-
### Troubleshooting
230-
- Verify the CONTINUE_API_KEY secret is set correctly
231-
- Check that the organization and config path are valid
232-
- Ensure the Continue service is accessible
233-
EOF
234-
else
235-
echo "Review generated successfully"
236-
fi
229+
### Troubleshooting
230+
- Verify the CONTINUE_API_KEY secret is set correctly
231+
- Check that the organization and config path are valid
232+
- Ensure the Continue service is accessible
233+
EOF
234+
else
235+
echo "Review generated successfully"
236+
fi
237237
fi
238238
239239
- name: Upload Review Results
@@ -294,5 +294,5 @@ EOF
294294
}
295295
296296
branding:
297-
icon: 'code'
298-
color: 'blue'
297+
icon: "code"
298+
color: "blue"

core/config/yaml/yamlToContinueConfig.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function convertYamlRuleToContinueRule(rule: Rule): RuleWithSource {
1616
description: rule.description,
1717
ruleFile: rule.sourceFile,
1818
alwaysApply: rule.alwaysApply,
19-
invokable: rule.invokable,
19+
invokable: rule.invokable ?? false,
2020
};
2121
}
2222
}

core/control-plane/client.ts

Lines changed: 139 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,19 @@ import {
1111
import fetch, { RequestInit, Response } from "node-fetch";
1212

1313
import { OrganizationDescription } from "../config/ProfileLifecycleManager.js";
14-
import { IDE, ModelDescription } from "../index.js";
14+
import {
15+
IDE,
16+
ModelDescription,
17+
Session,
18+
BaseSessionMetadata,
19+
} from "../index.js";
1520
import { Logger } from "../util/Logger.js";
1621

17-
import { ControlPlaneSessionInfo, isOnPremSession } from "./AuthTypes.js";
22+
import {
23+
ControlPlaneSessionInfo,
24+
HubSessionInfo,
25+
isOnPremSession,
26+
} from "./AuthTypes.js";
1827
import { getControlPlaneEnv } from "./env.js";
1928

2029
export interface PolicyResponse {
@@ -41,6 +50,11 @@ export interface FreeTrialStatus {
4150
export const TRIAL_PROXY_URL =
4251
"https://proxy-server-blue-l6vsfbzhba-uw.a.run.app";
4352

53+
export interface RemoteSessionMetadata extends BaseSessionMetadata {
54+
isRemote: true;
55+
remoteId: string;
56+
}
57+
4458
export class ControlPlaneClient {
4559
constructor(
4660
readonly sessionInfoPromise: Promise<ControlPlaneSessionInfo | undefined>,
@@ -303,4 +317,127 @@ export class ControlPlaneClient {
303317
return null;
304318
}
305319
}
320+
321+
/**
322+
* Check if remote sessions should be enabled based on feature flags
323+
* Requires: PostHog feature flag AND @continue.dev email
324+
*/
325+
public async shouldEnableRemoteSessions(): Promise<boolean> {
326+
// Check if user is signed in
327+
if (!(await this.isSignedIn())) {
328+
return false;
329+
}
330+
331+
// Check if user has @continue.dev email
332+
try {
333+
const sessionInfo = await this.sessionInfoPromise;
334+
if (isOnPremSession(sessionInfo) || !sessionInfo) {
335+
return false;
336+
}
337+
338+
const hubSession = sessionInfo as HubSessionInfo;
339+
const email = hubSession.account?.id;
340+
341+
return email ? email.includes("@continue.dev") : false;
342+
} catch (e) {
343+
Logger.error(e, {
344+
context: "control_plane_check_remote_sessions_enabled",
345+
});
346+
return false;
347+
}
348+
}
349+
350+
/**
351+
* Get current user's session info
352+
*/
353+
public async getSessionInfo(): Promise<ControlPlaneSessionInfo | undefined> {
354+
return await this.sessionInfoPromise;
355+
}
356+
357+
/**
358+
* Fetch remote agents/sessions from the control plane
359+
* Currently restricted to @continue.dev emails for internal use
360+
*/
361+
public async listRemoteSessions(): Promise<RemoteSessionMetadata[]> {
362+
if (!(await this.isSignedIn())) {
363+
return [];
364+
}
365+
366+
try {
367+
// Note: This endpoint is currently restricted to internal @continue.dev users
368+
// In the future, this may be expanded to support broader remote session access
369+
const resp = await this.requestAndHandleError("agents/devboxes", {
370+
method: "GET",
371+
});
372+
373+
const agents = (await resp.json()) as any[];
374+
375+
return agents.map(
376+
(agent: any): RemoteSessionMetadata => ({
377+
sessionId: `remote-${agent.id}`,
378+
title: agent.name || "Remote Agent",
379+
dateCreated: new Date(agent.create_time_ms).toISOString(),
380+
workspaceDirectory: "",
381+
isRemote: true,
382+
remoteId: agent.id,
383+
}),
384+
);
385+
} catch (e) {
386+
// Log error but don't throw - remote sessions are optional
387+
Logger.error(e, {
388+
context: "control_plane_list_remote_sessions",
389+
});
390+
return [];
391+
}
392+
}
393+
394+
public async loadRemoteSession(remoteId: string): Promise<Session> {
395+
if (!(await this.isSignedIn())) {
396+
throw new Error("Not signed in to load remote session");
397+
}
398+
399+
try {
400+
// First get the tunnel URL for the remote agent
401+
const tunnelResp = await this.requestAndHandleError(
402+
`agents/devboxes/${remoteId}/tunnel`,
403+
{
404+
method: "POST",
405+
},
406+
);
407+
408+
const tunnelData = (await tunnelResp.json()) as { url?: string };
409+
const tunnelUrl = tunnelData.url;
410+
411+
if (!tunnelUrl) {
412+
throw new Error(`Failed to get tunnel URL for agent ${remoteId}`);
413+
}
414+
415+
// Now fetch the session state from the remote agent's /state endpoint
416+
const stateResponse = await fetch(`${tunnelUrl}/state`);
417+
if (!stateResponse.ok) {
418+
throw new Error(
419+
`Failed to fetch state from remote agent: ${stateResponse.statusText}`,
420+
);
421+
}
422+
423+
const remoteState = (await stateResponse.json()) as { session?: Session };
424+
425+
// The remote state contains a session property with the full session data
426+
if (!remoteState.session) {
427+
throw new Error(
428+
"Remote agent returned invalid state - no session found",
429+
);
430+
}
431+
432+
return remoteState.session;
433+
} catch (e) {
434+
Logger.error(e, {
435+
context: "control_plane_load_remote_session",
436+
remoteId,
437+
});
438+
throw new Error(
439+
`Failed to load remote session: ${e instanceof Error ? e.message : "Unknown error"}`,
440+
);
441+
}
442+
}
306443
}

0 commit comments

Comments
 (0)