Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e34e971
chore: revert version to 0.0.34 after npm unpublish
ymkiux May 23, 2026
4b116bb
refactor(web-ui): redesign Usage tab with "River of Time" aesthetic
ymkiux May 23, 2026
686ec81
fix(web-ui): resolve /web-ui/ 404 and duplicate path issues
ymkiux May 23, 2026
05035ac
fix(web-ui): strengthen URL normalization to handle nested duplicates
ymkiux May 23, 2026
3ded8c3
test(web-ui): add URL routing and normalization tests
ymkiux May 23, 2026
1a7ebd8
refactor(web-ui): remove /web-ui route, use / as single entry point
ymkiux May 23, 2026
c676da9
feat(web): hide local provider in codex/claude config mode
ymkiux May 23, 2026
bd2f543
feat(web): disable local provider in codex/claude config mode
ymkiux May 23, 2026
ed25c6b
fix(web): correct disabled provider click logic
ymkiux May 23, 2026
1042050
fix(web): remove parentheses from computed property
ymkiux May 23, 2026
08ba575
feat(web): rename claude-local to local with system badge
ymkiux May 23, 2026
aaedffc
feat(web): remove local provider subtitle hint
ymkiux May 23, 2026
8511a41
refactor(web): redesign skills tab to minimalist single-column layout
ymkiux May 23, 2026
545ac9f
refactor(web): implement static URL, always stay at /
ymkiux May 23, 2026
260c613
chore: bump version to 0.0.35
ymkiux May 23, 2026
324c62e
fix(ci): restore missing CI scripts in package.json
ymkiux May 23, 2026
060f5e9
test: update unit tests to match new web-ui structure
ymkiux May 24, 2026
8f00f2a
test: add new keys to parity baseline allowlists
ymkiux May 24, 2026
35fb61c
test: add more usage hero keys to parity baseline
ymkiux May 24, 2026
e74a1a2
test: fix isLocalProviderDisabled key type
ymkiux May 24, 2026
a201a23
fix(web-ui): canonicalize session tab navigation URL
awsl233777 May 24, 2026
aa88b1f
fix: stabilize web ui navigation and canonical urls
awsl233777 May 24, 2026
8d5cc34
fix: avoid runtime vue compiler dependency
awsl233777 May 24, 2026
8251337
fix: preserve sessions tab render on navigation
awsl233777 May 24, 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
95 changes: 53 additions & 42 deletions cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -10058,9 +10058,10 @@ function watchPathsForRestart(targets, onChange) {
}
// #endregion watchPathsForRestart

function writeJsonResponse(res, statusCode, payload) {
function writeJsonResponse(res, statusCode, payload, headers = {}) {
const body = JSON.stringify(payload, null, 2);
res.writeHead(statusCode, {
...headers,
'Content-Type': 'application/json; charset=utf-8',
'Content-Length': Buffer.byteLength(body, 'utf-8')
});
Expand Down Expand Up @@ -10620,7 +10621,7 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
const securityHeaders = {
'X-Content-Type-Options': 'nosniff',
'X-Frame-Options': 'DENY',
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' ws: wss:"
'Content-Security-Policy': "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; img-src 'self' data:; connect-src 'self' ws: wss:"
};
const origWriteHead = res.writeHead.bind(res);
res.writeHead = function (statusCode, headers) {
Expand Down Expand Up @@ -10649,34 +10650,15 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
|| requestPath.startsWith('/download/')
) {
const remoteAddr = req && req.socket ? req.socket.remoteAddress : '';
const isLoopback = !remoteAddr
|| remoteAddr === '127.0.0.1'
|| remoteAddr === '::1'
|| remoteAddr === '::ffff:127.0.0.1';
const isLoopback = !remoteAddr || isLoopbackRemoteAddress(remoteAddr);
if (!isLoopback) {
const rateLimitKey = (remoteAddr || 'unknown') + ':' + requestPath;
if (!checkRateLimit(rateLimitKey)) {
res.writeHead(429, { 'Content-Type': 'application/json; charset=utf-8', 'Retry-After': '60' });
res.end(JSON.stringify({ error: 'Rate limit exceeded' }));
writeJsonResponse(res, 429, { error: 'Rate limit exceeded' }, { 'Retry-After': '60' });
return;
}
const expected = typeof process.env.CODEXMATE_HTTP_TOKEN === 'string'
? process.env.CODEXMATE_HTTP_TOKEN.trim()
: '';
if (!expected) {
sendJson(403, {
error: 'Remote access is disabled (set CODEXMATE_HTTP_TOKEN or use --host 127.0.0.1)'
});
return;
}
const headers = req && req.headers && typeof req.headers === 'object' ? req.headers : {};
const rawAuth = typeof headers.authorization === 'string' ? headers.authorization.trim() : '';
const match = rawAuth ? rawAuth.match(/^bearer\s+(.+)$/i) : null;
const actual = match && match[1]
? match[1].trim()
: (rawAuth ? rawAuth : (typeof headers['x-codexmate-token'] === 'string' ? String(headers['x-codexmate-token']).trim() : ''));
if (!actual || !safeTimingEqual(actual, expected)) {
sendJson(401, { error: 'Unauthorized' });
const auth = assertRequestAuthorized(req, res);
if (!auth.ok) {
return;
}
}
Expand Down Expand Up @@ -11408,15 +11390,18 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
res.end(errorBody, 'utf-8');
}
});
} else if (requestPath === '/web-ui') {
try {
const html = readBundledWebUiHtml(htmlPath);
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(html);
} catch (error) {
writeWebUiAssetError(res, requestPath, error);
}
} else if (requestPath === '/web-ui/index.html') {
const rawUrl = typeof req.url === 'string' ? req.url : '';
const queryIndex = rawUrl.indexOf('?');
const query = queryIndex >= 0 ? rawUrl.slice(queryIndex) : '';
res.writeHead(302, {
'Location': `/${query}`,
'Content-Type': 'text/plain; charset=utf-8',
'Cache-Control': 'no-store, max-age=0'
});
res.end('Found');
} else if (requestPath.startsWith('/web-ui/')) {
// Skip the /web-ui/ directory itself, which is handled above
const normalized = path.normalize(requestPath).replace(/^([\\.\\/])+/, '');
const filePath = path.join(__dirname, normalized);
if (!isPathInside(filePath, webDir)) {
Expand All @@ -11425,11 +11410,22 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
return;
}
const relativePath = path.relative(webDir, filePath).replace(/\\/g, '/');

// Empty relativePath means direct /web-ui/ access - return 404
if (relativePath === '' || relativePath === 'index.html') {
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Not Found');
return;
}

const dynamicAsset = PUBLIC_WEB_UI_DYNAMIC_ASSETS.get(relativePath);
if (dynamicAsset) {
try {
const assetBody = dynamicAsset.reader(filePath);
res.writeHead(200, { 'Content-Type': dynamicAsset.mime });
res.writeHead(200, {
'Content-Type': dynamicAsset.mime,
'Cache-Control': 'no-store, max-age=0'
});
res.end(assetBody, 'utf-8');
} catch (error) {
writeWebUiAssetError(res, requestPath, error);
Expand All @@ -11456,7 +11452,10 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
: ext === '.json'
? 'application/json; charset=utf-8'
: 'application/octet-stream';
res.writeHead(200, { 'Content-Type': mime });
res.writeHead(200, {
'Content-Type': mime,
'Cache-Control': 'no-store, max-age=0'
});
fs.createReadStream(filePath).pipe(res);
} else if (requestPath.startsWith('/download/')) {
const fileName = requestPath.slice('/download/'.length);
Expand Down Expand Up @@ -11517,15 +11516,27 @@ function createWebServer({ htmlPath, assetsDir, webDir, host, port, openBrowser
: ext === '.json'
? 'application/json; charset=utf-8'
: 'application/octet-stream';
res.writeHead(200, { 'Content-Type': mime });
res.writeHead(200, {
'Content-Type': mime,
'Cache-Control': 'no-store, max-age=0'
});
fs.createReadStream(filePath).pipe(res);
} else {
try {
const html = readBundledWebUiHtml(htmlPath);
res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
res.end(html);
} catch (error) {
writeWebUiAssetError(res, requestPath, error);
// Only serve HTML for root path; /web-ui returns 404.
if (requestPath === '/') {
try {
const html = readBundledWebUiHtml(htmlPath);
res.writeHead(200, {
'Content-Type': 'text/html; charset=utf-8',
'Cache-Control': 'no-store, max-age=0'
});
res.end(html);
} catch (error) {
writeWebUiAssetError(res, requestPath, error);
}
} else {
res.writeHead(404, { 'Content-Type': 'text/plain; charset=utf-8' });
res.end('Not Found');
}
}
});
Expand Down
15 changes: 3 additions & 12 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codexmate",
"version": "0.1.0",
"version": "0.0.35",
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | ⚡ Quick win

Version conflicts with PR objectives.

The PR description states: "Revert package.json version from 0.0.36 to 0.0.34; npm versions 0.0.35 and 0.0.36 are unpublished." However, this change sets the version to 0.0.35, which contradicts the stated goal and may conflict with the unpublished version.

🔧 Proposed fix
-  "version": "0.0.35",
+  "version": "0.0.34",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"version": "0.0.35",
"version": "0.0.34",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 3, The package.json "version" field was incorrectly set
to 0.0.35 while the PR intention is to revert to 0.0.34; open package.json,
change the "version" property value from "0.0.35" to "0.0.34" (ensure the
"version" key is updated), and then check and update any related metadata
(lockfile or CI npm/publish config) to remain consistent with that version.

"description": "Codex/Claude Code/OpenClaw 配置、会话与任务编排 CLI + Web 工具",
"main": "cli.js",
"bin": {
Expand Down Expand Up @@ -46,6 +46,7 @@
},
"dependencies": {
"@iarna/toml": "^2.2.5",
"@vue/compiler-dom": "^3.5.30",
"json5": "^2.2.3",
"yauzl": "^3.2.1",
"zip-lib": "^1.2.1"
Expand Down
Loading
Loading