diff --git a/ui-tui/src/__tests__/createSlashHandler.test.ts b/ui-tui/src/__tests__/createSlashHandler.test.ts index a671063e5e9..c0247795af3 100644 --- a/ui-tui/src/__tests__/createSlashHandler.test.ts +++ b/ui-tui/src/__tests__/createSlashHandler.test.ts @@ -9,6 +9,10 @@ describe('createSlashHandler', () => { beforeEach(() => { resetOverlayState() resetUiState() + delete process.env.HERMES_TUI_INLINE + delete process.env.HERMES_HOME + delete process.env.HERMES_WRITE_SAFE_ROOT + delete process.env.HERMES_DISABLE_LAZY_INSTALLS }) it('opens the unified sessions overlay for /resume', () => { @@ -68,6 +72,32 @@ describe('createSlashHandler', () => { expect(ctx.gateway.gw.request).not.toHaveBeenCalled() }) + it('keeps hosted dashboard chat alive for /exit', () => { + process.env.HERMES_TUI_INLINE = '1' + process.env.HERMES_HOME = '/opt/data/profiles/worker' + process.env.HERMES_WRITE_SAFE_ROOT = '/opt/data' + process.env.HERMES_DISABLE_LAZY_INSTALLS = '1' + const ctx = buildCtx() + + expect(createSlashHandler(ctx)('/exit')).toBe(true) + expect(ctx.session.die).not.toHaveBeenCalled() + expect(ctx.gateway.gw.request).not.toHaveBeenCalled() + expect(ctx.transcript.sys).toHaveBeenCalledWith( + 'exit is disabled in hosted dashboard chat — use /new to start a fresh session' + ) + }) + + it('keeps /quit available outside hosted dashboard chat', () => { + process.env.HERMES_TUI_INLINE = '1' + process.env.HERMES_HOME = '/Users/example/.hermes' + process.env.HERMES_WRITE_SAFE_ROOT = '/Users/example/.hermes' + process.env.HERMES_DISABLE_LAZY_INSTALLS = '1' + const ctx = buildCtx() + + expect(createSlashHandler(ctx)('/quit')).toBe(true) + expect(ctx.session.die).toHaveBeenCalledTimes(1) + }) + it('handles /update locally and exits with code 42 via dieWithCode', () => { vi.useFakeTimers() const ctx = buildCtx() diff --git a/ui-tui/src/app/slash/commands/core.ts b/ui-tui/src/app/slash/commands/core.ts index 5c021dbcdf9..b5d72cf7712 100644 --- a/ui-tui/src/app/slash/commands/core.ts +++ b/ui-tui/src/app/slash/commands/core.ts @@ -76,6 +76,20 @@ const DETAILS_USAGE = const DETAILS_SECTION_USAGE = 'usage: /details
[hidden|collapsed|expanded|reset]' +const truthyEnv = (v?: string) => /^(?:1|true|yes|on)$/i.test((v ?? '').trim()) + +const hostedInlineDashboardChat = () => { + const hermesHome = (process.env.HERMES_HOME ?? '').trim() + const hostedHome = hermesHome === '/opt/data' || hermesHome.startsWith('/opt/data/') + + return ( + process.env.HERMES_TUI_INLINE === '1' && + hostedHome && + process.env.HERMES_WRITE_SAFE_ROOT === '/opt/data' && + truthyEnv(process.env.HERMES_DISABLE_LAZY_INSTALLS) + ) +} + export const coreCommands: SlashCommand[] = [ { help: 'list commands + hotkeys', @@ -113,7 +127,15 @@ export const coreCommands: SlashCommand[] = [ aliases: ['exit'], help: 'exit hermes', name: 'quit', - run: (_arg, ctx) => ctx.session.die() + run: (_arg, ctx) => { + if (hostedInlineDashboardChat()) { + ctx.transcript.sys('exit is disabled in hosted dashboard chat — use /new to start a fresh session') + + return + } + + ctx.session.die() + } }, {