Enable maximum-strict TypeScript across our packages

tsconfig.base.json adds noUncheckedIndexedAccess,
exactOptionalPropertyTypes, noImplicitOverride,
noFallthroughCasesInSwitch, noUnusedLocals, and noUnusedParameters on
top of strict. Vendored packages opt out of the new flags locally
(their tsconfigs are ours to regenerate; their source is not), keeping
upstream-sync friendliness.

Our code fixed accordingly: index accesses acknowledge undefined
(assembler flush cursors, lastTurnNumber); optional properties are
omitted instead of set-to-undefined (GenerateResult.usage,
ToolDefinition.strict, GenerateOptions.system/tools, error payloads
via an errorData helper); Session.onAppend is explicitly
`(…) => void | undefined`; tests and examples updated for unused
parameters and indexed access.
This commit is contained in:
Tianyi Cui
2026-06-11 14:02:47 +08:00
parent 2b447625fa
commit d2fb352f3e
21 changed files with 214 additions and 86 deletions

View File

@@ -57,8 +57,8 @@ function renderTagged(tag: string, content: ContentBlock[], source: MessageSourc
*/
export class Session {
private log: SessionEvent[] = []
/** Set by the store so appends are observable; no-op when detached. */
onAppend?: (event: SessionEvent) => void
/** Set by the store so appends are observable; undefined when detached. */
onAppend: ((event: SessionEvent) => void) | undefined
constructor(public readonly id: string, seed?: SessionEvent[]) {
if (seed) this.log = [...seed]

View File

@@ -21,8 +21,8 @@ describe('Session', () => {
const messages = session.deriveMessages()
expect(messages.map(m => m.role)).toEqual(['user', 'assistant', 'user'])
// raw chunks must NOT appear in derived history
expect(messages[1].content).toHaveLength(2)
expect(messages[2].content[0]).toMatchObject({ type: 'tool-result', toolCallId: 'c1' })
expect(messages[1]!.content).toHaveLength(2)
expect(messages[2]!.content[0]).toMatchObject({ type: 'tool-result', toolCallId: 'c1' })
})
it('renders context and steering messages as tagged synthetic user content', () => {
@@ -38,10 +38,10 @@ describe('Session', () => {
})
const [contextMessage, steeringMessage] = session.deriveMessages()
expect(contextMessage.role).toBe('user')
expect(contextMessage.content[0]).toMatchObject({ type: 'text', text: '<context source="plugin">' })
expect(contextMessage.content.at(-1)).toMatchObject({ type: 'text', text: '</context>' })
expect(steeringMessage.content[0]).toMatchObject({ type: 'text', text: '<steering source="user">' })
expect(contextMessage!.role).toBe('user')
expect(contextMessage!.content[0]).toMatchObject({ type: 'text', text: '<context source="plugin">' })
expect(contextMessage!.content.at(-1)).toMatchObject({ type: 'text', text: '</context>' })
expect(steeringMessage!.content[0]).toMatchObject({ type: 'text', text: '<steering source="user">' })
})
it('replays identically from a seeded event log', () => {
@@ -70,8 +70,8 @@ describe('SessionStore', () => {
session.append('user/message', { content: [{ type: 'text', text: 'x' }], source: { kind: 'user' } })
expect(events).toHaveLength(1)
expect(events[0][0]).toBe(session)
expect(events[0][1].type).toBe('user/message')
expect(events[0]![0]).toBe(session)
expect(events[0]![1].type).toBe('user/message')
expect(ctx.sessions.get(session.id)).toBe(session)
expect(ctx.sessions.list()).toEqual([session])