Skip to content
Open
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
Original file line number Diff line number Diff line change
Expand Up @@ -39,9 +39,6 @@ export default new class NoBracketNotationForIdentifiers implements eslint.Rule.
* Check if a string is a valid JavaScript identifier
*/
function isValidIdentifier(str: string): boolean {
if (str.includes('\\')) {
return false;
}
const scanner = ts.createScanner(ts.ScriptTarget.Latest, false, ts.LanguageVariant.Standard, str);
const token = scanner.scan();
const isIdentifierName = token === ts.SyntaxKind.Identifier
Expand All @@ -63,6 +60,11 @@ export default new class NoBracketNotationForIdentifiers implements eslint.Rule.
return;
}

// Preserve escaped property names instead of replacing their authored representation.
if (memberExpr.property.raw.includes('\\')) {
return;
}

const propertyName = memberExpr.property.value;

// If it's a valid identifier, report it
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,12 @@ tampered with. The merged bag is then projected onto the declared schema (see be
Client-side merging still happens *within* a channel's value (e.g. `enabledPlugins`,
`extraKnownMarketplaces`).

**Sandbox routing exception:** `sandbox.enabled` follows the runtime's `force-on-wins`
contract: `true` from any managed channel wins over `false` from another channel.
The shared resolver supplies this result to harness selection, permissions UI, and
Policy Diagnostics; runtime enforcement remains authoritative. Other keys retain
their existing delivery-channel precedence.

## Schema source of truth

When the developer has `copilot-agent-runtime` checked out side-by-side, reference
Expand Down
2 changes: 1 addition & 1 deletion .vscode/notebooks/endgame.github-issues
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$MILESTONE=milestone:\"1.136.0\"\n\n$TPI_CREATION=2026-03-23 // Used to find fixes that need to be verified"
"value": "$MILESTONE=milestone:\"1.137.0\"\n\n$TPI_CREATION=2026-03-23 // Used to find fixes that need to be verified"
},
{
"kind": 1,
Expand Down
2 changes: 1 addition & 1 deletion .vscode/notebooks/my-endgame.github-issues
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
{
"kind": 2,
"language": "github-issues",
"value": "$MILESTONE=milestone:\"1.136.0\"\n\n$MINE=assignee:@me"
"value": "$MILESTONE=milestone:\"1.137.0\"\n\n$MINE=assignee:@me"
},
{
"kind": 2,
Expand Down
40 changes: 14 additions & 26 deletions build/azure-pipelines/common/apply-sdk-canary-override.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,9 @@ import { execFileSync } from 'child_process';
* node_modules cache key, derived from these manifests + lockfiles, naturally
* misses).
*
* Driven by environment variables so it is a no-op in normal builds:
* VSCODE_SDK_CANARY_VERSION - version to pin `@github/copilot-sdk` to (empty =
* no override / normal build). The sentinel
* `latest-canary` resolves to the newest
* `@github/copilot-sdk` canary on the feed here,
* inside the build.
* VSCODE_CLI_CANARY_VERSION - version to pin `@github/copilot` to. When empty
* (and an SDK version is set) the CLI version is
* inferred from the SDK's own `@github/copilot`
* dependency so the two stay compatible. When set
* explicitly, it is validated against that same
* dependency range and the build fails fast on a
* confirmed incompatible SDK/CLI pair.
* Driven by environment variables so SDK and runtime overrides can be applied
* independently. Product builds use an exact checked-in runtime parameter
* default while retaining the SDK version from the OSS manifest.
*
* npm registry + auth must already be configured in the ambient environment
* (the orchestrator authenticates to the private feed before invoking this).
Expand Down Expand Up @@ -150,9 +140,7 @@ function assertCliSatisfiesSdk(sdkVersion: string, cliVersion: string): void {
* orchestrator that queues the build never needs feed-read access.
*
* Canary versions look like `X.Y.Z-canary.<N>.g<sha>`; "newest" is the highest
* `[X, Y, Z, N]` tuple (numeric, so `canary.9` < `canary.10`). The resolved
* concrete version is also emitted as an ADO build tag (`sdk-canary=<version>`)
* so the orchestrator can read it back for accurate Slack reporting.
* `[X, Y, Z, N]` tuple (numeric, so `canary.9` < `canary.10`).
*/
function resolveLatestCanary(): string {
const versionsRaw = execFileSync(NPM, ['view', '@github/copilot-sdk', 'versions', '--json'], { encoding: 'utf8', shell: IS_WINDOWS });
Expand Down Expand Up @@ -189,28 +177,28 @@ function resolveLatestCanary(): string {

function collectOverrides(): Override[] {
let sdkVersion = (process.env['VSCODE_SDK_CANARY_VERSION'] ?? '').trim();
if (!sdkVersion) {
return [];
}
const explicitCli = (process.env['VSCODE_CLI_CANARY_VERSION'] ?? '').trim();
// `latest-canary` sentinel: resolve the newest published @github/copilot-sdk
// canary here, inside the build, where private-feed npm auth already exists —
// so the GitHub-side orchestrator that queues this build never needs
// feed-read access.
if (sdkVersion === 'latest-canary') {
sdkVersion = resolveLatestCanary();
}
assertSafeSpec('SDK canary version', sdkVersion);
const overrides: Override[] = [{ name: '@github/copilot-sdk', version: sdkVersion }];
const overrides: Override[] = [];
if (sdkVersion) {
assertSafeSpec('SDK canary version', sdkVersion);
overrides.push({ name: '@github/copilot-sdk', version: sdkVersion });
}

// Explicit CLI version wins (but must be compatible with the SDK); empty
// means "infer a compatible CLI from the SDK".
const explicitCli = (process.env['VSCODE_CLI_CANARY_VERSION'] ?? '').trim();
let cliVersion: string | undefined;
if (explicitCli) {
assertSafeSpec('CLI canary version', explicitCli);
assertCliSatisfiesSdk(sdkVersion, explicitCli);
if (sdkVersion) {
assertCliSatisfiesSdk(sdkVersion, explicitCli);
}
cliVersion = explicitCli;
} else {
} else if (sdkVersion) {
cliVersion = inferCliVersion(sdkVersion);
}
if (cliVersion) {
Expand Down
12 changes: 6 additions & 6 deletions build/azure-pipelines/common/apply-sdk-canary.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# SDK canary integration (no-op unless VSCODE_SDK_CANARY_VERSION is set).
# Copilot product dependency integration (no-op unless an override is set).
# Overrides @github/copilot-sdk / @github/copilot to a version published to the
# private feed and refreshes the lockfile so the node_modules cache key below
# misses and `npm ci` installs the canary. Authenticates to the feed first so
Expand All @@ -16,32 +16,32 @@ steps:
- powershell: |
npm config set registry $env:NPM_REGISTRY
Write-Host "##vso[task.setvariable variable=SDK_CANARY_NPMRC_PATH]$(npm config get userconfig)"
condition: and(succeeded(), ne(variables['VSCODE_SDK_CANARY_VERSION'], ''))
condition: and(succeeded(), or(ne(variables['VSCODE_SDK_CANARY_VERSION'], ''), ne(variables['VSCODE_CLI_CANARY_VERSION'], '')))
displayName: SDK canary — set registry for auth
- ${{ else }}:
- script: |
set -e
npm config set registry "$NPM_REGISTRY"
echo "##vso[task.setvariable variable=SDK_CANARY_NPMRC_PATH]$(npm config get userconfig)"
condition: and(succeeded(), ne(variables['VSCODE_SDK_CANARY_VERSION'], ''))
condition: and(succeeded(), or(ne(variables['VSCODE_SDK_CANARY_VERSION'], ''), ne(variables['VSCODE_CLI_CANARY_VERSION'], '')))
displayName: SDK canary — set registry for auth

- task: npmAuthenticate@0
inputs:
workingFile: $(SDK_CANARY_NPMRC_PATH)
condition: and(succeeded(), ne(variables['VSCODE_SDK_CANARY_VERSION'], ''))
condition: and(succeeded(), or(ne(variables['VSCODE_SDK_CANARY_VERSION'], ''), ne(variables['VSCODE_CLI_CANARY_VERSION'], '')))
displayName: SDK canary — authenticate feed

- ${{ if eq(parameters.windows, true) }}:
- powershell: node build/azure-pipelines/common/apply-sdk-canary-override.ts
condition: and(succeeded(), ne(variables['VSCODE_SDK_CANARY_VERSION'], ''))
condition: and(succeeded(), or(ne(variables['VSCODE_SDK_CANARY_VERSION'], ''), ne(variables['VSCODE_CLI_CANARY_VERSION'], '')))
env:
VSCODE_SDK_CANARY_VERSION: $(VSCODE_SDK_CANARY_VERSION)
VSCODE_CLI_CANARY_VERSION: $(VSCODE_CLI_CANARY_VERSION)
displayName: Apply SDK canary override
- ${{ else }}:
- script: node build/azure-pipelines/common/apply-sdk-canary-override.ts
condition: and(succeeded(), ne(variables['VSCODE_SDK_CANARY_VERSION'], ''))
condition: and(succeeded(), or(ne(variables['VSCODE_SDK_CANARY_VERSION'], ''), ne(variables['VSCODE_CLI_CANARY_VERSION'], '')))
env:
VSCODE_SDK_CANARY_VERSION: $(VSCODE_SDK_CANARY_VERSION)
VSCODE_CLI_CANARY_VERSION: $(VSCODE_CLI_CANARY_VERSION)
Expand Down
2 changes: 1 addition & 1 deletion build/azure-pipelines/darwin/product-build-darwin-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ parameters:
jobs:
- job: macOS${{ parameters.VSCODE_TEST_SUITE }}
displayName: ${{ parameters.VSCODE_TEST_SUITE }} Tests
timeoutInMinutes: 120
timeoutInMinutes: 240
variables:
VSCODE_ARCH: arm64
BUILDS_API_URL: $(System.CollectionUri)$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
jobs:
- job: macOSUniversal
displayName: macOS (UNIVERSAL)
timeoutInMinutes: 120
timeoutInMinutes: 240
variables:
VSCODE_ARCH: universal
BUILDS_API_URL: $(System.CollectionUri)$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/
Expand Down
2 changes: 1 addition & 1 deletion build/azure-pipelines/darwin/product-build-darwin.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ parameters:
jobs:
- job: macOS_${{ parameters.VSCODE_ARCH }}
displayName: macOS (${{ upper(parameters.VSCODE_ARCH) }})
timeoutInMinutes: 120
timeoutInMinutes: 240
variables:
VSCODE_ARCH: ${{ parameters.VSCODE_ARCH }}
BUILDS_API_URL: $(System.CollectionUri)$(System.TeamProject)/_apis/build/builds/$(Build.BuildId)/
Expand Down
13 changes: 6 additions & 7 deletions build/azure-pipelines/product-build-ado-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,17 +73,17 @@ parameters:
displayName: "Use legacy OSS Notice"
type: boolean
default: false
# SDK -> VS Code integration: override the Copilot dependencies to a version
# already published to the private feed. 'none'/'auto' = normal build.
# SDK -> VS Code integration: override Copilot dependencies with versions
# already published to the private feed. 'none' = use the OSS SDK version.
# See microsoft/vscode-engineering specs/sdk-vscode-integration.spec.md.
- name: VSCODE_SDK_CANARY_VERSION
displayName: "SDK canary: @github/copilot-sdk version ('none' = normal build)"
type: string
default: none
- name: VSCODE_CLI_CANARY_VERSION
displayName: "SDK canary: @github/copilot version ('auto' = infer from the SDK)"
displayName: "Product @github/copilot runtime version ('auto' = infer from an SDK override)"
type: string
default: auto
default: 1.0.84-canary.67.g6496fad.unsigned

variables:
- name: VSCODE_PRIVATE_BUILD
Expand All @@ -94,9 +94,8 @@ variables:
value: false
- name: NPM_REGISTRY
value: ${{ parameters.NPM_REGISTRY }}
# Normalize the canary sentinels ('none'/'auto') back to empty so the gated
# node-modules steps (condition: ne(..., '')) stay a no-op for normal builds
# and the override script infers the CLI when it is empty.
# Normalize sentinels back to empty so the override script can distinguish
# the normal SDK and inferred runtime paths.
- name: VSCODE_SDK_CANARY_VERSION
${{ if eq(parameters.VSCODE_SDK_CANARY_VERSION, 'none') }}:
value: ""
Expand Down
24 changes: 16 additions & 8 deletions build/azure-pipelines/product-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,10 @@ parameters:
values:
- Product
- CI
- name: VSCODE_BUILD_TITLE_PREFIX
displayName: "Build Title Prefix"
type: string
default: none
- name: NPM_REGISTRY
displayName: "Custom NPM Registry"
type: string
Expand Down Expand Up @@ -122,26 +126,30 @@ parameters:
displayName: "Run sanity tests against this build's artifacts (for unpublished builds)"
type: boolean
default: false
# SDK -> VS Code integration: override the Copilot dependencies to a version
# already published to the private feed. 'none'/'auto' = normal build.
# SDK -> VS Code integration: override Copilot dependencies with versions
# already published to the private feed. 'none' = use the OSS SDK version.
# See microsoft/vscode-engineering specs/sdk-vscode-integration.spec.md.
- name: VSCODE_SDK_CANARY_VERSION
displayName: "SDK canary: @github/copilot-sdk version ('none' = normal build)"
type: string
default: none
- name: VSCODE_CLI_CANARY_VERSION
displayName: "SDK canary: @github/copilot version ('auto' = infer from the SDK)"
displayName: "Product @github/copilot runtime version ('auto' = infer from an SDK override)"
type: string
default: auto
default: 1.0.84-canary.67.g6496fad.unsigned

variables:
- name: VSCODE_BUILD_TITLE_PREFIX
${{ if eq(parameters.VSCODE_BUILD_TITLE_PREFIX, 'none') }}:
value: ""
${{ else }}:
value: ${{ parameters.VSCODE_BUILD_TITLE_PREFIX }}
- name: VSCODE_PRIVATE_BUILD
value: ${{ ne(variables['Build.Repository.Uri'], 'https://github.com/microsoft/vscode.git') }}
- name: NPM_REGISTRY
value: ${{ parameters.NPM_REGISTRY }}
# Normalize the canary sentinels ('none'/'auto') back to empty so the gated
# node-modules steps (condition: ne(..., '')) stay a no-op for normal builds
# and the override script infers the CLI when it is empty.
# Normalize sentinels back to empty so the override script can distinguish
# the normal SDK and inferred runtime paths.
- name: VSCODE_SDK_CANARY_VERSION
${{ if eq(parameters.VSCODE_SDK_CANARY_VERSION, 'none') }}:
value: ""
Expand Down Expand Up @@ -217,7 +225,7 @@ variables:
- name: ARTIFACT_PREFIX
value: ''

name: "$(Date:yyyyMMdd).$(Rev:r) (${{ parameters.VSCODE_QUALITY }})"
name: "$(VSCODE_BUILD_TITLE_PREFIX)$(Date:yyyyMMdd).$(Rev:r) (${{ parameters.VSCODE_QUALITY }})"

resources:
repositories:
Expand Down
80 changes: 80 additions & 0 deletions build/lib/test/codeNoBracketNotationForIdentifiers.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import { RuleTester } from 'eslint';
import { suite, test } from 'node:test';
import rule from '../../../.eslint-plugin-local/code-no-bracket-notation-for-identifiers.ts';

RuleTester.describe = suite;
RuleTester.it = test;

new RuleTester().run('code-no-bracket-notation-for-identifiers', rule, {
valid: [
'object.property;',
'object[computedProperty];',
'object[42];',
'object["property-with-dashes"];',
'object["property with spaces"];',
'object[`property`];',
String.raw`object["\u0061"];`,
String.raw`object["a\x62"];`,
],
invalid: [
{
name: 'normal property',
code: 'object["property"];',
output: 'object.property;',
errors: [{ messageId: 'noBracketNotation', data: { property: 'property' } }],
},
{
name: 'private property',
code: 'object["_privateProperty"];',
output: 'object._privateProperty;',
errors: [{ messageId: 'noBracketNotation', data: { property: '_privateProperty' } }],
},
{
name: 'keyword property',
code: 'object["default"];',
output: 'object.default;',
errors: [{ messageId: 'noBracketNotation', data: { property: 'default' } }],
},
{
name: 'Unicode property',
code: 'object["π"];',
output: 'object.π;',
errors: [{ messageId: 'noBracketNotation', data: { property: 'π' } }],
},
{
name: 'optional property access',
code: 'object?.["property"];',
output: 'object?.property;',
errors: [{ messageId: 'noBracketNotation', data: { property: 'property' } }],
},
{
name: 'integer literal property access',
code: '1["toString"];',
output: '(1).toString;',
errors: [{ messageId: 'noBracketNotation', data: { property: 'toString' } }],
},
{
name: 'decimal literal property access',
code: '1.5["toString"];',
output: '(1.5).toString;',
errors: [{ messageId: 'noBracketNotation', data: { property: 'toString' } }],
},
{
name: 'comment before property',
code: 'object[/* comment */"property"];',
output: null,
errors: [{ messageId: 'noBracketNotation', data: { property: 'property' } }],
},
{
name: 'comment after property',
code: 'object["property"/* comment */];',
output: null,
errors: [{ messageId: 'noBracketNotation', data: { property: 'property' } }],
},
],
});
Loading
Loading