Skip to content

Commit d0386d0

Browse files
committed
resolve conflict
2 parents ac8d5fd + a001bea commit d0386d0

File tree

8 files changed

+125
-24
lines changed

8 files changed

+125
-24
lines changed

.prettierrc

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
],
1010
"options": {
1111
"printWidth": 80,
12-
"proseWrap": "always"
12+
"proseWrap": "preserve"
1313
}
1414
}
1515
]

CHANGELOG.md

+12
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22

33
## Unreleased
44

5+
## [v1.6.0](https://github.com/coder/vscode-coder/releases/tag/v1.6.0) (2025-04-01)
6+
7+
### Added
8+
9+
- Add support for Coder inbox.
10+
11+
## [v1.5.0](https://github.com/coder/vscode-coder/releases/tag/v1.5.0) (2025-03-20)
12+
13+
### Fixed
14+
15+
- Fixed regression where autostart needed to be disabled.
16+
517
### Changed
618

719
- Make the MS Remote SSH extension part of an extension pack rather than a hard dependency, to enable

README.md

+11-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# Coder Remote
22

33
[![Visual Studio Marketplace](https://vsmarketplacebadges.dev/version/coder.coder-remote.svg)](https://marketplace.visualstudio.com/items?itemName=coder.coder-remote)
4+
[![Open VSX Version](https://img.shields.io/open-vsx/v/coder/coder-remote)](https://open-vsx.org/extension/coder/coder-remote)
45
[!["Join us on
56
Discord"](https://badgen.net/discord/online-members/coder)](https://coder.com/chat?utm_source=github.com/coder/vscode-coder&utm_medium=github&utm_campaign=readme.md)
67

@@ -13,11 +14,11 @@ workspaces with a single click.
1314
- Works in air-gapped or restricted networks. Just connect to your Coder
1415
deployment!
1516
- Supports multiple editors: VS Code, Cursor, and Windsurf.
16-
> [!NOTE]
17-
> The extension builds on VSCode provided implementations of SSH. Make sure
18-
> you have the correct ssh extension installed for your editor
19-
> (ms-vscode-remote.remote-ssh or codeium.windsurf-remote-openssh for
20-
> windsurf)
17+
18+
> [!NOTE]
19+
> The extension builds on VS Code-provided implementations of SSH. Make
20+
> sure you have the correct SSH extension installed for your editor
21+
> (`ms-vscode-remote.remote-ssh` or `codeium.windsurf-remote-openssh` for Windsurf).
2122
2223
![Demo](https://github.com/coder/vscode-coder/raw/main/demo.gif?raw=true)
2324

@@ -26,19 +27,18 @@ workspaces with a single click.
2627
Launch VS Code Quick Open (Ctrl+P), paste the following command, and press
2728
enter.
2829

29-
```text
30+
```shell
3031
ext install coder.coder-remote
3132
```
3233

3334
Alternatively, manually install the VSIX from the
3435
[latest release](https://github.com/coder/vscode-coder/releases/latest).
3536

36-
#### Variables Reference
37+
### Variables Reference
3738

38-
Coder uses
39-
${userHome} from VS Code's
39+
Coder uses `${userHome}` from VS Code's
4040
[variables reference](https://code.visualstudio.com/docs/editor/variables-reference).
41-
Use this when formatting paths in the Coder extension settings rather than ~ or
42-
$HOME.
41+
Use this when formatting paths in the Coder extension settings rather than `~`
42+
or `$HOME`.
4343

4444
Example: ${userHome}/foo/bar.baz

package.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
"displayName": "Coder",
55
"description": "Open any workspace with a single click.",
66
"repository": "https://github.com/coder/vscode-coder",
7-
"version": "1.4.2",
7+
"version": "1.6.0",
88
"engines": {
99
"vscode": "^1.73.0"
1010
},
@@ -328,7 +328,7 @@
328328
"webpack-cli": "^5.1.4"
329329
},
330330
"dependencies": {
331-
"axios": "1.7.7",
331+
"axios": "1.8.4",
332332
"date-fns": "^3.6.0",
333333
"eventsource": "^3.0.5",
334334
"find-process": "^1.4.7",

src/api.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ export function needToken(): boolean {
2828
/**
2929
* Create a new agent based off the current settings.
3030
*/
31-
async function createHttpAgent(): Promise<ProxyAgent> {
31+
export async function createHttpAgent(): Promise<ProxyAgent> {
3232
const cfg = vscode.workspace.getConfiguration()
3333
const insecure = Boolean(cfg.get("coder.insecure"))
3434
const certFile = expandPath(String(cfg.get("coder.tlsCertFile") ?? "").trim())

src/inbox.ts

+83
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import { Api } from "coder/site/src/api/api"
2+
import { Workspace, GetInboxNotificationResponse } from "coder/site/src/api/typesGenerated"
3+
import { ProxyAgent } from "proxy-agent"
4+
import * as vscode from "vscode"
5+
import { WebSocket } from "ws"
6+
import { errToStr } from "./api-helper"
7+
import { type Storage } from "./storage"
8+
9+
// These are the template IDs of our notifications.
10+
// Maybe in the future we should avoid hardcoding
11+
// these in both coderd and here.
12+
const TEMPLATE_WORKSPACE_OUT_OF_MEMORY = "a9d027b4-ac49-4fb1-9f6d-45af15f64e7a"
13+
const TEMPLATE_WORKSPACE_OUT_OF_DISK = "f047f6a3-5713-40f7-85aa-0394cce9fa3a"
14+
15+
export class Inbox implements vscode.Disposable {
16+
readonly #storage: Storage
17+
#disposed = false
18+
#socket: WebSocket
19+
20+
constructor(workspace: Workspace, httpAgent: ProxyAgent, restClient: Api, storage: Storage) {
21+
this.#storage = storage
22+
23+
const baseUrlRaw = restClient.getAxiosInstance().defaults.baseURL
24+
if (!baseUrlRaw) {
25+
throw new Error("No base URL set on REST client")
26+
}
27+
28+
const watchTemplates = [TEMPLATE_WORKSPACE_OUT_OF_DISK, TEMPLATE_WORKSPACE_OUT_OF_MEMORY]
29+
const watchTemplatesParam = encodeURIComponent(watchTemplates.join(","))
30+
31+
const watchTargets = [workspace.id]
32+
const watchTargetsParam = encodeURIComponent(watchTargets.join(","))
33+
34+
// We shouldn't need to worry about this throwing. Whilst `baseURL` could
35+
// be an invalid URL, that would've caused issues before we got to here.
36+
const baseUrl = new URL(baseUrlRaw)
37+
const socketProto = baseUrl.protocol === "https:" ? "wss:" : "ws:"
38+
const socketUrl = `${socketProto}//${baseUrl.host}/api/v2/notifications/inbox/watch?format=plaintext&templates=${watchTemplatesParam}&targets=${watchTargetsParam}`
39+
40+
const coderSessionTokenHeader = "Coder-Session-Token"
41+
this.#socket = new WebSocket(new URL(socketUrl), {
42+
followRedirects: true,
43+
agent: httpAgent,
44+
headers: {
45+
[coderSessionTokenHeader]: restClient.getAxiosInstance().defaults.headers.common[coderSessionTokenHeader] as
46+
| string
47+
| undefined,
48+
},
49+
})
50+
51+
this.#socket.on("open", () => {
52+
this.#storage.writeToCoderOutputChannel("Listening to Coder Inbox")
53+
})
54+
55+
this.#socket.on("error", (error) => {
56+
this.notifyError(error)
57+
this.dispose()
58+
})
59+
60+
this.#socket.on("message", (data) => {
61+
try {
62+
const inboxMessage = JSON.parse(data.toString()) as GetInboxNotificationResponse
63+
64+
vscode.window.showInformationMessage(inboxMessage.notification.title)
65+
} catch (error) {
66+
this.notifyError(error)
67+
}
68+
})
69+
}
70+
71+
dispose() {
72+
if (!this.#disposed) {
73+
this.#storage.writeToCoderOutputChannel("No longer listening to Coder Inbox")
74+
this.#socket.close()
75+
this.#disposed = true
76+
}
77+
}
78+
79+
private notifyError(error: unknown) {
80+
const message = errToStr(error, "Got empty error while monitoring Coder Inbox")
81+
this.#storage.writeToCoderOutputChannel(message)
82+
}
83+
}

src/remote.ts

+8-2
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,13 @@ import * as path from "path"
99
import prettyBytes from "pretty-bytes"
1010
import * as semver from "semver"
1111
import * as vscode from "vscode"
12-
import { makeCoderSdk, needToken, startWorkspaceIfStoppedOrFailed, waitForBuild } from "./api"
12+
import { createHttpAgent, makeCoderSdk, needToken, startWorkspaceIfStoppedOrFailed, waitForBuild } from "./api"
1313
import { extractAgents } from "./api-helper"
1414
import * as cli from "./cliManager"
1515
import { Commands } from "./commands"
1616
import { featureSetForVersion, FeatureSet } from "./featureSet"
1717
import { getHeaderCommand } from "./headers"
18+
import { Inbox } from "./inbox"
1819
import { SSHConfig, SSHValues, mergeSSHConfigValues } from "./sshConfig"
1920
import { computeSSHProperties, sshSupportsSetEnv } from "./sshSupport"
2021
import { Storage } from "./storage"
@@ -403,6 +404,11 @@ export class Remote {
403404
disposables.push(monitor)
404405
disposables.push(monitor.onChange.event((w) => (this.commands.workspace = w)))
405406

407+
// Watch coder inbox for messages
408+
const httpAgent = await createHttpAgent()
409+
const inbox = new Inbox(workspace, httpAgent, workspaceRestClient, this.storage)
410+
disposables.push(inbox)
411+
406412
// Wait for the agent to connect.
407413
if (agent.status === "connecting") {
408414
this.storage.writeToCoderOutputChannel(`Waiting for ${workspaceName}/${agent.name}...`)
@@ -627,7 +633,7 @@ export class Remote {
627633
const proxyCommand = featureSet.wildcardSSH
628634
? `${escape(binaryPath)}${headerArg} --global-config ${escape(
629635
path.dirname(this.storage.getSessionTokenPath(label)),
630-
)} ssh --stdio --usage-app=vscode --network-info-dir ${escape(this.storage.getNetworkInfoPath())}${await this.formatLogArg(logDir)} --ssh-host-prefix ${hostPrefix} %h`
636+
)} ssh --stdio --usage-app=vscode --disable-autostart --network-info-dir ${escape(this.storage.getNetworkInfoPath())}${await this.formatLogArg(logDir)} --ssh-host-prefix ${hostPrefix} %h`
631637
: `${escape(binaryPath)}${headerArg} vscodessh --network-info-dir ${escape(
632638
this.storage.getNetworkInfoPath(),
633639
)}${await this.formatLogArg(logDir)} --session-token-file ${escape(this.storage.getSessionTokenPath(label))} --url-file ${escape(

yarn.lock

+7-7
Original file line numberDiff line numberDiff line change
@@ -1200,10 +1200,10 @@ available-typed-arrays@^1.0.7:
12001200
dependencies:
12011201
possible-typed-array-names "^1.0.0"
12021202

1203-
axios@1.7.7:
1204-
version "1.7.7"
1205-
resolved "https://registry.yarnpkg.com/axios/-/axios-1.7.7.tgz#2f554296f9892a72ac8d8e4c5b79c14a91d0a47f"
1206-
integrity sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==
1203+
axios@1.8.4:
1204+
version "1.8.4"
1205+
resolved "https://registry.yarnpkg.com/axios/-/axios-1.8.4.tgz#78990bb4bc63d2cae072952d374835950a82f447"
1206+
integrity sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==
12071207
dependencies:
12081208
follow-redirects "^1.15.6"
12091209
form-data "^4.0.0"
@@ -5986,9 +5986,9 @@ tapable@^2.1.1, tapable@^2.2.0:
59865986
integrity sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==
59875987

59885988
tar-fs@^2.0.0:
5989-
version "2.1.1"
5990-
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.1.tgz#489a15ab85f1f0befabb370b7de4f9eb5cbe8784"
5991-
integrity sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==
5989+
version "2.1.2"
5990+
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.1.2.tgz#425f154f3404cb16cb8ff6e671d45ab2ed9596c5"
5991+
integrity sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==
59925992
dependencies:
59935993
chownr "^1.1.1"
59945994
mkdirp-classic "^0.5.2"

0 commit comments

Comments
 (0)