Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
b1e7a01
Bump the npm_and_yarn group across 2 directories with 12 updates
dependabot[bot] May 24, 2026
78f9fa0
Merge pull request #8 from sassdawe/dependabot/npm_and_yarn/src/polyg…
sassdawe May 24, 2026
c41851d
Bump the npm_and_yarn group across 4 directories with 14 updates
dependabot[bot] May 24, 2026
a140575
Merge pull request #9 from sassdawe/dependabot/npm_and_yarn/src/polyg…
sassdawe May 24, 2026
b473191
Bump the npm_and_yarn group across 3 directories with 3 updates
dependabot[bot] May 24, 2026
bcc56a2
Merge pull request #10 from sassdawe/dependabot/npm_and_yarn/src/poly…
sassdawe May 24, 2026
4d13c23
Use public npm registry for notebook packages
sassdawe May 24, 2026
554dac3
Fix JS notebook bundle entrypoints
sassdawe May 24, 2026
1162e62
Handle existing tool manifests during activation
sassdawe May 24, 2026
c322756
Normalize package-lock registry URLs
sassdawe May 25, 2026
d6ed7ba
Remove direct uuid deps from JS packages
sassdawe May 25, 2026
ac56518
Remove direct uuid usage from VS Code packages
sassdawe May 25, 2026
6a43e0e
Fix pull request discovery in VS Code extension
sassdawe May 25, 2026
f189a61
Harden tool manifest failure detection in acquisition tests
Copilot May 25, 2026
a5a8bb2
Trim whitespace in acquisition error output
sassdawe May 26, 2026
6b41eca
Refactor acquisition manifest detection helpers
Copilot May 26, 2026
affb5fd
Use secure UUID fallback across packages
Copilot May 26, 2026
5354b0e
Add UUID helper for notebook command/event IDs
sassdawe May 26, 2026
6faf719
Adopt UUID helper in commands and webview activation
sassdawe May 26, 2026
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
3 changes: 1 addition & 2 deletions src/polyglot-notebooks-browser/.npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
registry=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/
always-auth=true
registry=https://registry.npmjs.org/
1,304 changes: 880 additions & 424 deletions src/polyglot-notebooks-browser/package-lock.json

Large diffs are not rendered by default.

12 changes: 5 additions & 7 deletions src/polyglot-notebooks-browser/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
"dist"
],
"scripts": {
"compile": "npm run rollup",
"compile": "tsc -p ./ && npm run rollup",
"compile-ci": "rollup -c rollup.config.js --bundleConfigAsCjs",
"test": "mocha tests/**/*.test.ts",
"ciTest": "node ../ensure-testresults-directory.js && npm test -- --reporter mocha-multi-reporters --reporter-options configFile=testConfig.json",
"rollup": "npm run compile-ci -- -i src/index.ts -o dist/dotnet-interactive.js",
"rollup": "npm run compile-ci -- -i dist/index.js -o dist/dotnet-interactive.js",
"watch": "tsc -watch -p ./"
},
"repository": {
Expand All @@ -32,7 +32,6 @@
"@microsoft/signalr": "7.0.7",
"rxjs": "7.5.6",
"tslib": "2.4.0",
"uuid": "8.3.2",
"vscode-uri": "3.0.6"
},
"devDependencies": {
Expand All @@ -44,17 +43,16 @@
"@types/mocha": "9.1.1",
"@types/node": "22.13.14",
"@types/node-fetch": "2.5.12",
"@types/uuid": "9.0.1",
"chai": "4.3.6",
"chai-as-promised": "7.1.1",
"fetch-mock": "9.11.0",
"mkdirp": "1.0.4",
"mocha": "10.0.0",
"mocha": "10.8.2",
"mocha-multi-reporters": "1.5.1",
"mocha-trx-reporter": "3.3.1",
"node-fetch": "2.6.7",
"requirejs": "2.3.6",
"rollup": "3.26.1",
"requirejs": "2.3.7",
"rollup": "4.60.4",
"rollup-plugin-commonjs": "10.1.0",
"rollup-plugin-node-resolve": "5.2.0",
"rollup-plugin-typescript2": "0.35.0",
Expand Down
3 changes: 1 addition & 2 deletions src/polyglot-notebooks-ui-components/.npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
registry=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/
always-auth=true
registry=https://registry.npmjs.org/
3,284 changes: 1,690 additions & 1,594 deletions src/polyglot-notebooks-ui-components/package-lock.json

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion src/polyglot-notebooks-ui-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@
"ts-mocha": "10.0.0",
"ts-node": "10.8.0",
"typescript": "5.8.3",
"webpack": "5.76.0",
"webpack": "5.107.1",
"webpack-cli": "5.0.1"
},
"dependencies": {
Expand Down
8 changes: 3 additions & 5 deletions src/polyglot-notebooks-vscode-common/src/acquisition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,9 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

import * as fs from 'fs';
import * as path from 'path';
import { InstallInteractiveTool, InstallInteractiveArgs, CreateToolManifest, GetCurrentInteractiveVersion, InteractiveLaunchOptions, ReportInstallationStarted, ReportInstallationFinished } from './interfaces';

import { isVersionExactlyEqual } from './utilities';
import { isVersionExactlyEqual, toolManifestExists } from './utilities';

// The acquisition function. Uses predefined callbacks for external command invocations to make testing easier.
export async function acquireDotnetInteractive(
Expand All @@ -20,12 +19,11 @@ export async function acquireDotnetInteractive(
): Promise<InteractiveLaunchOptions> {
// Ensure `globalStoragePath` exists. This prevents a bunch of issues with spawned processes and working directories.
if (!fs.existsSync(globalStoragePath)) {
fs.mkdirSync(globalStoragePath);
fs.mkdirSync(globalStoragePath, { recursive: true });
}

// create tool manifest if necessary
const toolManifestFile = path.join(globalStoragePath, '.config', 'dotnet-tools.json');
if (!fs.existsSync(toolManifestFile)) {
if (!toolManifestExists(globalStoragePath)) {
await createToolManifest(args.dotnetPath, globalStoragePath);
}

Expand Down
5 changes: 3 additions & 2 deletions src/polyglot-notebooks-vscode-common/src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import { InstallInteractiveArgs, InteractiveLaunchOptions } from './interfaces';
import { ClientMapper } from './clientMapper';
import { getEol, toNotebookDocument } from './vscodeUtilities';
import { DotNetPathManager } from './extension';
import { computeToolInstallArguments, executeSafe, executeSafeAndLog, extensionToDocumentType, getVersionNumber } from './utilities';
import { computeToolInstallArguments, executeSafe, executeSafeAndLog, extensionToDocumentType, getVersionNumber, toolManifestExists } from './utilities';

import * as notebookControllers from './notebookControllers';
import * as metadataUtilities from './metadataUtilities';
Expand Down Expand Up @@ -56,13 +56,14 @@ export async function registerAcquisitionCommands(context: vscode.ExtensionConte
const launchOptions = await acquirePromise;
return launchOptions;
} catch (err) {
acquirePromise = undefined;
diagnosticChannel.appendLine(`Error acquiring dotnet-interactive tool: ${err}`);
}
}));

async function createToolManifest(dotnetPath: string, globalStoragePath: string): Promise<void> {
const result = await executeSafeAndLog(diagnosticChannel, 'create-tool-manifest', dotnetPath, ['new', 'tool-manifest'], globalStoragePath);
if (result.code !== 0) {
if (result.code !== 0 && !toolManifestExists(globalStoragePath)) {
throw new Error(`Unable to create local tool manifest. Command failed with code ${result.code}.\n\nSTDOUT:\n${result.output}\n\nSTDERR:\n${result.error}`);
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/polyglot-notebooks-vscode-common/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,11 @@ async function activateCore(context: vscode.ExtensionContext, diagnosticsChannel

////////////////////////////////////////////////////////////////////////////////
const launchOptions = await getInteractiveLaunchOptions();
if (!launchOptions) {
throw new Error(`Unable to get interactive launch options. Please see the '${diagnosticsChannel.getName()}' output window for details.`);
}
const serializerCommand = dotnetConfig.get('notebookParserArgs') as string[] || [];
const serializerCommandProcessStart = processArguments({ args: serializerCommand, workingDirectory: launchOptions!.workingDirectory }, '.', DotNetPathManager.getDotNetPath(), context.globalStorageUri.fsPath);
const serializerCommandProcessStart = processArguments({ args: serializerCommand, workingDirectory: launchOptions.workingDirectory }, '.', DotNetPathManager.getDotNetPath(), context.globalStorageUri.fsPath);
const serializerLineAdapter = new ChildProcessLineAdapter(serializerCommandProcessStart.command, serializerCommandProcessStart.args, serializerCommandProcessStart.workingDirectory, true, diagnosticsChannel);
const messageClient = new MessageClient(serializerLineAdapter);
const parserServer = new NotebookParserServer(messageClient);
Expand Down
12 changes: 10 additions & 2 deletions src/polyglot-notebooks-vscode-common/src/utilities.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@

import * as compareVersions from 'compare-versions';
import * as cp from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import { v4 as uuid } from 'uuid';
import { InstallInteractiveArgs, ProcessStart } from "./interfaces";
import { NotebookCellOutput, NotebookCellOutputItem, ReportChannel, Uri } from './interfaces/vscode-like';
import * as commandsAndEvents from './polyglot-notebooks/commandsAndEvents';
import * as connection from './polyglot-notebooks/connection';
import { createUuid } from './polyglot-notebooks/uuid';
import { OutputChannelAdapter } from './OutputChannelAdapter';
import { Logger } from './polyglot-notebooks';

Expand Down Expand Up @@ -65,9 +66,16 @@ export async function executeSafeAndLog(outputChannel: ReportChannel, operationN
return result;
}

export function toolManifestExists(globalStoragePath: string): boolean {
return [
path.join(globalStoragePath, '.config', 'dotnet-tools.json'),
path.join(globalStoragePath, 'dotnet-tools.json')
].some(file => fs.existsSync(file));
}

export function createOutput(outputItems: Array<NotebookCellOutputItem>, outputId?: string): NotebookCellOutput {
if (!outputId) {
outputId = uuid();
outputId = commandsAndEvents.createUuid();
}

const output: NotebookCellOutput = {
Expand Down
40 changes: 39 additions & 1 deletion src/polyglot-notebooks-vscode-common/tests/acquisition.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ describe('Acquisition tests', () => {
function createEmptyToolManifest(dotnetPath: string, globalStoragePath: string): Promise<void> {
return new Promise((resolve, reject) => {
const manifestDir = path.join(globalStoragePath, '.config');
fs.mkdirSync(manifestDir);
fs.mkdirSync(manifestDir, { recursive: true });
const manifestPath = path.join(manifestDir, 'dotnet-tools.json');
const manfiestContent = {
version: 1,
Expand All @@ -45,6 +45,18 @@ describe('Acquisition tests', () => {
});
}

function createRootToolManifest(globalStoragePath: string): Promise<void> {
return new Promise((resolve, reject) => {
const manifestPath = path.join(globalStoragePath, 'dotnet-tools.json');
const manifestContent = {
version: 1,
isRoot: true,
tools: {}
};
fs.writeFile(manifestPath, JSON.stringify(manifestContent), err => err ? reject(err) : resolve());
});
}

function createToolManifestThatThrows(dotnetPath: string, globalStoragePath: string): Promise<void> {
throw new Error('This function should have never been called.');
}
Expand Down Expand Up @@ -195,6 +207,32 @@ describe('Acquisition tests', () => {
});
});

it("simulate global storage and root tool manifest exist; acquisition should not recreate it", async () => {
await withFakeGlobalStorageLocation(true, async globalStoragePath => {
const args = {
dotnetPath: 'dotnet',
toolVersion: undefined
};

await createRootToolManifest(globalStoragePath);

const launchOptions = await acquireDotnetInteractive(
args,
'42.42.42',
globalStoragePath,
getInteractiveVersionThatReturnsNoVersionFound,
createToolManifestThatThrows,
report,
installInteractiveToolWithSpecificVersion('42.42.42'),
report);

expect(launchOptions).to.deep.equal({
workingDirectory: globalStoragePath
});
expect(path.join(globalStoragePath, 'dotnet-tools.json')).to.be.file().with.json;
});
});

it("simulate local tool exists, is out of date, and is updated to the auto version", async () => {
await withFakeGlobalStorageLocation(true, async globalStoragePath => {
const args = {
Expand Down
57 changes: 55 additions & 2 deletions src/polyglot-notebooks-vscode-common/tests/misc.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,33 @@
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

import { expect } from 'chai';
import * as fs from 'fs';
import * as path from 'path';
import { DisplayElement, ErrorElement, TextElement } from '../../src/vscode-common/polyglot-notebooks/contracts';
import { isDisplayOutput, isErrorOutput, isTextOutput, reshapeOutputValueForVsCode } from '../../src/vscode-common/interfaces/utilities';
import { createUri, debounce, executeSafe, getVersionNumber, getWorkingDirectoryForNotebook, parse, processArguments, stringify } from '../../src/vscode-common/utilities';
import { decodeToString } from './utilities';
import { createOutput, createUri, debounce, executeSafe, getVersionNumber, getWorkingDirectoryForNotebook, parse, processArguments, stringify, toolManifestExists } from '../../src/vscode-common/utilities';
import { decodeToString, withFakeGlobalStorageLocation } from './utilities';

import * as vscodeLike from '../../src/vscode-common/interfaces/vscode-like';
import { areEquivalentObjects, sortInPlace } from '../../src/vscode-common/metadataUtilities';

describe('Miscellaneous tests', () => {
const originalCryptoDescriptor = Object.getOwnPropertyDescriptor(globalThis, 'crypto');

function setCrypto(value: any) {
Object.defineProperty(globalThis, 'crypto', {
value,
configurable: true,
});
}

afterEach(() => {
if (originalCryptoDescriptor) {
Object.defineProperty(globalThis, 'crypto', originalCryptoDescriptor);
} else {
delete (globalThis as { crypto?: Crypto }).crypto;
}
});

it(`verify command and argument replacement is as expected`, () => {
let template = {
Expand Down Expand Up @@ -73,6 +91,41 @@ describe('Miscellaneous tests', () => {
expect(workingDir).to.equal('fallback-is-used');
});

it('tool manifest existence check detects manifests in the .config directory', async () => {
await withFakeGlobalStorageLocation(true, async globalStoragePath => {
const manifestDir = path.join(globalStoragePath, '.config');
fs.mkdirSync(manifestDir, { recursive: true });
fs.writeFileSync(path.join(manifestDir, 'dotnet-tools.json'), '{}');

expect(toolManifestExists(globalStoragePath)).to.be.true;
});
});

it('tool manifest existence check detects manifests in the storage root', async () => {
await withFakeGlobalStorageLocation(true, async globalStoragePath => {
fs.writeFileSync(path.join(globalStoragePath, 'dotnet-tools.json'), '{}');

expect(toolManifestExists(globalStoragePath)).to.be.true;
});
});

it('cell output ids use crypto.getRandomValues when randomUUID is unavailable', () => {
setCrypto({
getRandomValues: (values: Uint8Array) => {
values.set([
0xde, 0xad, 0xbe, 0xef,
0xca, 0xfe, 0x0a, 0xbe,
0x10, 0x20, 0x30, 0x40,
0x50, 0x60, 0x70, 0x80,
]);
return values;
},
});

const output = createOutput([]);
expect(output.id).to.equal('deadbeef-cafe-4abe-9020-304050607080');
});

it('debounce test', async () => {
let callbackHit = false;
let debounceDelay = 500;
Expand Down
3 changes: 1 addition & 2 deletions src/polyglot-notebooks-vscode-insiders/.npmrc
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
registry=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/
always-auth=true
registry=https://registry.npmjs.org/
Loading