Merge remote-tracking branch 'origin/master' into dshw/pr-2250

# Conflicts:
#	packages/client/connection/tests/fake-api.client.ts
#	packages/client/runtime/tests/manager.client.spec.ts
#	packages/client/runtime/tests/workspaces-service.client.spec.ts
#	packages/host/apiproxy/tests/rpc-schemas.spec.ts
This commit is contained in:
_Kerman
2026-08-12 04:22:58 +08:00
523 changed files with 4024 additions and 2331 deletions

View File

@@ -10,7 +10,7 @@ export type {
ApprovalResponsePayload, QuestionResponsePayload, HistoryEntry, ToolEventView,
DirectoryEntry, DirectoryListing,
ResponseValue, WorkspaceApi, WorkspaceId, WorkspaceView,
CommandsApi, CommandDescriptor, SkillsApi, SkillEntry,
SkillsApi, SkillEntry,
ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning,
ModelReasoningEffort, ModelSelection, QueueAction, QueuedInboxItem, SessionModels,
GoalsApi, GoalRef,

View File

@@ -28,6 +28,7 @@ import type {
// Type-only: the brand constructor is host-side; the fixture casts at its
// wire-fabrication boundary (the schema layer's one-cast-point posture).
import type { CommandId } from '@deepseek-ai/dsh-commands/brand'
import type { CommandDescriptor, CommandExecution, CommandResult } from '@deepseek-ai/dsh-commands/types'
import { deriveEventMessage, foldSurface } from '@deepseek-ai/dsh-session/surface'
import type {
ApiProxy, ClientRequest, ClientResponse, HistoryEntry, HostFrame, MuxFrame, RpcReceipt,
@@ -115,7 +116,7 @@ const TERMINAL_OUTPUT_FIXTURE = [
`${sgr(32, '\u2713')} duplication 2.10s`,
`${sgr(31, '\u2717')} unit 8.41s`,
'',
sgr(90, 'packages/client/ui-primitives/tests/terminal-block.spec.tsx'),
sgr(90, 'packages/client/ui-primitives/tests/terminal-block.client.spec.tsx'),
` ${sgr(31, 'FAIL')} caps output at the configured line budget`,
' expected 16 lines, received 24',
'',
@@ -200,7 +201,7 @@ const SEARCH_PATHS_FIXTURE = [
'packages/client/ui-primitives/src/SearchBlock.module.css',
'packages/client/ui-tool/src/client/tool/models/search-card-model.ts',
'packages/client/ui-tool/src/client/tool/toolviews/search-row.tsx',
'packages/client/ui-tool/tests/search-card.spec.tsx',
'packages/client/ui-tool/tests/search-card.client.spec.tsx',
]
/**
@@ -1379,11 +1380,24 @@ export function createFixtureApi(options: FixtureOptions = {}): ApiProxy {
return createFixtureWorld(options).api
}
interface FixtureWorld {
/** Both fixture faces over one state graph. */
export interface FixtureWorld {
/** Legacy unary/stream API the fixture still answers. */
readonly api: ApiProxy
/** Generic Remote caller for the endpoints business services own. */
readonly rpc: ClientConnectionRpc
}
/**
* Build both fixture faces so a caller can drive the Remote endpoints and the
* legacy API against one in-memory state graph.
* @param options - fixture branches for empty state and failure timing.
* @returns the legacy API face and the Remote RPC face.
*/
export function createFixtureFaces(options: FixtureOptions = {}): FixtureWorld {
return createFixtureWorld(options)
}
/** Build the fixture's legacy API and Remote RPC faces over one state graph. */
function createFixtureWorld(options: FixtureOptions): FixtureWorld {
// The resident fixture sessions all carry history, so none of them is blank.
@@ -1598,6 +1612,98 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld {
: undefined
)
/** Canonical fixture implementation of the generated Commands Remote contract. */
const commandRemotes = {
list(id: SessionId): RpcResult<readonly CommandDescriptor[]> {
const missing = requireGoalSession(id)
if (missing !== undefined) return missing
return {
ok: true,
value: [
{ name: 'compact', description: 'fixture压缩当前会话上下文' },
{ name: 'echo', description: 'fixture回显参数', input: { hint: 'text to echo' } },
{ name: 'goal', description: 'set or view the goal for a long-running task', input: { hint: '<objective>' } },
{ name: 'permission', description: 'Switch the permission preset (sandbox mode + approval policy)', input: { hint: '<preset>' } },
{ name: 'plan', description: 'Enter or leave plan mode', input: { hint: '[off|message]' } },
],
}
},
execute(id: SessionId, line: string): RpcResult<CommandExecution | undefined> {
const missing = requireGoalSession(id)
if (missing !== undefined) return missing
// Structured split mirroring the Host parser: name + verbatim rawInput
// (separator whitespace included) — the run payload carries no line.
const match = /^\/(\S+)((?:\s.*)?)$/.exec(line.trim())
const name = match?.[1]
const args = match?.[2] ?? ''
if (name === 'permission') {
const preset = args.trim()
const commandId = `fx-cmd-${logOf(id).length}` as CommandId
append(id, { type: 'command/run', data: { commandId, name, args, source: { kind: 'user' } } })
const spec = PERMISSION_PRESETS[preset]
let result: CommandResult
if (preset === '') {
const current = permissionSelectOf(logOf(id)).currentValue
result = { kind: 'success', text: `current preset ${current} (available: ${Object.keys(PERMISSION_PRESETS).join(', ')})` }
} else if (spec === undefined) {
result = { kind: 'error', text: `unknown preset "${preset}" (available: ${Object.keys(PERMISSION_PRESETS).join(', ')})` }
} else {
if (permissionSelectOf(logOf(id)).currentValue !== preset) append(id, { type: 'permission/preset', data: { preset } })
append(id, { type: 'sandbox/mode', data: { mode: spec.sandbox } })
append(id, { type: 'approval/policy', data: { policy: spec.approval } })
result = { kind: 'success', text: `preset ${preset}` }
}
append(id, { type: 'command/done', data: { commandId, ...result } })
return { ok: true, value: { commandId, result } }
}
if (name === 'goal') {
const commandId = `fx-cmd-${logOf(id).length}` as CommandId
append(id, { type: 'command/run', data: { commandId, name, args, source: { kind: 'user' } } })
const objective = args.trim()
const current = backscanGoal(logOf(id))
let text: string
if (objective === '') {
text = current === null ? 'No goal is set. Usage: /goal <objective>' : `Current goal: ${current.goal.objective}`
} else if (current !== null && current.goal.phase !== 'complete') {
text = `A goal already exists (${current.goal.objective}). Clear it first.`
} else {
const created = appendGoalChange(id, {
kind: 'goal/change', version: 1, operation: 'create',
goal: { id: `fx-goal-${logOf(id).length}`, revision: 1, objective, phase: 'active', maxGoalRounds: 256 },
roundsStarted: 0, createdAt: Date.now(), updatedAt: Date.now(),
})
text = `Goal created: ${created.goal.objective}`
}
const result: CommandResult = { kind: 'success', text }
append(id, { type: 'command/done', data: { commandId, ...result } })
return { ok: true, value: { commandId, result } }
}
const running = summaryOf(id)?.running === true
const outcomes: Record<string, string> = {
compact: 'fixture已压缩假动作',
echo: args.trim(),
plan: args.trim() === 'off'
? (running ? 'Leaving plan mode (applies from the next step).' : 'Plan mode off.')
: (running
? 'Entering plan mode (applies from the next step). Use /plan off to leave.'
: 'Plan mode on. Use /plan off to leave.'),
}
const text = name === undefined ? undefined : outcomes[name]
if (name === undefined || text === undefined) return { ok: true, value: undefined }
const commandId = `fx-cmd-${logOf(id).length}` as CommandId
append(id, { type: 'command/run', data: { commandId, name, args, source: { kind: 'user' } } })
if (name === 'plan' && !running) {
const plan = foldPlan(logOf(id))
if (plan.wanted !== null && plan.wanted !== plan.active) {
append(id, { type: 'plan/mode', data: { active: plan.wanted } })
}
}
const result: CommandResult = { kind: 'success', ...text === '' ? {} : { text } }
append(id, { type: 'command/done', data: { commandId, ...result } })
return { ok: true, value: { commandId, result } }
},
}
const goalView = (projection: FxGoalProjection): FxGoalView => ({
...projection.goal,
roundsStarted: projection.roundsStarted,
@@ -2478,104 +2584,6 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld {
return ok(request, { archivedSessionIds: [...archivedSessionIds] })
},
},
commands: {
// The catalog mirrors one session's effective view (every fixture
// session has an agent, like the real host).
list: (request) => {
const missing = requireSession(request)
if (missing !== undefined) return missing
return ok(request, {
commands: [
{ name: 'compact', description: 'fixture压缩当前会话上下文' },
{ name: 'echo', description: 'fixture回显参数', input: { hint: 'text to echo' } },
{ name: 'goal', description: 'set or view the goal for a long-running task', input: { hint: '<objective>' } },
{ name: 'permission', description: 'Switch the permission preset (sandbox mode + approval policy)', input: { hint: '<preset>' } },
{ name: 'plan', description: 'Enter or leave plan mode', input: { hint: '[off|message]' } },
],
})
},
// Pure admission, mirroring the host: an admitted command logs the
// command/run + command/done lifecycle pair (mux-broadcast by append),
// and the response only reports resolution.
execute: (request) => {
const missing = requireSession(request)
if (missing !== undefined) return missing
const id = request.payload.sessionId
// Structured split mirroring the host parser: name + verbatim rawInput
// (separator whitespace included) — the run payload carries no line.
const match = /^\/(\S+)((?:\s.*)?)$/.exec(request.payload.line.trim())
const name = match?.[1]
const args = match?.[2] ?? ''
// /permission mirrors the host handler: switch through the knob
// events (each append pushes a permissions projection frame).
if (name === 'permission') {
const preset = args.trim()
const commandId = `fx-cmd-${logOf(id).length}` as CommandId
append(id, { type: 'command/run', data: { commandId, name, args, source: { kind: 'user' } } })
const spec = PERMISSION_PRESETS[preset]
if (preset === '') {
const current = permissionSelectOf(logOf(id)).currentValue
append(id, { type: 'command/done', data: { commandId, kind: 'success', text: `current preset ${current} (available: ${Object.keys(PERMISSION_PRESETS).join(', ')})` } })
} else if (spec === undefined) {
append(id, { type: 'command/done', data: { commandId, kind: 'error', text: `unknown preset "${preset}" (available: ${Object.keys(PERMISSION_PRESETS).join(', ')})` } })
} else {
if (permissionSelectOf(logOf(id)).currentValue !== preset) append(id, { type: 'permission/preset', data: { preset } })
append(id, { type: 'sandbox/mode', data: { mode: spec.sandbox } })
append(id, { type: 'approval/policy', data: { policy: spec.approval } })
append(id, { type: 'command/done', data: { commandId, kind: 'success', text: `preset ${preset}` } })
}
return ok(request, { matched: true as const, commandId })
}
if (name === 'goal') {
// Host parallel: /goal with an objective creates (or reports) the
// current goal; the command lifecycle pair brackets the mutation.
const commandId = `fx-cmd-${logOf(id).length}` as CommandId
append(id, { type: 'command/run', data: { commandId, name, args, source: { kind: 'user' } } })
const objective = args.trim()
const current = backscanGoal(logOf(id))
let text: string
if (objective === '') {
text = current === null ? 'No goal is set. Usage: /goal <objective>' : `Current goal: ${current.goal.objective}`
} else if (current !== null && current.goal.phase !== 'complete') {
text = `A goal already exists (${current.goal.objective}). Clear it first.`
} else {
const created = appendGoalChange(id, {
kind: 'goal/change', version: 1, operation: 'create',
goal: { id: `fx-goal-${logOf(id).length}`, revision: 1, objective, phase: 'active', maxGoalRounds: 256 },
roundsStarted: 0, createdAt: Date.now(), updatedAt: Date.now(),
})
text = `Goal created: ${created.goal.objective}`
}
append(id, { type: 'command/done', data: { commandId, kind: 'success', text } })
return ok(request, { matched: true as const, commandId })
}
// Host parallel: /plan on an idle fixture session commits plan/mode
// immediately (the boundary flush covers only a running turn), so the
// outcome copy matches the immediate branch of the host handler.
const running = summaryOf(id)?.running === true
const outcomes: Record<string, string> = {
compact: 'fixture已压缩假动作',
echo: args.trim(),
plan: args.trim() === 'off'
? (running ? 'Leaving plan mode (applies from the next step).' : 'Plan mode off.')
: (running
? 'Entering plan mode (applies from the next step). Use /plan off to leave.'
: 'Plan mode on. Use /plan off to leave.'),
}
const text = name === undefined ? undefined : outcomes[name]
if (name === undefined || text === undefined) return ok(request, { matched: false as const })
const commandId = `fx-cmd-${logOf(id).length}` as CommandId
append(id, { type: 'command/run', data: { commandId, name, args, source: { kind: 'user' } } })
if (name === 'plan' && !running) {
const plan = foldPlan(logOf(id))
if (plan.wanted !== null && plan.wanted !== plan.active) {
append(id, { type: 'plan/mode', data: { active: plan.wanted } })
}
}
append(id, { type: 'command/done', data: { commandId, kind: 'success', ...text === '' ? {} : { text } } })
return ok(request, { matched: true as const, commandId })
},
},
agentPresets: {
// Both trusts appear, because a surface must present a locally authored
// preset differently from one the deployment vetted.
@@ -2884,12 +2892,15 @@ function createFixtureWorld(options: FixtureOptions): FixtureWorld {
const args = (payload as {
args: {
agentId: SessionId
line?: string
ref?: { id: string; revision: number }
request?: { objective?: string; maxGoalRounds?: number }
}
}).args
const sessionId = args.agentId
switch (endpoint) {
case 'commands/list': return Promise.resolve(commandRemotes.list(sessionId))
case 'commands/execute': return Promise.resolve(commandRemotes.execute(sessionId, args.line as string))
case 'goals/create': return Promise.resolve(goalRemotes.create(sessionId, {
objective: args.request?.objective as string,
...args.request?.maxGoalRounds === undefined ? {} : { maxGoalRounds: args.request.maxGoalRounds },
@@ -2983,8 +2994,6 @@ export class FixtureApiClient extends AbstractApiClient {
case 'workspace.insertBefore': return this.api.workspace.insertBefore(request)
case 'workspace.insertSessionBefore': return this.api.workspace.insertSessionBefore(request)
case 'workspace.archiveSession': return this.api.workspace.archiveSession(request)
case 'command.list': return this.api.commands.list(request)
case 'command.execute': return this.api.commands.execute(request, signal)
case 'skill.list': return this.api.skills.list(request)
case 'agentPreset.list': return this.api.agentPresets.list(request)
case 'agentPreset.select': return this.api.agentPresets.select(request)

View File

@@ -18,7 +18,7 @@ export type {
ApprovalResponsePayload, QuestionResponsePayload, HistoryEntry, ToolEventView,
DirectoryEntry, DirectoryListing,
ToolCallView, ToolResultView, WorkspaceApi, WorkspaceId, WorkspaceView,
CommandsApi, CommandDescriptor, SkillsApi, SkillEntry,
SkillsApi, SkillEntry,
ModelCatalogFailure, ModelCatalogModel, ModelProviderGroup, ModelReasoning,
MessageId, ModelReasoningEffort, ModelSelection, QueueAction, QueuedInboxItem, SessionModels,
SubagentsApi, SubagentAddress, SubagentCatalog, SubagentListEntry, SubagentPromptReceipt,

View File

@@ -10,7 +10,7 @@ import { describe, expect, it, vi } from 'vitest'
import type { SessionId } from '../src/client/api.ts'
import type { ConnectionState } from '../src/client/connection.ts'
import { ConnectionController } from '../src/client/connection.ts'
import { FakeApiClient, deferred, ok } from './fake-api.ts'
import { FakeApiClient, deferred, ok } from './fake-api.client.ts'
const SID = 'fk-c1' as SessionId
const FAST = { backoffBaseMs: 10, backoffFactor: 1, backoffMaxMs: 10, streamOpenTimeoutMs: 500 }

View File

@@ -1,9 +1,8 @@
// Test-local programmable IApiClient fake (NOT the fixture: fixture is a demo
// data source on a real clock; behavior tests need per-case responses and
// deferred-controlled timing). Streams are hand pumps: pushMux/pushHost.
import type { CommandId } from '@deepseek-ai/dsh-commands/brand'
import type {
CommandDescriptor, HostFrame, IApiClient, ModelSelection, MuxFrame,
HostFrame, IApiClient, ModelSelection, MuxFrame,
RpcRequest, RpcResponse, SessionId, SessionModels, SessionSearchItem, SkillEntry, WorkspaceId,
} from '../src/client/api.ts'
import { RpcId } from '../src/client/api.ts'
@@ -172,19 +171,10 @@ export class FakeApiClient implements IApiClient {
// Payloads stay `unknown` (lint-lane note above); response rows are the real
// wire shapes so cases can program catalogs and skill lists without casts.
onCommandList: (payload: unknown) => Promise<RpcResponse<{ commands: CommandDescriptor[] }>>
= () => Promise.resolve(ok({ commands: [] }))
onCommandExecute: (payload: unknown) => Promise<RpcResponse<{ matched: boolean; commandId?: CommandId }>>
= () => Promise.resolve(ok({ matched: false }))
onSkillList: (payload: unknown) => Promise<RpcResponse<{ skills: SkillEntry[] }>>
= () => Promise.resolve(ok({ skills: [] }))
readonly commands: IApiClient['commands'] = {
list: (payload: unknown) => this.record('command.list', payload, this.onCommandList(payload)),
execute: (payload: unknown) => this.record('command.execute', payload, this.onCommandExecute(payload)),
}
readonly agentPresets: IApiClient['agentPresets'] = {
list: (payload: unknown) => this.record('agentPreset.list', payload, Promise.resolve(ok({ presets: [], authorable: false, hasDocument: false }))),
select: (payload: { agentPreset: string }) =>

View File

@@ -1,28 +1,35 @@
/**
* Fixture commands/skills domains: contract-shape conformance for the two
* domains added to ApiProxy rpcId echo, session-addressed catalogs, execute
* parse/dispatch, skill.list session resolution, and the FixtureApiClient
* dispatch rows.
* Fixture commands/skills domains: session-addressed catalogs, execute
* parse/dispatch and its logged lifecycle pair, skill.list session resolution,
* and the FixtureApiClient dispatch rows. Commands answer on the Remote face
* and skills on the legacy API face, so both are driven here.
*/
import { describe, expect, it } from 'vitest'
import type { SessionId } from '../src/client/api.ts'
import { RpcId } from '../src/client/api.ts'
import type { RpcRequest } from '../src/client/api.ts'
import { FixtureApiClient, createFixtureApi } from '../src/client/fixture.ts'
import { FixtureApiClient, createFixtureApi, createFixtureFaces } from '../src/client/fixture.ts'
/** Drive one commands Remote endpoint against the fixture state graph. */
async function callRemote<T>(
rpc: ReturnType<typeof createFixtureFaces>['rpc'],
endpoint: string,
args: Record<string, unknown>,
): Promise<T> {
const result = await rpc.call('/api', endpoint, { args })
if (!result.ok) throw new Error(`${endpoint} failed: ${result.error.code}`)
return result.value as T
}
const sid = (id: string): SessionId => id as SessionId
let reqCount = 0
const req = <P>(payload: P): RpcRequest<P> => ({ rpcId: RpcId(`t-${reqCount++}`), payload })
const signal = new AbortController().signal
describe('createFixtureApi commands/skills', () => {
it('serves the addressed session catalog with rpcId echo', async () => {
const api = createFixtureApi()
const request = req({ sessionId: sid('fx-alpha') })
const response = await api.commands.list(request)
expect(response.rpcId).toBe(request.rpcId)
if (!response.result.ok) throw new Error('list failed')
const commands = response.result.value.commands
it('serves the addressed session catalog', async () => {
const { rpc } = createFixtureFaces()
const commands = await callRemote<{ name: string; input?: { hint: string } }[]>(
rpc, 'commands/list', { agentId: sid('fx-alpha') })
expect(commands.map(c => c.name)).toEqual(['compact', 'echo', 'goal', 'permission', 'plan'])
// input hint rides only the commands declaring it.
const echo = commands.find(c => c.name === 'echo')
@@ -31,13 +38,13 @@ describe('createFixtureApi commands/skills', () => {
})
it('rejects a catalog request for an unknown session', async () => {
const api = createFixtureApi()
const response = await api.commands.list(req({ sessionId: sid('fx-nope') }))
expect(response.result).toMatchObject({ ok: false, error: { code: 'session-not-found' } })
const { rpc } = createFixtureFaces()
const result = await rpc.call('/api', 'commands/list', { args: { agentId: sid('fx-nope') } })
expect(result).toMatchObject({ ok: false, error: { code: 'session-not-found' } })
})
it('executes a known command line: pure admission plus a mux-broadcast lifecycle pair', async () => {
const api = createFixtureApi()
const { api, rpc } = createFixtureFaces()
const frames: unknown[] = []
const abort = new AbortController()
const stream = api.events.mux(req({}), abort.signal)
@@ -47,10 +54,9 @@ describe('createFixtureApi commands/skills', () => {
if (frames.filter(f => (f as { type: string }).type === 'session/event').length >= 2) abort.abort()
}
})()
const response = await api.commands.execute(req({ sessionId: sid('fx-alpha'), line: '/echo hello world' }), signal)
if (!response.result.ok) throw new Error('execute failed')
expect(response.result.value).toMatchObject({ matched: true })
expect(response.result.value.commandId).toBeTruthy()
const execution = await callRemote<{ commandId: string } | undefined>(
rpc, 'commands/execute', { agentId: sid('fx-alpha'), line: '/echo hello world' })
expect(execution?.commandId).toBeTruthy()
await pump
const events = frames
.filter((f): f is { type: string; event: { type: string; data: Record<string, unknown> } } => (f as { type: string }).type === 'session/event')
@@ -63,22 +69,23 @@ describe('createFixtureApi commands/skills', () => {
})
it('addresses execute to the session; an unknown session errs', async () => {
const api = createFixtureApi()
const hit = await api.commands.execute(req({ sessionId: sid('fx-alpha'), line: '/goal ship' }), signal)
if (!hit.result.ok) throw new Error('execute failed')
expect(hit.result.value.matched).toBe(true)
const { rpc } = createFixtureFaces()
const hit = await callRemote<{ commandId: string } | undefined>(
rpc, 'commands/execute', { agentId: sid('fx-alpha'), line: '/goal ship' })
expect(hit?.commandId).toBeTruthy()
const missing = await api.commands.execute(req({ sessionId: sid('fx-nope'), line: '/goal ship' }), signal)
expect(missing.result).toMatchObject({ ok: false, error: { code: 'session-not-found' } })
const missing = await rpc.call('/api', 'commands/execute', {
args: { agentId: sid('fx-nope'), line: '/goal ship' },
})
expect(missing).toMatchObject({ ok: false, error: { code: 'session-not-found' } })
})
it('falls to matched:false on unknown names and non-command lines', async () => {
const api = createFixtureApi()
it('answers no execution for unknown names and non-command lines', async () => {
const { rpc } = createFixtureFaces()
for (const line of ['/nope', 'plain text', '/']) {
const response = await api.commands.execute(req({ sessionId: sid('fx-alpha'), line }), signal)
if (!response.result.ok) throw new Error('execute failed')
// Pure admission value: the matched bit is the whole response shape.
expect(response.result.value).toEqual({ matched: false })
// Absence is the whole answer: nothing matched, so no lifecycle id exists.
expect(await callRemote(rpc, 'commands/execute', { agentId: sid('fx-alpha'), line }))
.toBeUndefined()
}
})
@@ -94,14 +101,13 @@ describe('createFixtureApi commands/skills', () => {
})
describe('FixtureApiClient command/skill dispatch', () => {
it('routes the three method keys through the in-memory dispatch table', async () => {
it('routes the Remote commands face and the legacy skill row through one state graph', async () => {
const client = new FixtureApiClient()
const list = await client.commands.list({ sessionId: sid('fx-alpha') })
if (!list.result.ok) throw new Error('command.list failed')
expect(list.result.value.commands.length).toBeGreaterThan(0)
const executed = await client.commands.execute({ sessionId: sid('fx-alpha'), line: '/compact' })
if (!executed.result.ok) throw new Error('command.execute failed')
expect(executed.result.value.matched).toBe(true)
const commands = await callRemote<{ name: string }[]>(client.rpc, 'commands/list', { agentId: sid('fx-alpha') })
expect(commands.length).toBeGreaterThan(0)
const executed = await callRemote<{ commandId: string } | undefined>(
client.rpc, 'commands/execute', { agentId: sid('fx-alpha'), line: '/compact' })
expect(executed?.commandId).toBeTruthy()
const skills = await client.skills.list({ sessionId: sid('fx-alpha') })
if (!skills.result.ok) throw new Error('skill.list failed')
expect(skills.result.value.skills.length).toBeGreaterThan(0)

View File

@@ -0,0 +1,49 @@
{
"extends": "../../../tsconfig.base.client.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib/types",
"tsBuildInfoFile": "lib/tsconfig.client.tsbuildinfo"
},
"files": [
"src/api-path.ts",
"src/client/api.ts",
"src/client/connection.ts",
"src/client/fixture.ts",
"src/client/index.ts",
"src/client/random-uuid.ts",
"src/client/rpc.ts",
"src/client/web-api-client.ts",
"src/loopback-hostname.ts",
"src/rpc.ts"
],
"references": [
{
"path": "../../../vendor/cordis"
},
{
"path": "../../attachment/attachment"
},
{
"path": "../../core/session"
},
{
"path": "../../core/tools"
},
{
"path": "../../host/apiproxy"
},
{
"path": "../../interaction/commands"
},
{
"path": "../../llm/llm"
},
{
"path": "../../support/invariants"
},
{
"path": "../../util/brand"
}
]
}

View File

@@ -0,0 +1,33 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib/types",
"tsBuildInfoFile": "lib/tsconfig.host.tsbuildinfo"
},
"files": [
"src/api-path.ts",
"src/api-request-trust.ts",
"src/http-bridge.ts",
"src/index.ts",
"src/invariant.ts",
"src/loopback-hostname.ts",
"src/rpc-host.ts",
"src/rpc.ts",
"src/websocket-downlink.ts"
],
"references": [
{
"path": "../../attachment/attachment"
},
{
"path": "../../host/apiproxy"
},
{
"path": "../../host/webserver"
},
{
"path": "../../support/invariants"
}
]
}

View File

@@ -1,46 +1,11 @@
{
"extends": "../../../tsconfig.base.client.json",
"compilerOptions": {
"rootDir": "src",
"outDir": "lib/types",
"types": ["node"]
},
"include": [
"src"
],
"files": [],
"references": [
{
"path": "../../attachment/attachment"
"path": "./tsconfig.host.json"
},
{
"path": "../../llm/llm"
},
{
"path": "../../core/session"
},
{
"path": "../../interaction/commands"
},
{
"path": "../../util/brand"
},
{
"path": "../../host/apiproxy"
},
{
"path": "../../host/webserver"
},
{
"path": "../../interaction/user-approval"
},
{
"path": "../../interaction/user-interaction"
},
{
"path": "../../support/invariants"
"path": "./tsconfig.client.json"
}
],
"exclude": [
"**/*.legacy.*"
]
}