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
99 changes: 36 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,82 +15,55 @@ Please download the latest release for your platform from the [Releases](https:/

## Development

To run AKS desktop locally, follow these steps:
### Prerequisites

1. Clone the repository:
- [Node.js](https://nodejs.org/) 20+
- [Go](https://go.dev/) 1.22+ (for the Headlamp backend)
- [Git](https://git-scm.com/)
- GNU Make — included on macOS/Linux; on Windows install via `winget install GnuWin32.Make` or [Chocolatey](https://community.chocolatey.org/packages/make) (`choco install make`)

```bash
git clone --recurse-submodules https://github.com/Azure/aks-desktop.git
```
### Quick start

2. Navigate to the project directory:
```bash
git clone --recurse-submodules https://github.com/Azure/aks-desktop.git
cd aks-desktop
npm run setup # resets submodule, installs deps, builds backend
npm run dev # starts the app in development mode
```

```bash
cd aks-desktop
```
### Optional: use system Azure CLI

3. Install the dependencies:
If you already have [Azure CLI](https://learn.microsoft.com/cli/azure/install-azure-cli) installed and want to skip the bundled download:

```bash
./scripts/headlamp-submodule.sh --reset
npm install
npm run install:all
```
```bash
# Linux / macOS
AKS_DESKTOP_SYSTEM_AZ=1 npm run setup

4. Check for the resource folder:
# Windows (cmd)
set AKS_DESKTOP_SYSTEM_AZ=1 && npm run setup

Ensure that the `resources` folder exists in the `headlamp/app` directory.
If `headlamp/app/resources` does not exist, run the following command from the root directory.
# Windows (PowerShell)
$env:AKS_DESKTOP_SYSTEM_AZ="1"; npm run setup
```

```bash
npm run plugin:setup
```
### Manual steps (if you prefer)

5. Build the Headlamp backend server:

Navigate to the `headlamp` directory and build the backend server

```bash
cd headlamp
make backend
```

6. Start the application at the root directory:

Navigate back to the root directory and start the application in development mode:

```bash
npm run dev
```
```bash
node scripts/setup-submodule.mjs # or: ./scripts/headlamp-submodule.sh --reset
npm ci
npm run install:all # installs headlamp, plugin, and ai-assistant in parallel
cd headlamp && make backend && cd ..
npm run dev
```

## How to Build

To get started with AKS desktop, follow these steps:

1. Clone the repository:

```bash
git clone --recurse-submodules https://github.com/Azure/aks-desktop.git
```

2. Navigate to the project directory:

```bash
cd aks-desktop
```

3. Install the dependencies:

```bash
./scripts/headlamp-submodule.sh --reset
npm install
npm run install:all
```

4. Build the project:
```bash
npm run build
```
```bash
git clone --recurse-submodules https://github.com/Azure/aks-desktop.git
cd aks-desktop
npm run setup
npm run build
```

## Documentation

Expand Down
52 changes: 43 additions & 9 deletions build/setup-external-tools.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,19 +35,53 @@ const EXTERNAL_TOOLS_DIR = path.join(ROOT_DIR, 'headlamp', 'app', 'resources', '
const EXTERNAL_TOOLS_BIN = path.join(EXTERNAL_TOOLS_DIR, 'bin');
const AZ_CLI_DIR = path.join(EXTERNAL_TOOLS_DIR, 'az-cli', PLATFORM);

// Download and install Azure CLI
// Download and install Azure CLI (or use system az if AKS_DESKTOP_SYSTEM_AZ is set)
console.log('==========================================');
console.log('Installing Azure CLI...');
console.log('==========================================');

try {
execSync(`npx --yes tsx "${path.join(SCRIPT_DIR, 'download-az-cli.ts')}"`, {
stdio: 'inherit',
cwd: ROOT_DIR
});
} catch (error) {
console.error('❌ ERROR: Failed to install Azure CLI');
process.exit(1);
if (process.env.AKS_DESKTOP_SYSTEM_AZ) {
// Check if system az is available
try {
const azVersion = execSync('az version --output tsv', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] });
console.log('Using system Azure CLI installation:');
console.log(azVersion.trim());
console.log('');
console.log('Skipping bundled Azure CLI download (AKS_DESKTOP_SYSTEM_AZ is set).');

// Create the az-cli directory structure so the rest of the setup doesn't fail
const azCliBinDir = path.join(AZ_CLI_DIR, 'bin');
fs.mkdirSync(azCliBinDir, { recursive: true });

// Create a wrapper that delegates to the system az using its absolute path.
// This avoids infinite recursion since Electron prepends az-cli/bin to PATH at runtime.
if (PLATFORM === 'win32') {
const systemAzPath = execSync('where az', { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'pipe'] }).trim().split(/\r?\n/)[0];
fs.writeFileSync(path.join(azCliBinDir, 'az.cmd'), `@echo off\r\ncall "${systemAzPath}" %*\r\n`);
} else {
const systemAzPath = execSync('command -v az', { encoding: 'utf-8', shell: '/bin/sh', stdio: ['pipe', 'pipe', 'pipe'] }).trim();
fs.writeFileSync(path.join(azCliBinDir, 'az-wrapper'), `#!/bin/sh\nexec "${systemAzPath}" "$@"\n`, { mode: 0o755 });
const azSymlink = path.join(azCliBinDir, 'az');
if (fs.existsSync(azSymlink)) fs.unlinkSync(azSymlink);
fs.symlinkSync('az-wrapper', azSymlink);
}

console.log('✅ System Azure CLI wrapper created');
} catch {
console.error('❌ ERROR: AKS_DESKTOP_SYSTEM_AZ is set but "az" was not found on PATH.');
console.error(' Install Azure CLI or unset AKS_DESKTOP_SYSTEM_AZ to download it automatically.');
process.exit(1);
}
} else {
try {
execSync(`npx --yes tsx "${path.join(SCRIPT_DIR, 'download-az-cli.ts')}"`, {
stdio: 'inherit',
cwd: ROOT_DIR
});
} catch (error) {
console.error('❌ ERROR: Failed to install Azure CLI');
process.exit(1);
}
}

console.log('');
Expand Down
9 changes: 5 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,24 @@
"build:unpacked:win": "npm run plugin:setup && cd headlamp && make app-build",
"test:post-build": "npx --yes tsx ./build/verify-bundled-tools.ts",
"plugin:setup": "npx --yes tsx ./build/setup-plugins.ts",
"plugin:install": "cd plugins/aks-desktop && npm install",
"plugin:install": "cd plugins/aks-desktop && npm ci",
"plugin:build": "cd plugins/aks-desktop && npm run build",
"plugin:start": "cd plugins/aks-desktop && npm start",
"plugin:test": "cd plugins/aks-desktop && npm test",
"plugin:lint": "cd plugins/aks-desktop && npm run lint",
"plugin:test:all": "cd plugins/aks-desktop && npm run test:all",
"plugin:format": "cd plugins/aks-desktop && npm run format",
"plugin:package": "cd plugins/aks-desktop && npm run package",
"ai-assistant:install": "cd plugins/ai-assistant && npm install",
"ai-assistant:install": "cd plugins/ai-assistant && npm ci",
"ai-assistant:build": "cd plugins/ai-assistant && npm run build",
"ai-assistant:start": "cd plugins/ai-assistant && npm start",
"ai-assistant:test": "cd plugins/ai-assistant && npm test",
"ai-assistant:lint": "cd plugins/ai-assistant && npm run lint",
"ai-assistant:format": "cd plugins/ai-assistant && npm run format",
"headlamp:install": "cd headlamp/frontend && npm install && cd ../app && npm install",
"headlamp:install": "cd headlamp/frontend && npm ci && cd ../app && npm ci",
"headlamp:build": "cd headlamp && make backend && make frontend",
"install:all": "npm run headlamp:install && npm run plugin:install && npm run ai-assistant:install",
"install:all": "concurrently \"npm run headlamp:install\" \"npm run plugin:install\" \"npm run ai-assistant:install\"",
"setup": "node scripts/setup-submodule.mjs && npm ci && npm run install:all && cd headlamp && make backend",
"build:all": "npm run headlamp:build && npm run plugin:build && npm run ai-assistant:build",
"dev": "concurrently --kill-others --names \"PLUGIN,AI-ASSISTANT,BACKEND,FRONTEND,APP\" -c \"cyan,blue,green,yellow,magenta\" \"npm run plugin:start\" \"npm run ai-assistant:start\" \"cd headlamp && make run-backend\" \"cd headlamp && make run-frontend\" \"cd headlamp && make run-only-app\"",
"prepare": "husky",
Expand Down
55 changes: 55 additions & 0 deletions scripts/setup-submodule.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env node

// Copyright (c) Microsoft Corporation.
// Licensed under the Apache 2.0.

/**
* Cross-platform Node.js replacement for headlamp-submodule.sh --reset
* Resets the headlamp submodule to the commit recorded in the superproject.
*
* Usage:
* node scripts/setup-submodule.mjs # reset submodule (default)
* node scripts/setup-submodule.mjs --reset # same as above
*/

import { execSync } from 'child_process';
import { existsSync } from 'fs';
import { dirname, join } from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const ROOT_DIR = dirname(dirname(__filename));
const HEADLAMP_DIR = join(ROOT_DIR, 'headlamp');

// Check for dirty submodule
if (existsSync(HEADLAMP_DIR)) {
try {
const status = execSync('git status --porcelain', {
cwd: HEADLAMP_DIR,
encoding: 'utf-8',
}).trim();
if (status) {
console.warn(
'[warn] You have local changes inside the headlamp submodule that will be overwritten by reset.'
);
}
} catch {
// Not initialized yet — that's fine
}
}

console.log('[info] Resetting headlamp submodule to superproject recorded commit');

execSync('git submodule update --init --checkout headlamp', {
cwd: ROOT_DIR,
stdio: 'inherit',
});

// Show current commit
const desc = execSync('git log --oneline -1', {
cwd: HEADLAMP_DIR,
encoding: 'utf-8',
}).trim();

console.log(`[info] Headlamp now at: ${desc}`);
console.log('[done] Submodule reset to recorded commit.');
Loading