diff --git a/cypher-executor/src/routes/console-dashboard.ts b/cypher-executor/src/routes/console-dashboard.ts
index ef22ec6..c403443 100644
--- a/cypher-executor/src/routes/console-dashboard.ts
+++ b/cypher-executor/src/routes/console-dashboard.ts
@@ -814,4 +814,9 @@ function renderDashboardHtml(brand: string): string {
// GET /console/dashboard — 駕駛艙頁(無需登入;純渲染 dashboard-data,無互動、無說明文字)
// 品牌字樣(Arcrun#21):引擎預設 Arcrun,實例可用 CONSOLE_BRAND 覆蓋(如 "Arcrun RAG")
-consoleDashboardRouter.get('/console/dashboard', (c) => c.html(renderDashboardHtml(c.env.CONSOLE_BRAND || 'Arcrun')));
+// CONSOLE_PROFILE=rag(console-profile-trim):駕駛艙不屬企業版頁面 → 302 回 /console。
+// 選 302 不選 404:舊書籤/外鏈直接落回產品頁,不給死路(只裁 UI 頁面,資料端點行為不動)。
+consoleDashboardRouter.get('/console/dashboard', (c) => {
+ if ((c.env.CONSOLE_PROFILE || 'full') === 'rag') return c.redirect('/console', 302);
+ return c.html(renderDashboardHtml(c.env.CONSOLE_BRAND || 'Arcrun'));
+});
diff --git a/cypher-executor/src/routes/console.ts b/cypher-executor/src/routes/console.ts
index 072011b..7426669 100644
--- a/cypher-executor/src/routes/console.ts
+++ b/cypher-executor/src/routes/console.ts
@@ -63,7 +63,18 @@ import { TAIPEI_CLIENT_JS } from '../lib/taipei-time';
export const consoleRouter = new Hono<{ Bindings: Bindings }>();
-function renderConsoleHtml(registryBase: string, brand: string): string {
+function renderConsoleHtml(registryBase: string, brand: string, profile: string): string {
+ // Console profile(config 裁剪,非 auth——#24/#25 多人 Portal 是另一回事):
+ // full(未設即此)=全套,Mira 實例現行為一字不變。
+ // rag=企業產品樣:只留 總庫搜尋/工作流/設定(card 是搜尋的詳頁,跟著留),落地=搜尋頁。
+ // 隱藏頁的 view div 仍在 DOM(display:none、路由 guard 導回,永遠點不進)——
+ // 因 creds/inbox 有 top-level addEventListener 綁定,抽掉 div 會讓整包 JS 啟動即炸,
+ // 純渲染層裁剪以「導不進去」為準,不為了抽 DOM 把 null-guard 灑滿全檔。
+ const rag = profile === 'rag';
+ const views = rag
+ ? ['search', 'card', 'workflows', 'settings']
+ : ['cockpit', 'search', 'card', 'workflows', 'creds', 'inbox', 'settings'];
+ const home = rag ? 'search' : 'cockpit';
return `
@@ -302,7 +313,7 @@ function renderConsoleHtml(registryBase: string, brand: string): string {
這是一個人的智慧總部。
若你不是擁有者,這裡沒有你要找的東西。
- 免登入看駕駛艙 ›
+ ${rag ? '' : '免登入看駕駛艙 ›'}
@@ -330,11 +341,11 @@ function renderConsoleHtml(registryBase: string, brand: string): string {
${brand}
-
駕駛艙
+ ${rag ? '' : '
駕駛艙
'}
總庫搜尋
工作流
-
憑證管理
-
分流台
+ ${rag ? '' : `
憑證管理
+
分流台
`}
設定
☾ 切深色
@@ -498,13 +509,13 @@ function renderConsoleHtml(registryBase: string, brand: string): string {
- `}
系統資訊
@@ -518,10 +529,10 @@ function renderConsoleHtml(registryBase: string, brand: string): string {
-
駕駛艙
+ ${rag ? '' : '
駕駛艙
'}
搜尋
工作流
-
分流台
+ ${rag ? '' : '
分流台
'}
設定
@@ -646,11 +657,14 @@ function renderConsoleHtml(registryBase: string, brand: string): string {
}
// ── 路由 ──
- var VIEWS = ['cockpit', 'search', 'card', 'workflows', 'creds', 'inbox', 'settings'];
+ // VIEWS / HOME 由 server 依 CONSOLE_PROFILE 注入(full=全套 7 頁落地駕駛艙;rag=4 頁落地搜尋)。
+ // 不在 VIEWS 裡的 hash(含被 profile 裁掉的頁)一律導回 HOME——手打 #/cockpit 也進不去。
+ var VIEWS = ${JSON.stringify(views)};
+ var HOME = ${JSON.stringify(home)};
function currentRoute() {
var h = location.hash.replace(/^#\\/?/, '');
var seg = h.split('/');
- return { view: VIEWS.indexOf(seg[0]) >= 0 ? seg[0] : 'cockpit', arg: seg.slice(1).join('/') };
+ return { raw: seg[0] || '', view: VIEWS.indexOf(seg[0]) >= 0 ? seg[0] : HOME, arg: seg.slice(1).join('/') };
}
function nav(view, arg) {
location.hash = '#/' + view + (arg ? '/' + encodeURIComponent(arg) : '');
@@ -666,6 +680,8 @@ function renderConsoleHtml(registryBase: string, brand: string): string {
var LOADERS = { cockpit: loadCockpit, search: initSearchOnce, card: loadCard, workflows: loadWorkflows, creds: loadCreds, inbox: loadTriage, settings: loadSettings };
function route() {
var r = currentRoute();
+ // 隱藏頁/不存在頁 guard:hash 不在 VIEWS → 改寫成 HOME(hashchange 會再進來一次正常渲染)
+ if (r.raw && r.raw !== r.view) { location.hash = '#/' + r.view; return; }
if (r.view === 'card' && r.arg) S.cardId = decodeURIComponent(r.arg);
showView(r.view);
if (LOADERS[r.view]) LOADERS[r.view]();
@@ -689,7 +705,7 @@ function renderConsoleHtml(registryBase: string, brand: string): string {
$('shell').classList.add('on');
$('tabbar').classList.add('on');
$('side-foot').innerHTML = '租戶 ' + esc(S.tenant) + '
' + esc(location.host);
- if (!location.hash) location.hash = '#/cockpit';
+ if (!location.hash) location.hash = '#/' + HOME;
route();
}
function init() {
@@ -1476,5 +1492,6 @@ consoleRouter.get('/console', (c) => {
? `https://arcrun-registry.${subdomain}.workers.dev`
: 'https://registry.arcrun.dev';
// 品牌字樣(Arcrun#21):引擎預設 Arcrun,實例可用 CONSOLE_BRAND 覆蓋(如 "Arcrun RAG")
- return c.html(renderConsoleHtml(registryBase, c.env.CONSOLE_BRAND || 'Arcrun'));
+ // 頁面組成(console-profile-trim):CONSOLE_PROFILE 未設=full 全套;"rag"=企業產品樣(搜尋落地)
+ return c.html(renderConsoleHtml(registryBase, c.env.CONSOLE_BRAND || 'Arcrun', c.env.CONSOLE_PROFILE || 'full'));
});
diff --git a/cypher-executor/src/types.ts b/cypher-executor/src/types.ts
index 7e59ac3..21e1867 100644
--- a/cypher-executor/src/types.ts
+++ b/cypher-executor/src/types.ts
@@ -82,6 +82,12 @@ export type Bindings = {
// 不影響任何行為。未設 → "Arcrun"(console 是引擎共用件,不寫死產品名)。
// 實例可覆蓋,例:arcrun-rag demo 可設 --var CONSOLE_BRAND:"Arcrun RAG"。
CONSOLE_BRAND?: string;
+ // Console 頁面組成 profile(console-profile-trim,非機密)。只影響 UI 組成與落地頁,
+ // 不動任何 API/資料行為。未設或 "full" → 全套(Mira 實例現行為,一字不變)。
+ // "rag" → 企業產品樣:側欄只留 總庫搜尋/工作流/設定(含卡片詳頁),落地=搜尋頁;
+ // 駕駛艙/分流台/憑證管理隱藏且路由導回搜尋;/console/dashboard 302 回 /console。
+ // 例:arcrun-rag demo 可設 --var CONSOLE_PROFILE:rag。
+ CONSOLE_PROFILE?: string;
// ── console 駕駛艙「等你的事」活資料源(fix/console-dashboard-live-data,2026-07-07)──
// 等 leo 的事真相源=InkStoneCo sprint 檔「## 等 leo 清單」(progress-guard 每日維護),
// 不是沒人維護的 KBDB dash_wait。cypher 進程內 fetch Gitea API(自架 Gitea,非 GitHub,