fix(cli): preserve active query access
This commit is contained in:
@@ -8,6 +8,9 @@
|
|||||||
- id: telemetry-redact-rule
|
- id: telemetry-redact-rule
|
||||||
name: './telemetry-redact-rule.ts'
|
name: './telemetry-redact-rule.ts'
|
||||||
|
|
||||||
|
- id: subprocess
|
||||||
|
name: '@deepseek-ai/dsh-subprocess-local'
|
||||||
|
|
||||||
- id: bash
|
- id: bash
|
||||||
name: '@deepseek-ai/dsh-bash-local'
|
name: '@deepseek-ai/dsh-bash-local'
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ import {
|
|||||||
type SlashCommand,
|
type SlashCommand,
|
||||||
type TerminalColorScheme,
|
type TerminalColorScheme,
|
||||||
} from '@earendil-works/pi-tui'
|
} from '@earendil-works/pi-tui'
|
||||||
import { Service, type Context, type Fiber } from 'cordis'
|
import { Service, type Context, type Fiber, type FiberState } from 'cordis'
|
||||||
import {
|
import {
|
||||||
assembleContextFor,
|
assembleContextFor,
|
||||||
installAgentLlmTarget,
|
installAgentLlmTarget,
|
||||||
@@ -55,6 +55,7 @@ import {
|
|||||||
TuiExtensionServiceImpl,
|
TuiExtensionServiceImpl,
|
||||||
TuiOverlayManager,
|
TuiOverlayManager,
|
||||||
} from './extension/overlay-manager.ts'
|
} from './extension/overlay-manager.ts'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
parseTuiPromptTemplate,
|
parseTuiPromptTemplate,
|
||||||
renderTuiPromptTemplate,
|
renderTuiPromptTemplate,
|
||||||
@@ -170,6 +171,9 @@ export type {
|
|||||||
TuiViewport,
|
TuiViewport,
|
||||||
} from './extension/types.ts'
|
} from './extension/types.ts'
|
||||||
|
|
||||||
|
/** First terminal Cordis state: FAILED, DISPOSED, and UNLOADING are unusable. */
|
||||||
|
const FIBER_FAILED = 3 as FiberState.FAILED
|
||||||
|
|
||||||
declare module 'cordis' {
|
declare module 'cordis' {
|
||||||
interface Context {
|
interface Context {
|
||||||
/** Terminal-only interaction service, available only while a TUI is mounted. */
|
/** Terminal-only interaction service, available only while a TUI is mounted. */
|
||||||
@@ -840,10 +844,14 @@ export function createTuiChat(
|
|||||||
resolved,
|
resolved,
|
||||||
palette,
|
palette,
|
||||||
overlayManager,
|
overlayManager,
|
||||||
// Optional and independently mounted: read at each use so config row order
|
// Optional and independently mounted. Cordis transiently leaves this sibling
|
||||||
// cannot decide whether /resume works. Strict lookup excludes a closing or
|
// non-ACTIVE during command callbacks, so the non-strict read is intentional;
|
||||||
// closed provider rather than dispatching into a stale SQLite handle.
|
// terminal fiber states still exclude failed, closing, and closed providers.
|
||||||
sessionQuery: () => ctx.get('sessionQuery'),
|
sessionQuery: () => {
|
||||||
|
const implementation = ctx.reflect._getImpl('sessionQuery', false)
|
||||||
|
if (implementation === undefined || implementation.fiber.state >= FIBER_FAILED) return undefined
|
||||||
|
return ctx.get('sessionQuery', false)
|
||||||
|
},
|
||||||
ui,
|
ui,
|
||||||
editor,
|
editor,
|
||||||
appendNotice,
|
appendNotice,
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ import { mkdir, mkdtemp, rm, writeFile } from 'node:fs/promises'
|
|||||||
import { homedir, tmpdir } from 'node:os'
|
import { homedir, tmpdir } from 'node:os'
|
||||||
import { join, resolve } from 'node:path'
|
import { join, resolve } from 'node:path'
|
||||||
import { describe, expect, it, vi } from 'vitest'
|
import { describe, expect, it, vi } from 'vitest'
|
||||||
import { Context } from 'cordis'
|
import { Context, type FiberState } from 'cordis'
|
||||||
import { CombinedAutocompleteProvider, visibleWidth, type Terminal } from '@earendil-works/pi-tui'
|
import { CombinedAutocompleteProvider, visibleWidth, type Terminal } from '@earendil-works/pi-tui'
|
||||||
import AgentRegistry, {
|
import AgentRegistry, {
|
||||||
agentEvents, assembleContextFor, InboxItemId, type Agent, type InboxItem,
|
agentEvents, assembleContextFor, InboxItemId, type Agent, type InboxItem,
|
||||||
@@ -503,7 +503,7 @@ describe('goodbye message and /resume', () => {
|
|||||||
await dispose(result)
|
await dispose(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('treats a closed session-query provider as unavailable', async () => {
|
it('treats a terminal-state session-query provider as unavailable', async () => {
|
||||||
let queryCtx: Context | undefined
|
let queryCtx: Context | undefined
|
||||||
const result = await setup({
|
const result = await setup({
|
||||||
cwd: '/workspace',
|
cwd: '/workspace',
|
||||||
@@ -518,12 +518,15 @@ describe('goodbye message and /resume', () => {
|
|||||||
})
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
await queryCtx!.fiber.dispose()
|
if (queryCtx === undefined) throw new Error('query provider did not mount')
|
||||||
|
const activeState = queryCtx.fiber.state
|
||||||
|
queryCtx.fiber.state = 5
|
||||||
result.terminal.send('/resume')
|
result.terminal.send('/resume')
|
||||||
result.terminal.send('\r')
|
result.terminal.send('\r')
|
||||||
await tick()
|
await tick()
|
||||||
expect(result.terminal.output).toContain('session query is not mounted')
|
expect(result.terminal.output).toContain('session query is not mounted')
|
||||||
expect(result.terminal.output).not.toContain('closed database')
|
expect(result.terminal.output).not.toContain('closed database')
|
||||||
|
queryCtx.fiber.state = activeState
|
||||||
await dispose(result)
|
await dispose(result)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user