Files
orca/src/main/codex/codex-app-server-record-prefix.ts
T
Brennan BensonandMerge Sim 872bd51d47 fix(native-chat): reland large structured command results (#17720)
* fix(native-chat): preserve large structured command results (#17707)

* fix(native-chat): preserve large structured command results

* chore: place native chat validation artifacts under docs

* chore: drop stale root package config

* fix(native-chat): enforce rebuilt lifecycle append slots

---------

Co-authored-by: Merge Sim <sim@local>

* chore: omit native-chat reland planning docs

* fix(native-chat): remove journal store import cycle

* fix(native-chat): keep journal factory acyclic

---------

Co-authored-by: Merge Sim <sim@local>
2026-08-31 13:12:19 -07:00

187 lines
4.9 KiB
TypeScript

export type JsonRpcPrefix =
| { kind: 'response'; id: number }
| { kind: 'server-request'; id: number | string; method: string }
| { kind: 'notification'; method: string }
| { kind: 'response-unknown' }
| { kind: 'unknown' }
type LeadingProperty = { key: string; value?: string | number }
function readJsonStringEnd(value: string, start: number): number | null {
if (value[start] !== '"') {
return null
}
let escaped = false
for (let index = start + 1; index < value.length; index += 1) {
const character = value[index]
if (escaped) {
escaped = false
} else if (character === '\\') {
escaped = true
} else if (character === '"') {
return index + 1
}
}
return null
}
function skipJsonContainer(value: string, start: number): number | null {
const opening = value[start]
const closing = opening === '{' ? '}' : opening === '[' ? ']' : null
if (!closing) {
return null
}
const stack = [closing]
let escaped = false
let inString = false
for (let index = start + 1; index < value.length; index += 1) {
const character = value[index]
if (inString) {
if (escaped) {
escaped = false
} else if (character === '\\') {
escaped = true
} else if (character === '"') {
inString = false
}
continue
}
if (character === '"') {
inString = true
continue
}
if (character === '{') {
stack.push('}')
} else if (character === '[') {
stack.push(']')
} else if (character === stack.at(-1)) {
stack.pop()
if (stack.length === 0) {
return index + 1
}
}
}
return null
}
function skipJsonLiteral(value: string, start: number): number | null {
for (const literal of ['true', 'false', 'null']) {
if (value.startsWith(literal, start)) {
return start + literal.length
}
}
return null
}
function leadingJsonRpcProperties(prefix: string): LeadingProperty[] {
const properties: LeadingProperty[] = []
let cursor = 0
const skipWhitespace = (): void => {
while (/\s/.test(prefix[cursor] ?? '')) {
cursor += 1
}
}
skipWhitespace()
if (prefix[cursor] !== '{') {
return properties
}
cursor += 1
while (properties.length < 8) {
skipWhitespace()
const keyEnd = readJsonStringEnd(prefix, cursor)
if (keyEnd === null) {
break
}
let key: unknown
try {
key = JSON.parse(prefix.slice(cursor, keyEnd))
} catch {
break
}
cursor = keyEnd
skipWhitespace()
if (prefix[cursor] !== ':') {
break
}
cursor += 1
skipWhitespace()
if (prefix[cursor] === '{' || prefix[cursor] === '[') {
properties.push({ key: String(key) })
const valueEnd = skipJsonContainer(prefix, cursor)
if (valueEnd === null) {
break
}
cursor = valueEnd
skipWhitespace()
if (prefix[cursor] !== ',') {
break
}
cursor += 1
continue
}
const literalEnd = skipJsonLiteral(prefix, cursor)
if (literalEnd !== null) {
properties.push({ key: String(key) })
cursor = literalEnd
skipWhitespace()
if (prefix[cursor] !== ',') {
break
}
cursor += 1
continue
}
const stringEnd = readJsonStringEnd(prefix, cursor)
if (stringEnd !== null) {
try {
properties.push({ key: String(key), value: JSON.parse(prefix.slice(cursor, stringEnd)) })
} catch {
break
}
cursor = stringEnd
skipWhitespace()
if (prefix[cursor] !== ',') {
break
}
cursor += 1
continue
}
const match = /^-?(?:0|[1-9]\d*)/.exec(prefix.slice(cursor))
if (!match) {
break
}
properties.push({ key: String(key), value: Number(match[0]) })
cursor += match[0].length
skipWhitespace()
if (prefix[cursor] !== ',') {
break
}
cursor += 1
}
return properties
}
export function classifyJsonRpcPrefix(prefix: string): JsonRpcPrefix {
// Only inspect complete top-level properties. Searching arbitrary quoted
// keys would let a nested result/params object impersonate JSON-RPC fields.
const properties = leadingJsonRpcProperties(prefix)
const method = properties.find((property) => property.key === 'method')?.value
const id = properties.find((property) => property.key === 'id')?.value
if (typeof method === 'string' && (typeof id === 'number' || typeof id === 'string')) {
return { kind: 'server-request', id, method }
}
if (
typeof id === 'number' &&
properties.some((property) => property.key === 'id') &&
properties.some((property) => property.key === 'result' || property.key === 'error')
) {
return { kind: 'response', id }
}
if (typeof id === 'number') {
return { kind: 'response-unknown' }
}
if (typeof method === 'string' && properties.some((property) => property.key === 'params')) {
return { kind: 'notification', method }
}
return { kind: 'unknown' }
}