Skip to content

Commit 8d13060

Browse files
hanrwclaude
andcommitted
fix(web-server): redirect /command-center and /console to asccli.app
Local static file serving for these routes was broken (files not bundled in the binary). Routes now 302-redirect to the hosted apps at asccli.app/command-center and asccli.app/console. Startup banner updated to show the hosted URLs. Removes dead serveStatic/MIME_TYPES code. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 4bc3c11 commit 8d13060

3 files changed

Lines changed: 20 additions & 66 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10+
### Changed
11+
- **`asc web-server`**`/command-center/`, `/console/`, and `/` now redirect (302) to the hosted apps at `asccli.app/command-center` and `asccli.app/console` instead of serving local files that no longer exist; startup banner updated to show hosted URLs
12+
1013
---
1114

1215
## [0.1.56] - 2026-03-21

apps/asc-web/server.js

Lines changed: 15 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,10 @@
77
// node server.js --port 3000 # custom port
88
//
99
// Routes:
10-
// /command-center/ → command-center (dashboard)
11-
// /console/ → console (terminal)
12-
// /shared/ → shared (domain, infrastructure, static)
13-
// / → appstore-command-center (default)
1410
// /api/run → execute asc CLI commands
11+
// /command-center/ → 302 redirect to asccli.app/command-center
12+
// /console/ → 302 redirect to asccli.app/console
13+
// / → 302 redirect to asccli.app/command-center
1514
//
1615
// Prerequisites:
1716
// - `asc` CLI installed and on PATH (or built: swift run asc)
@@ -31,18 +30,6 @@ const ASC_DIR = path.join(os.homedir(), '.asc');
3130
const CERT_KEY = path.join(ASC_DIR, 'server.key');
3231
const CERT_PEM = path.join(ASC_DIR, 'server.crt');
3332

34-
const APPS_DIR = __dirname;
35-
const MIME_TYPES = {
36-
'.html': 'text/html; charset=utf-8',
37-
'.js': 'text/javascript; charset=utf-8',
38-
'.css': 'text/css; charset=utf-8',
39-
'.json': 'application/json',
40-
'.png': 'image/png',
41-
'.webp': 'image/webp',
42-
'.svg': 'image/svg+xml',
43-
'.ico': 'image/x-icon',
44-
};
45-
4633
function runASC(command) {
4734
return new Promise((resolve) => {
4835
const parts = command.split(/\s+/);
@@ -62,32 +49,6 @@ function runASC(command) {
6249
});
6350
}
6451

65-
function serveStatic(filePath, res) {
66-
const ext = path.extname(filePath);
67-
const contentType = MIME_TYPES[ext] || 'application/octet-stream';
68-
69-
fs.stat(filePath, (statErr, stats) => {
70-
if (statErr || !stats) {
71-
res.writeHead(404);
72-
res.end('Not found');
73-
return;
74-
}
75-
if (stats.isDirectory()) {
76-
serveStatic(path.join(filePath, 'index.html'), res);
77-
return;
78-
}
79-
fs.readFile(filePath, (err, data) => {
80-
if (err) {
81-
res.writeHead(404);
82-
res.end('Not found');
83-
return;
84-
}
85-
res.writeHead(200, { 'Content-Type': contentType });
86-
res.end(data);
87-
});
88-
});
89-
}
90-
9152
function handleRequest(req, res) {
9253
res.setHeader('Access-Control-Allow-Origin', '*');
9354
res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
@@ -131,32 +92,22 @@ function handleRequest(req, res) {
13192
return;
13293
}
13394

134-
// Static file serving with app routing
95+
// Redirect to hosted web apps at asccli.app
13596
const urlPath = decodeURIComponent(req.url.split('?')[0]);
13697

137-
let filePath;
138-
if (urlPath.startsWith('/command-center')) {
139-
const subPath = urlPath.slice('/command-center'.length) || '/';
140-
filePath = path.join(APPS_DIR, 'command-center', subPath === '/' ? 'index.html' : subPath);
141-
} else if (urlPath.startsWith('/console')) {
142-
const subPath = urlPath.slice('/console'.length) || '/';
143-
filePath = path.join(APPS_DIR, 'console', subPath === '/' ? 'index.html' : subPath);
144-
} else if (urlPath.startsWith('/shared')) {
145-
filePath = path.join(APPS_DIR, urlPath);
146-
} else if (urlPath === '/' || urlPath === '/index.html') {
147-
filePath = path.join(APPS_DIR, 'command-center', 'index.html');
148-
} else {
149-
filePath = path.join(APPS_DIR, 'command-center', urlPath);
98+
if (urlPath === '/' || urlPath === '/index.html' || urlPath.startsWith('/command-center')) {
99+
res.writeHead(302, { 'Location': 'https://asccli.app/command-center' });
100+
res.end();
101+
return;
150102
}
151-
152-
// Security: block path traversal
153-
if (!filePath.startsWith(APPS_DIR)) {
154-
res.writeHead(403);
155-
res.end('Forbidden');
103+
if (urlPath.startsWith('/console')) {
104+
res.writeHead(302, { 'Location': 'https://asccli.app/console' });
105+
res.end();
156106
return;
157107
}
158108

159-
serveStatic(filePath, res);
109+
res.writeHead(404);
110+
res.end('Not found');
160111
}
161112

162113
const server = http.createServer(handleRequest);
@@ -221,8 +172,8 @@ server.listen(PORT, () => {
221172
}
222173
lines.push(
223174
' │ │',
224-
' │ /command-center/ Dashboard │',
225-
' │ /console/ Terminal │',
175+
' │ asccli.app/command-center │',
176+
' │ asccli.app/console │',
226177
' │ /api/run CLI bridge │',
227178
' │ │',
228179
` │ Binary: ${ASC_BIN.padEnd(31)}│`,

docs/features/web-apps.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ asc web-server --port 9000
1313
```
1414

1515
Then open either web app:
16-
- **Command Center:** https://asccli.app/asc-web-command-center/
17-
- **Console:** https://asccli.app/asc-web-console/
16+
- **Command Center:** https://asccli.app/command-center
17+
- **Console:** https://asccli.app/console
1818

1919
**Prerequisites:** Node.js (for the API proxy) and `asc` in your PATH.
2020

0 commit comments

Comments
 (0)