app
Adom Desktop
Public Made by Adomby adom
Installs the adom-desktop CLI and its Claude skills INTO A CLOUD CONTAINER so an AI assistant there can understand and drive Adom Desktop over the relay. This is the container side, NOT the app itself. The Adom Desktop app is the signed Windows installer under Download below: run THAT on the PC you want the AI to control. Rule of thumb: pkg install here (in your Linux container), Download there (on your Windows PC). Once installed, the AI can drive file transfer, screenshots, notifications, KiCa
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259
#!/bin/bash
# Hydrogen Desktop Bootstrap Script
# HD downloads this from the wiki and runs it via:
# docker exec -u adom hydrogen-workspace bash /tmp/hd-bootstrap.sh
#
# Each step prints a structured line that HD's frontend parses:
# STEP|<status>|<command>|<message>
# status: run|done|skip|fail
# HD renders these as a terminal-style log in the Bootstrap panel.
#
# Order matters — install everything FIRST, reload ONCE, then activate.
set -euo pipefail
CODESERVER="/usr/lib/code-server/bin/code-server"
HD_HOST="host.docker.internal"
step() {
local status="$1" cmd="$2" msg="$3"
echo "STEP|${status}|${cmd}|${msg}"
}
# ── 1. adom-vscode binary (needed before extension install) ──
if ! command -v adom-vscode &>/dev/null; then
step run "curl -fsSL .../adom-vscode -o /usr/local/bin/adom-vscode" "downloading binary..."
curl -fsSL "https://wiki-ufypy5dpx93o.adom.cloud/static/apps/adom-vscode/adom-vscode" -o /tmp/adom-vscode-dl
chmod +x /tmp/adom-vscode-dl
sudo mv /tmp/adom-vscode-dl /usr/local/bin/adom-vscode 2>/dev/null || mv /tmp/adom-vscode-dl /usr/local/bin/adom-vscode
step done "curl -fsSL .../adom-vscode -o /usr/local/bin/adom-vscode" "binary installed"
else
step skip "which adom-vscode" "binary already installed"
fi
# ── 2. adom-vscode VS Code extension + skill ──
step run "adom-vscode install" "installing extension + skill..."
/usr/local/bin/adom-vscode install 2>/dev/null || true
step done "adom-vscode install" "extension + skill deployed"
# ── 3. adom-vscode extension in code-server (the install command may use wrong path) ──
if ! $CODESERVER --list-extensions 2>/dev/null | grep -q "adom.adom-vscode"; then
step run "$CODESERVER --install-extension /tmp/adom-vscode-0.1.0.vsix" "registering extension in code-server..."
$CODESERVER --install-extension /tmp/adom-vscode-0.1.0.vsix 2>/dev/null || true
step done "$CODESERVER --install-extension /tmp/adom-vscode-0.1.0.vsix" "registered"
else
step skip "$CODESERVER --list-extensions | grep adom" "already registered"
fi
# ── 4. Claude Code Extension ──
if $CODESERVER --list-extensions 2>/dev/null | grep -q "anthropic.claude-code"; then
step skip "$CODESERVER --list-extensions | grep claude-code" "already installed"
else
step run "$CODESERVER --install-extension anthropic.claude-code" "installing Claude Code..."
$CODESERVER --install-extension anthropic.claude-code 2>/dev/null || true
step done "$CODESERVER --install-extension anthropic.claude-code" "installed"
fi
# ── 5. Claude Code CLI ──
if command -v claude &>/dev/null; then
step skip "which claude" "CLI already installed"
else
step run "curl -fsSL https://claude.ai/install.sh | bash" "installing Claude CLI..."
curl -fsSL https://claude.ai/install.sh -o /tmp/claude-install.sh 2>/dev/null
bash /tmp/claude-install.sh 2>/dev/null || true
step done "curl -fsSL https://claude.ai/install.sh | bash" "CLI installed"
fi
# ── 6. Gallia Platform ──
if [ -f "$HOME/.claude/skills/adom/SKILL.md" ]; then
step skip "test -f ~/.claude/skills/adom/SKILL.md" "gallia already installed"
else
step run "curl -fsSL .../gallia-bundle.tar.gz | tar xz" "downloading gallia..."
curl -fsSL "https://wiki-ufypy5dpx93o.adom.cloud/static/apps/gallia-bundle/gallia-bundle.tar.gz" -o /tmp/gallia-bundle.tar.gz
tar xzf /tmp/gallia-bundle.tar.gz -C "$HOME/"
step done "curl -fsSL .../gallia-bundle.tar.gz | tar xz" "extracted"
step run "cd gallia && npm install && node install.mjs" "deploying skills..."
cd "$HOME/gallia" && npm install --no-audit --no-fund 2>&1 | tail -3
if node "$HOME/gallia/install.mjs" --project "$HOME/project" 2>&1 | tail -5; then
step done "cd gallia && npm install && node install.mjs" "skills deployed"
else
step fail "cd gallia && npm install && node install.mjs" "install.mjs failed (non-fatal)"
fi
fi
# ── 6b. Set ADOM_CARBON_URL to route adom-cli workspace commands to HD ──
CARBON_LINE="export ADOM_CARBON_URL=http://host.docker.internal:9000"
HYDROGEN_LINE="export ADOM_HYDROGEN_URL=http://host.docker.internal:9000"
if grep -q "ADOM_CARBON_URL" "$HOME/.bashrc" 2>/dev/null; then
step skip "grep ADOM_CARBON_URL ~/.bashrc" "already set"
else
step run "echo export ADOM_CARBON/HYDROGEN_URL >> ~/.bashrc" "routing adom-cli to HD..."
echo "$CARBON_LINE" >> "$HOME/.bashrc"
echo "$HYDROGEN_LINE" >> "$HOME/.bashrc"
step done "echo export ADOM_CARBON/HYDROGEN_URL >> ~/.bashrc" "adom-cli routed to HD"
fi
export ADOM_CARBON_URL=http://host.docker.internal:9000
export ADOM_HYDROGEN_URL=http://host.docker.internal:9000
# ── 6c. Inject API key from HD (host has the session token) ──
if [ -f /var/run/adom/api-key ] && [ -s /var/run/adom/api-key ]; then
step skip "test -f /var/run/adom/api-key" "API key already present"
else
step run "inject api-key from HD" "fetching session token from host..."
TOKEN=$(curl -sf http://host.docker.internal:9001/auth-token 2>/dev/null || echo "")
if [ -n "$TOKEN" ]; then
sudo mkdir -p /var/run/adom
echo -n "$TOKEN" | sudo tee /var/run/adom/api-key > /dev/null
sudo chmod 644 /var/run/adom/api-key
step done "inject api-key from HD" "API key injected"
else
step fail "inject api-key from HD" "no token available from HD"
fi
fi
# ── 7. VS Code Settings ──
step run "configure VS Code settings" "dark mode, Claude Code, trust..."
node -e "
const fs = require('fs');
const p = '$HOME/.local/share/code-server/User/settings.json';
let s = {}; try { s = JSON.parse(fs.readFileSync(p, 'utf8')) } catch(e) {}
Object.assign(s, {
'security.workspace.trust.enabled': false,
'workbench.startupEditor': 'none',
'workbench.activityBar.visible': true,
'workbench.colorTheme': 'Default Dark Modern',
'workbench.statusBar.visible': false,
'claudeCode.allowDangerouslySkipPermissions': true,
'claudeCode.initialPermissionMode': 'bypassPermissions',
'claudeCode.preferredLocation': 'panel',
'github.copilot.chat.enabled': false,
'github.copilot.enable': {'*': false},
'security.trustedDomains': ['*'],
'workbench.trustedDomains.promptInTrustedWorkspace': false,
'remote.portsAttributes': {'*': {'onAutoForward': 'silent'}}
});
fs.mkdirSync(require('path').dirname(p), {recursive: true});
fs.writeFileSync(p, JSON.stringify(s, null, 2));
console.log('configured');
"
step done "configure VS Code settings" "settings applied"
# ── 7b. Patch workbench.html BEFORE reload so it loads with the page ──
step run "patch workbench.html" "making external links propagate to parent browser..."
WORKBENCH="/usr/lib/code-server/lib/vscode/out/vs/code/browser/workbench/workbench.html"
MARKER="__hdLinkPropagation"
if ! grep -q "$MARKER" "$WORKBENCH" 2>/dev/null; then
sudo tee -a "$WORKBENCH" > /dev/null 2>&1 << 'LINKPATCH'
<script>
// Hydrogen Desktop: suppress "open external website?" dialog
// All URL interception is handled by WebView2's on_new_window + on_navigation
// in the Rust layer. This patch ONLY sets trusted domains in IndexedDB so
// code-server doesn't show its own confirmation dialog.
(function() {
if (window.__hdLinkPropagation) return;
window.__hdLinkPropagation = true;
try {
var req = indexedDB.open('vscode-web-state-db-global', 1);
req.onupgradeneeded = function(e) {
var db = e.target.result;
if (!db.objectStoreNames.contains('ItemTable')) {
db.createObjectStore('ItemTable');
}
};
req.onsuccess = function(e) {
var db = e.target.result;
try {
var tx = db.transaction('ItemTable', 'readwrite');
var store = tx.objectStore('ItemTable');
store.put(JSON.stringify(['*']), 'http.linkProtectionTrustedDomains');
tx.oncomplete = function() { console.log('[hd] Trusted domains set to * in IndexedDB'); db.close(); };
} catch(err) { db.close(); }
};
} catch(e) { console.error('[hd] Failed to set trusted domains:', e); }
console.log('[hd] Trusted domains patch loaded');
})();
</script>
LINKPATCH
step done "patch workbench.html" "trusted domains set"
else
step skip "patch workbench.html" "already patched"
fi
# ── 8. Reload VS Code (ONCE — after all extensions + settings are in place) ──
step run "adom-vscode reload" "reloading VS Code to activate extensions..."
# First trigger HD iframe reload so the webview picks up changes
curl -sf -X POST "http://host.docker.internal:9001/reload-vscode" 2>/dev/null || true
sleep 3
# Then reload the code-server window so extension host restarts
/usr/local/bin/adom-vscode reload 2>/dev/null || true
step done "adom-vscode reload" "VS Code reloaded"
# ── 9. Wait for adom-vscode extension to activate ──
step run "curl -sf http://127.0.0.1:8821/health" "waiting for adom-vscode (up to 60s)..."
VSCODE_READY=false
for i in $(seq 1 20); do
if curl -sf http://127.0.0.1:8821/health >/dev/null 2>&1; then
VSCODE_READY=true
break
fi
# Retry reload at 30s
if [ "$i" = "10" ]; then
/usr/local/bin/adom-vscode reload 2>/dev/null || true
fi
sleep 3
done
if [ "$VSCODE_READY" = true ]; then
step done "curl -sf http://127.0.0.1:8821/health" "extension active on :8821"
# ── 10. Clean VS Code layout (hide chrome, open Claude Code) ──
step run "configure VS Code layout" "hiding sidebars, panel, status bar..."
/usr/local/bin/adom-vscode sidebar hide 2>/dev/null || true
/usr/local/bin/adom-vscode panel hide 2>/dev/null || true
curl -sf -X POST http://127.0.0.1:8821/command \
-H "Content-Type: application/json" \
-d '{"command":"workbench.action.closeAuxiliaryBar"}' || true
step done "configure VS Code layout" "clean layout ready"
# ── 10b. Open Claude Code with countdown + auto-submit ──
step run "open Claude Code" "launching Claude Code panel..."
curl -sf -X POST http://127.0.0.1:8821/command \
-H "Content-Type: application/json" \
-d '{"command":"claude-vscode.editor.open"}' || true
sleep 1
curl -sf -X POST http://127.0.0.1:8821/command \
-H "Content-Type: application/json" \
-d '{"command":"claude-vscode.focus"}' || true
step done "open Claude Code" "Claude Code panel open"
step run "say hello to Claude" "3..."
sleep 1
step run "say hello to Claude" "2..."
sleep 1
step run "say hello to Claude" "1..."
sleep 1
SEED_MSG="hey, i'm here and ready to go. do you know who i am? and what can you do for me?"
curl -sf -X POST http://127.0.0.1:8821/command \
-H "Content-Type: application/json" \
-d "{\"command\":\"claude-vscode.editor.open\",\"args\":[null,\"$SEED_MSG\"]}" || true
step done "say hello to Claude" "message sent"
else
step fail "curl -sf http://127.0.0.1:8821/health" "timed out after 60s"
fi
# ── 11. Start relay server ──
if curl -sf http://127.0.0.1:8766/health >/dev/null 2>&1; then
step skip "curl -sf http://127.0.0.1:8766/health" "relay already running"
else
step run "nohup adom-desktop serve &" "starting relay..."
nohup adom-desktop serve > /tmp/adom-desktop-relay.log 2>&1 & disown
sleep 2
if curl -sf http://127.0.0.1:8766/health >/dev/null 2>&1; then
step done "nohup adom-desktop serve &" "relay on :8765/:8766"
else
step fail "nohup adom-desktop serve &" "relay failed to start"
fi
fi
echo "STEP|done|bootstrap|complete"