-
Notifications
You must be signed in to change notification settings - Fork 898
feat(desktop): Windows native port #2196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
18aae88
11c6c82
fe37657
3a1594c
93a5ba7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -143,6 +143,89 @@ jobs: | |||||
| retention-days: ${{ inputs.artifact_retention_days }} | ||||||
| if-no-files-found: error | ||||||
|
|
||||||
| build-windows: | ||||||
| name: Build - Windows (x64) | ||||||
| runs-on: windows-latest | ||||||
| environment: production | ||||||
|
|
||||||
| steps: | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v4 | ||||||
|
|
||||||
| - name: Enable git long paths | ||||||
| run: git config --global core.longpaths true | ||||||
|
|
||||||
| - name: Setup Bun | ||||||
| uses: oven-sh/setup-bun@v1 | ||||||
| with: | ||||||
| bun-version: "1.3.2" | ||||||
|
|
||||||
| - name: Cache dependencies | ||||||
| uses: actions/cache@v4 | ||||||
| with: | ||||||
| path: | | ||||||
| ~/.bun/install/cache | ||||||
| key: ${{ runner.os }}-bun-${{ github.sha }} | ||||||
| restore-keys: | | ||||||
| ${{ runner.os }}-bun- | ||||||
|
|
||||||
| - name: Install dependencies | ||||||
| run: bun install --frozen | ||||||
|
|
||||||
| - name: Set version suffix | ||||||
| if: inputs.version_suffix != '' | ||||||
| working-directory: apps/desktop | ||||||
| shell: bash | ||||||
| run: | | ||||||
| CURRENT_VERSION=$(node -p "require('./package.json').version") | ||||||
| NEW_VERSION="${CURRENT_VERSION}${{ inputs.version_suffix }}" | ||||||
| node -e " | ||||||
| const fs = require('fs'); | ||||||
| const pkg = require('./package.json'); | ||||||
| pkg.version = '$NEW_VERSION'; | ||||||
| fs.writeFileSync('./package.json', JSON.stringify(pkg, null, '\t') + '\n'); | ||||||
| " | ||||||
|
|
||||||
| - name: Clean dev folder | ||||||
| working-directory: apps/desktop | ||||||
| run: bun run clean:dev | ||||||
|
|
||||||
| - name: Generate icons | ||||||
| working-directory: apps/desktop | ||||||
| run: bun run generate:icons | ||||||
|
|
||||||
| - name: Compile app | ||||||
| working-directory: apps/desktop | ||||||
| run: bun run compile:app | ||||||
| env: | ||||||
| SENTRY_AUTH_TOKEN: ${{ secrets.SENTRY_AUTH_TOKEN }} | ||||||
| SENTRY_DSN_DESKTOP: ${{ secrets.SENTRY_DSN_DESKTOP }} | ||||||
|
|
||||||
| - name: Copy native modules | ||||||
| working-directory: apps/desktop | ||||||
| run: bun run copy:native-modules | ||||||
|
|
||||||
| - name: Validate native runtime | ||||||
| working-directory: apps/desktop | ||||||
| run: bun run validate:native-runtime | ||||||
|
|
||||||
| - name: Build installer | ||||||
| working-directory: apps/desktop | ||||||
| run: bun run build | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The Windows build step ignores the workflow’s Prompt for AI agents
Suggested change
|
||||||
| env: | ||||||
| CSC_IDENTITY_AUTO_DISCOVERY: "false" | ||||||
|
|
||||||
|
Comment on lines
+212
to
+217
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The Windows packaging step drops That workflow input is honored on macOS/Linux but ignored here, so callers can select an alternate builder config for those jobs and silently get a different Windows artifact from the same workflow invocation. 🤖 Prompt for AI Agents |
||||||
| - name: Upload artifacts | ||||||
| uses: actions/upload-artifact@v4 | ||||||
| with: | ||||||
| name: ${{ inputs.artifact_prefix }}-windows-x64 | ||||||
| path: | | ||||||
| apps/desktop/release/*.exe | ||||||
| apps/desktop/release/*.yml | ||||||
| apps/desktop/release/*.blockmap | ||||||
| retention-days: ${{ inputs.artifact_retention_days }} | ||||||
| if-no-files-found: error | ||||||
|
|
||||||
| build-linux: | ||||||
| name: Build - Linux (x64) | ||||||
| runs-on: ubuntu-latest | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -130,3 +130,25 @@ jobs: | |||||
| env: | ||||||
| NEXT_PUBLIC_OUTLIT_KEY: ${{ secrets.NEXT_PUBLIC_OUTLIT_KEY || 'ci-outlit-placeholder-key' }} | ||||||
| run: bun turbo run build --filter=@superset/desktop | ||||||
|
|
||||||
| test-windows: | ||||||
| name: Test (Windows) | ||||||
| runs-on: windows-latest | ||||||
| steps: | ||||||
| - name: Checkout code | ||||||
| uses: actions/checkout@v4 | ||||||
|
|
||||||
| - name: Enable git long paths | ||||||
| run: git config --global core.longpaths true | ||||||
|
|
||||||
| - name: Setup Bun | ||||||
| uses: oven-sh/setup-bun@v1 | ||||||
| with: | ||||||
| bun-version: "1.3.2" | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: The Windows CI job pins Bun 1.3.2 while the rest of the workflow uses 1.3.6, which can cause version-specific test behavior and inconsistent CI results across platforms. Prompt for AI agents
Suggested change
|
||||||
|
|
||||||
| - name: Install dependencies | ||||||
| run: bun install --frozen | ||||||
|
|
||||||
| - name: Run desktop tests | ||||||
| working-directory: apps/desktop | ||||||
| run: bun test | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -63,12 +63,21 @@ If it runs in a terminal, it runs on Superset | |
|
|
||
| | Requirement | Details | | ||
| |:------------|:--------| | ||
| | **OS** | macOS (Windows/Linux untested) | | ||
| | **OS** | macOS, Windows 10+ (Linux untested) | | ||
| | **Runtime** | [Bun](https://bun.sh/) v1.0+ | | ||
| | **Version Control** | Git 2.20+ | | ||
| | **GitHub CLI** | [gh](https://cli.github.com/) | | ||
| | **Caddy** | [caddy](https://caddyserver.com/docs/install) (for dev server) | | ||
|
|
||
| ### Windows Support | ||
|
|
||
| | Requirement | Details | | ||
| |---|---| | ||
| | OS | Windows 10 1809+ (ConPTY support required) | | ||
| | Developer Mode | Enable in Settings > Privacy & Security > For developers | | ||
| | Git long paths | `git config --global core.longpaths true` | | ||
| | Build Tools | Visual Studio Build Tools with "Desktop development with C++" (for native modules) | | ||
|
Comment on lines
+66
to
+79
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add a Windows download path alongside this support claim. Line 66 now advertises Windows support, but the prebuilt CTAs at Line 15 and Line 85 still point to macOS only. Windows users will end up on a README that says they're supported without showing which 🤖 Prompt for AI Agents |
||
|
|
||
| ## Getting Started | ||
|
|
||
| ### Quick Start (Pre-built) | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -198,6 +198,8 @@ const config: Configuration = { | |||||
| }, | ||||||
| ], | ||||||
| artifactName: `${productName}-${pkg.version}-\${arch}.\${ext}`, | ||||||
| signAndEditExecutable: false, | ||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Prompt for AI agents
Suggested change
|
||||||
| forceCodeSigning: false, | ||||||
|
Comment on lines
+201
to
+202
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -euo pipefail
rg -n -C2 'electron_builder_config|signAndEditExecutable|forceCodeSigning|CSC_IDENTITY_AUTO_DISCOVERY|CSC_LINK|WIN_CSC' .github/workflows apps/desktopRepository: superset-sh/superset Length of output: 3847 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Check if electron-builder.canary.ts exists and compare Windows configs
echo "=== Checking electron-builder.canary.ts ==="
if [ -f "apps/desktop/electron-builder.canary.ts" ]; then
sed -n '/windows:/,/^[[:space:]]*},$/p' apps/desktop/electron-builder.canary.ts | head -30
else
echo "electron-builder.canary.ts not found"
fi
echo -e "\n=== Checking for any Windows code signing config in electron-builder.ts ==="
sed -n '/windows:/,/^[[:space:]]*},$/p' apps/desktop/electron-builder.ts | grep -E 'sign|csc|CSC|certificate'
echo -e "\n=== Checking context around lines 201-202 in electron-builder.ts ==="
sed -n '195,210p' apps/desktop/electron-builder.tsRepository: superset-sh/superset Length of output: 184 🏁 Script executed: #!/bin/bash
set -euo pipefail
# List electron-builder files
echo "=== Files in apps/desktop matching electron-builder ==="
ls -la apps/desktop/electron-builder* 2>/dev/null || echo "No electron-builder files found"
# Read the full Windows section from electron-builder.ts with more context
echo -e "\n=== Full Windows config in electron-builder.ts ==="
awk '/windows:/{flag=1} flag{print NR": "$0} /^[[:space:]]*},/{if(flag && prev_close) flag=0} {prev_close=/^[[:space:]]*},/}' apps/desktop/electron-builder.ts | head -50Repository: superset-sh/superset Length of output: 342 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Read electron-builder.ts to see the full context
echo "=== Reading electron-builder.ts ==="
cat -n apps/desktop/electron-builder.ts
echo -e "\n=== Reading electron-builder.canary.ts ==="
cat -n apps/desktop/electron-builder.canary.tsRepository: superset-sh/superset Length of output: 9765 This disables signing for all release builds, not just development. Both stable (release-desktop.yml) and canary (release-desktop-canary.yml) release workflows use unsigned Windows configurations:
No alternate signed Windows builder config exists for the release paths. If code signing should be enabled for public releases, the Windows config must be split into signed and unsigned variants or gated by environment/channel. 🤖 Prompt for AI Agents |
||||||
| }, | ||||||
|
|
||||||
| // NSIS installer (Windows) | ||||||
|
|
||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -54,6 +54,20 @@ async function getShellEnvWithTimeout(): Promise<Record<string, string>> { | |
| * Results are cached for 1 minute to avoid spawning shells repeatedly. | ||
| */ | ||
| export async function getShellEnvironment(): Promise<Record<string, string>> { | ||
| // Windows: process.env already contains the full user environment. | ||
| // Unlike macOS GUI apps launched from Finder/Dock, Windows apps inherit | ||
| // the complete user environment including PATH modifications. | ||
| if (process.platform === "win32") { | ||
| const env: Record<string, string> = {}; | ||
| for (const [key, value] of Object.entries(process.env)) { | ||
| if (typeof value === "string") { | ||
| env[key] = value; | ||
| } | ||
| } | ||
| return env; | ||
| } | ||
|
Comment on lines
+57
to
+68
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't short-circuit Windows to raw This function is the source of truth for 🤖 Prompt for AI Agents |
||
|
|
||
| // Existing macOS/Linux code follows... | ||
| const now = Date.now(); | ||
| const ttl = isFallbackCache ? fallbackCacheTtlMs : CACHE_TTL_MS; | ||
| if (cachedEnv && now - cacheTime < ttl) { | ||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -5,8 +5,9 @@ import { | |||||||||||||
| getCommandShellArgs, | ||||||||||||||
| getShellEnv, | ||||||||||||||
| } from "main/lib/agent-setup/shell-wrappers"; | ||||||||||||||
| import { buildSafeEnv, sanitizeEnv } from "main/lib/terminal/env"; | ||||||||||||||
| import { buildSafeEnv, getDefaultShell, sanitizeEnv } from "main/lib/terminal/env"; | ||||||||||||||
| import { SUPERSET_DIR_NAME } from "shared/constants"; | ||||||||||||||
| import treeKill from "tree-kill"; | ||||||||||||||
| import { removeWorktree } from "./git"; | ||||||||||||||
| import { loadSetupConfig } from "./setup"; | ||||||||||||||
|
|
||||||||||||||
|
|
@@ -42,9 +43,7 @@ export async function runTeardown({ | |||||||||||||
| console.log(`[teardown] Running for "${workspaceName}": ${command}`); | ||||||||||||||
|
|
||||||||||||||
| try { | ||||||||||||||
| const shell = | ||||||||||||||
| process.env.SHELL || | ||||||||||||||
| (process.platform === "darwin" ? "/bin/zsh" : "/bin/bash"); | ||||||||||||||
| const shell = process.env.SHELL || getDefaultShell(); | ||||||||||||||
|
Comment on lines
45
to
+46
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Don't let On Windows, an inherited Suggested fix- const shell = process.env.SHELL || getDefaultShell();
+ const shell =
+ process.platform === "win32"
+ ? getDefaultShell()
+ : process.env.SHELL || getDefaultShell();🤖 Prompt for AI Agents |
||||||||||||||
| const supersetHomeDir = | ||||||||||||||
| process.env.SUPERSET_HOME_DIR || join(homedir(), SUPERSET_DIR_NAME); | ||||||||||||||
| const shellWrapperPaths = { | ||||||||||||||
|
|
@@ -60,7 +59,8 @@ export async function runTeardown({ | |||||||||||||
| const output = await new Promise<string>((resolve, reject) => { | ||||||||||||||
| const child = spawn(shell, args, { | ||||||||||||||
| cwd: worktreePath, | ||||||||||||||
| detached: true, | ||||||||||||||
| detached: process.platform !== "win32", | ||||||||||||||
| ...(process.platform === "win32" ? { windowsHide: true } : {}), | ||||||||||||||
| stdio: ["ignore", "pipe", "pipe"], | ||||||||||||||
| env: { | ||||||||||||||
| ...baseEnv, | ||||||||||||||
|
|
@@ -114,7 +114,14 @@ export async function runTeardown({ | |||||||||||||
| `[teardown] Timed out after ${TEARDOWN_TIMEOUT_MS}ms, killing process group`, | ||||||||||||||
| ); | ||||||||||||||
| try { | ||||||||||||||
| if (child.pid) process.kill(-child.pid, "SIGKILL"); | ||||||||||||||
| if (child.pid) { | ||||||||||||||
| if (process.platform === "win32") { | ||||||||||||||
| // Windows: can't use negative PID for process group kill | ||||||||||||||
| treeKill(child.pid, "SIGKILL"); | ||||||||||||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Handle (Based on your team's feedback about handling async failures instead of silently swallowing them.) Prompt for AI agents
Suggested change
|
||||||||||||||
| } else { | ||||||||||||||
| process.kill(-child.pid, "SIGKILL"); | ||||||||||||||
| } | ||||||||||||||
|
Comment on lines
+117
to
+123
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, find and read the teardown.ts file
fd -p "teardown.ts" apps/desktop/src/lib/trpcRepository: superset-sh/superset Length of output: 126 🏁 Script executed: # Read the teardown.ts file to understand the full context
cat -n apps/desktop/src/lib/trpc/routers/workspaces/utils/teardown.tsRepository: superset-sh/superset Length of output: 6152 🏁 Script executed: # Check the tree-kill package to understand its API
fd -p "node_modules/tree-kill" --max-depth 1 && cat node_modules/tree-kill/package.json 2>/dev/null | head -20Repository: superset-sh/superset Length of output: 46 🌐 Web query:
💡 Result:
Citations:
Wait for On Windows, Use the callback-based API and only reject after the kill completes: Suggested fix if (child.pid) {
if (process.platform === "win32") {
// Windows: can't use negative PID for process group kill
- treeKill(child.pid, "SIGKILL");
+ treeKill(child.pid, "SIGKILL", () => {
+ reject(
+ new Error(`Teardown timed out after ${TEARDOWN_TIMEOUT_MS}ms`),
+ );
+ });
+ return;
} else {
process.kill(-child.pid, "SIGKILL");
}
}🤖 Prompt for AI Agents |
||||||||||||||
| } | ||||||||||||||
| } catch {} | ||||||||||||||
| reject( | ||||||||||||||
| new Error(`Teardown timed out after ${TEARDOWN_TIMEOUT_MS}ms`), | ||||||||||||||
|
|
||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -8,7 +8,8 @@ import { | |
| } from "./agent-wrappers-common"; | ||
| import { HOOKS_DIR } from "./paths"; | ||
|
|
||
| export const COPILOT_HOOK_SCRIPT_NAME = "copilot-hook.sh"; | ||
| export const COPILOT_HOOK_SCRIPT_NAME = | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P1: Windows now selects a Prompt for AI agents |
||
| process.platform === "win32" ? "copilot-hook.ps1" : "copilot-hook.sh"; | ||
|
|
||
| const COPILOT_HOOK_SIGNATURE = "# Superset copilot hook"; | ||
| const COPILOT_HOOK_VERSION = "v1"; | ||
|
|
@@ -17,7 +18,9 @@ export const COPILOT_HOOK_MARKER = `${COPILOT_HOOK_SIGNATURE} ${COPILOT_HOOK_VER | |
| const COPILOT_HOOK_TEMPLATE_PATH = path.join( | ||
| __dirname, | ||
| "templates", | ||
| "copilot-hook.template.sh", | ||
| process.platform === "win32" | ||
| ? "copilot-hook.template.ps1" | ||
| : "copilot-hook.template.sh", | ||
| ); | ||
|
|
||
| export function getCopilotHookScriptPath(): string { | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,13 +3,16 @@ import path from "node:path"; | |
| import { env } from "shared/env.shared"; | ||
| import { HOOKS_DIR } from "./paths"; | ||
|
|
||
| export const NOTIFY_SCRIPT_NAME = "notify.sh"; | ||
| export const NOTIFY_SCRIPT_NAME = | ||
| process.platform === "win32" ? "notify.ps1" : "notify.sh"; | ||
|
Comment on lines
+6
to
+7
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: #!/bin/bash
# Check how notify script is invoked across agent wrappers
rg -n "notifyScriptPath|NOTIFY_SCRIPT" apps/desktop/src/main/lib/agent-setup/*.ts | head -50Repository: superset-sh/superset Length of output: 3531 🏁 Script executed: cat -n apps/desktop/src/main/lib/agent-setup/notify-hook.tsRepository: superset-sh/superset Length of output: 1941 🏁 Script executed: sed -n '60,85p' apps/desktop/src/main/lib/agent-setup/agent-wrappers-mastra.tsRepository: superset-sh/superset Length of output: 980 🏁 Script executed: # Check if there's any platform detection or Windows-specific handling for Mastra
rg -n "win32|platform|Windows" apps/desktop/src/main/lib/agent-setup/agent-wrappers-mastra.tsRepository: superset-sh/superset Length of output: 46 🏁 Script executed: # Check where Mastra wrapper is integrated
rg -n "getMastraHooksJsonContent|setupMastraHooks" apps/desktop/src/main/lib/agent-setup/*.tsRepository: superset-sh/superset Length of output: 769 🏁 Script executed: # Check if there's Windows-specific agent setup logic
rg -n "platform.*win32|win32.*platform" apps/desktop/src/main/lib/agent-setup/*.tsRepository: superset-sh/superset Length of output: 1220 🏁 Script executed: # Check agent setup initialization to see if Mastra is conditionally enabled
head -50 apps/desktop/src/main/lib/agent-setup/index.tsRepository: superset-sh/superset Length of output: 1254 🏁 Script executed: # Check the full setupAgentHooks to see if Mastra creation is conditional
sed -n '36,100p' apps/desktop/src/main/lib/agent-setup/index.tsRepository: superset-sh/superset Length of output: 1105 🏁 Script executed: # Check how agent-wrappers.ts uses getMastraHooksJsonContent
sed -n '55,100p' apps/desktop/src/main/lib/agent-setup/agent-wrappers.tsRepository: superset-sh/superset Length of output: 359 🏁 Script executed: # Check if Droid and other wrappers have similar bash hardcoding
sed -n '50,80p' apps/desktop/src/main/lib/agent-setup/agent-wrappers-droid.tsRepository: superset-sh/superset Length of output: 828 🏁 Script executed: # Check the full getMastraHooksJsonContent function to understand the scope
sed -n '55,100p' apps/desktop/src/main/lib/agent-setup/agent-wrappers-mastra.tsRepository: superset-sh/superset Length of output: 1649 🏁 Script executed: # Check if Gemini and Copilot wrappers have similar bash hardcoding issues
rg -n "bash.*quoteShellPath|notifyCommand.*bash" apps/desktop/src/main/lib/agent-setup/agent-wrappers-*.tsRepository: superset-sh/superset Length of output: 196 🏁 Script executed: # Check the Droid wrapper to see how it handles the notify script
sed -n '120,145p' apps/desktop/src/main/lib/agent-setup/agent-wrappers-droid.tsRepository: superset-sh/superset Length of output: 613 Mastra wrapper hardcodes bash invocation, incompatible with Windows PowerShell scripts. While const notifyCommand = `bash ${quoteShellPath(notifyScriptPath)}`;On Windows, this produces 🤖 Prompt for AI Agents |
||
| export const NOTIFY_SCRIPT_MARKER = "# Superset agent notification hook"; | ||
|
|
||
| const NOTIFY_SCRIPT_TEMPLATE_PATH = path.join( | ||
| __dirname, | ||
| "templates", | ||
| "notify-hook.template.sh", | ||
| process.platform === "win32" | ||
| ? "notify-hook.template.ps1" | ||
| : "notify-hook.template.sh", | ||
| ); | ||
|
|
||
| function writeFileIfChanged( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pass the same build-time config into the Windows compile step.
compile:apponly gets Sentry values here, while the macOS/Linux jobs also inject the web/API URLs and OAuth client IDs. If those values are compiled into the renderer bundle, the Windows artifact will ship with missing auth and endpoint config.🤖 Prompt for AI Agents