Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .github/workflows/pull-request-check-licenses.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,8 @@ jobs:
docker run --rm -t \
-v $PWD/code/extensions/che-terminal:/workspace/project \
quay.io/che-incubator/dash-licenses:next --check
- name: Check che-keybindings dependencies usage restrictions
run: |
docker run --rm -t \
-v $PWD/code/extensions/che-keybindings:/workspace/project \
quay.io/che-incubator/dash-licenses:next --check
1 change: 1 addition & 0 deletions code/build/gulpfile.extensions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const compilations = [
'extensions/che-terminal/tsconfig.json',
'extensions/che-telemetry/tsconfig.json',
'extensions/che-github-authentication/tsconfig.json',
'extensions/che-keybindings/tsconfig.json',
'extensions/configuration-editing/tsconfig.json',
'extensions/css-language-features/client/tsconfig.json',
'extensions/css-language-features/server/tsconfig.json',
Expand Down
1 change: 1 addition & 0 deletions code/build/npm/dirs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export const dirs = [
'extensions/che-resource-monitor',
'extensions/che-terminal',
'extensions/che-github-authentication',
'extensions/che-keybindings',
'extensions/configuration-editing',
'extensions/copilot',
'extensions/css-language-features',
Expand Down
8 changes: 8 additions & 0 deletions code/extensions/che-keybindings/.vscodeignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
build/**
src/**
tests/**
coverage/**
out/**
tsconfig.json
extension.webpack.config.js
yarn.lock
7 changes: 7 additions & 0 deletions code/extensions/che-keybindings/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Che Workspace Key Bindings for Visual Studio Code

**Notice:** This extension is bundled with Visual Studio Code. It can be disabled but not uninstalled.

## Features

This extension handles Key Bindings of Che workspace on Visual Studio Code
30 changes: 30 additions & 0 deletions code/extensions/che-keybindings/esbuild.mts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/**********************************************************************
* Copyright (c) 2026 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/
/*
* This file was generated using AI assistance (Cursor AI)
* and reviewed by the maintainers.
*/
import * as path from 'node:path';
import { run } from '../esbuild-extension-common.mts';

const srcDir = path.join(import.meta.dirname, 'src');
const outDir = path.join(import.meta.dirname, 'dist');

run({
platform: 'node',
entryPoints: {
'extension': path.join(srcDir, 'extension.ts'),
},
srcDir,
outdir: outDir,
additionalOptions: {
external: ['vscode', 'bufferutil', 'utf-8-validate'],
},
}, process.argv);
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
153 changes: 153 additions & 0 deletions code/extensions/che-keybindings/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

48 changes: 48 additions & 0 deletions code/extensions/che-keybindings/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
{
"name": "keybindings",
"displayName": "%displayName%",
"description": "%description%",
"publisher": "eclipse-che",
"license": "EPL-2.0",
"version": "0.0.1",
"engines": {
"vscode": "^1.88.0"
},
"icon": "images/eclipse-che-logo.png",
"categories": [
"Other"
],
"activationEvents": [
"*"
],
"capabilities": {
"virtualWorkspaces": true,
"untrustedWorkspaces": {
"supported": true
}
},
"main": "./out/extension.js",
"scripts": {
"compile": "gulp compile-extension:che-keybindings",
"watch": "gulp watch-extension:che-keybindings",
"vscode:prepublish": "npm run compile",
"lint:fix": "eslint --fix --cache=true --no-error-on-unmatched-pattern=true \"{src,tests}/**/*.{ts,tsx}\"",
"license:generate": "podman run --rm -t -v $PWD:/workspace/project quay.io/che-incubator/dash-licenses:next"
},
"repository": {
"type": "git",
"url": "https://github.com/che-incubator/che-code.git"
},
"extensionDependencies": [
"eclipse-che.api",
"eclipse-che.terminal"
],
"dependencies": {
"node-fetch": "^3.3.2"
},
"devDependencies": {
"@types/node": "^20.10.5",
"typescript": "^5.3.3",
"@types/vscode": "^1.85.0"
}
}
4 changes: 4 additions & 0 deletions code/extensions/che-keybindings/package.nls.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"displayName": "Eclipse Che Keybindings",
"description": "Provides Keybindings support"
}
90 changes: 90 additions & 0 deletions code/extensions/che-keybindings/src/cheAPi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**********************************************************************
* Copyright (c) 2025 Red Hat, Inc.
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
***********************************************************************/

/* eslint-disable header/header */
import * as vscode from "vscode";

export interface KeybindingsResponse {
keybindingsJson: string;

meta?: {
clientId?: string;
resourceVersion?: string;
};
}
Comment on lines +14 to +21

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Map the relevant file and inspect the surrounding code paths.
git ls-files code/extensions/che-keybindings/src/cheAPi.ts
wc -l code/extensions/che-keybindings/src/cheAPi.ts
cat -n code/extensions/che-keybindings/src/cheAPi.ts | sed -n '1,220p'

# Find all uses of resourceVersion / clientId in this extension.
rg -n "resourceVersion|clientId|patchKeybindings|getKeybindings" code/extensions/che-keybindings -S

Repository: che-incubator/che-code

Length of output: 4834


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the caller to understand whether conflict detection is handled elsewhere.
cat -n code/extensions/che-keybindings/src/syncManager.ts | sed -n '1,220p'

# Search for any backend or protocol references to resourceVersion / optimistic concurrency.
rg -n "resourceVersion|If-Match|etag|conflict|409|clientId" -S .

Repository: che-incubator/che-code

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read the sync flow and any local handling of server metadata.
cat -n code/extensions/che-keybindings/src/syncManager.ts | sed -n '1,220p'
cat -n code/extensions/che-keybindings/src/utils.ts | sed -n '1,160p'

# Search only within the che-keybindings extension for protocol fields and conflict handling.
rg -n "resourceVersion|If-Match|etag|conflict|409|meta\\." code/extensions/che-keybindings/src -S

Repository: che-incubator/che-code

Length of output: 7234


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Locate the backend API and any schema that mentions keybindingsJson/resourceVersion.
rg -n "keybindingsJson|resourceVersion|clientId" code -S

Repository: che-incubator/che-code

Length of output: 50378


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Read only the relevant sync manager logic and any local API/schema references.
sed -n '1,220p' code/extensions/che-keybindings/src/syncManager.ts | cat -n
sed -n '1,140p' code/extensions/che-keybindings/src/utils.ts | cat -n

# Search narrowly for backend or protocol handling of keybinding metadata.
rg -n "/keybindings|resourceVersion|clientId|If-Match|409" code/extensions/che-keybindings code/src -S --glob '!**/node_modules/**'

Repository: che-incubator/che-code

Length of output: 50380


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Find the backend implementation or docs for the keybindings API only.
rg -n "/namespace/.*/keybindings|keybindingsJson|resourceVersion" code/extensions code/src -S --glob '!**/node_modules/**' --max-count 200

Repository: che-incubator/che-code

Length of output: 2036


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Narrow to the che-keybindings extension files to see whether resourceVersion is propagated anywhere else.
rg -n "resourceVersion|patchKeybindings|getKeybindings|keybindingsJson|clientId" code/extensions/che-keybindings/src -S --max-count 80

Repository: che-incubator/che-code

Length of output: 2847


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect any docs or tests that describe the keybindings sync payload/semantics.
fd -a -t f -g '*keybindings*' code/extensions/che-keybindings code | sed -n '1,200p'
rg -n "che-keybindings|keybindings sync|resourceVersion|clientId" code/extensions/che-keybindings -S --glob '!**/node_modules/**'

Repository: che-incubator/che-code

Length of output: 4071


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the built-in user data sync model for how resourceVersion is treated.
rg -n "resourceVersion" code/src/vs/platform/userDataSync code/src/vs/workbench/services/userDataProfile -S --max-count 80

Repository: che-incubator/che-code

Length of output: 160


Thread resourceVersion through PATCH to prevent stale overwrites. clientId only suppresses self-echoes on pull; it does not detect concurrent edits. A second client can still overwrite newer keybindings without any conflict signal.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/extensions/che-keybindings/src/cheAPi.ts` around lines 14 - 21, The
KeybindingsResponse metadata currently carries clientId only, which filters
self-echoes but does not protect against concurrent updates. Thread
resourceVersion through the PATCH flow in the keybindings API and related
handling so updates include and compare the latest version before writing, using
the existing KeybindingsResponse.meta shape and any PATCH handler or client
methods that consume it.


const API = "/api";

export async function getKeybindings(
namespace: string,
output?: vscode.OutputChannel,
): Promise<KeybindingsResponse | null> {
output?.appendLine(`[API] GET ${API}/namespace/${namespace}/keybindings`);

const res = await fetch(`${API}/namespace/${namespace}/keybindings`, {
credentials: "include",
});

output?.appendLine(`[API] GET Status: ${res.status}`);

if (!res.ok) {
output?.appendLine(`[API] GET Failed: ${await res.text()}`);
return null;
}

const data = (await res.json()) as KeybindingsResponse;

output?.appendLine(
`[API] GET Success - Received ${data.keybindingsJson.length} bytes`,
);

if (data.meta) {
output?.appendLine(
`[API] Meta => clientId=${data.meta.clientId ?? "N/A"}, resourceVersion=${data.meta.resourceVersion ?? "N/A"}`,
);
}

return data;
}
Comment on lines +25 to +55

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🩺 Stability & Availability | 🔴 Critical | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Files:\n'
git ls-files | rg '(^|/)code/extensions/che-keybindings/src/(cheAPi|syncManager|.*types.*|.*api.*)\.(ts|tsx|js|jsx)$|(^|/)code/extensions/che-keybindings/src/'

printf '\nOutline cheAPi.ts:\n'
ast-grep outline code/extensions/che-keybindings/src/cheAPi.ts --view expanded || true

printf '\nOutline syncManager.ts:\n'
ast-grep outline code/extensions/che-keybindings/src/syncManager.ts --view expanded || true

printf '\nRelevant type/search hits:\n'
rg -n "resourceVersion|AbortSignal\.timeout|fetch\(" code/extensions/che-keybindings/src -S

Repository: che-incubator/che-code

Length of output: 1629


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo '--- cheAPi.ts (1-140) ---'
cat -n code/extensions/che-keybindings/src/cheAPi.ts | sed -n '1,140p'

echo
echo '--- syncManager.ts (1-220) ---'
cat -n code/extensions/che-keybindings/src/syncManager.ts | sed -n '1,220p'

Repository: che-incubator/che-code

Length of output: 8701


🏁 Script executed:

#!/bin/bash
set -euo pipefail

printf 'Search for resourceVersion and keybindings API server:\n'
rg -n "resourceVersion|namespace/.*/keybindings|keybindingsJson|clientId" . -S

printf '\nPotential server-side files:\n'
git ls-files | rg '(^|/)(server|backend|api|routes|handlers|controllers|services|src)/.*\.(ts|js|tsx|jsx)$' | head -n 200

Repository: che-incubator/che-code

Length of output: 50378


Add a timeout to both keybinding API calls. getKeybindings() and patchKeybindings() can hang forever on a stalled backend, which blocks sync work and can stack up overlapping poll requests. Use an abort signal/timeout on both fetch() calls.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@code/extensions/che-keybindings/src/cheAPi.ts` around lines 25 - 55, Both
keybinding API requests can hang indefinitely, so add a timeout-driven abort
signal to the fetch calls in getKeybindings and patchKeybindings. Update the
request flow in cheAPi.ts to create an AbortController (or equivalent timeout
helper), pass its signal into each fetch, and ensure the timeout is cleared once
the request completes. Keep the existing logging and return behavior unchanged,
but make sure stalled backend calls fail fast instead of blocking sync or piling
up overlapping polls.


export async function patchKeybindings(
namespace: string,
keybindingsJson: string,
clientId: string,
output?: vscode.OutputChannel,
): Promise<void> {
output?.appendLine(`[API] PATCH ${API}/namespace/${namespace}/keybindings`);
output?.appendLine(`[API] Payload Size: ${keybindingsJson.length} bytes`);
output?.appendLine(`[API] Client ID: ${clientId}`);

const res = await fetch(`${API}/namespace/${namespace}/keybindings`, {
method: "PATCH",
credentials: "include",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
keybindingsJson,
meta: {
clientId,
},
}),
});

output?.appendLine(`[API] PATCH Status: ${res.status}`);

if (!res.ok) {
const error = await res.text();
output?.appendLine(`[API] PATCH Failed: ${error}`);
throw new Error(error);
}

output?.appendLine("[API] PATCH Successful.");
}
Loading
Loading