Merge remote-tracking branch 'origin/main' into brennanb2025/terminal-prompt-delivery

This commit is contained in:
Brennan Benson
2026-09-20 21:08:19 -07:00
8 changed files with 103 additions and 17 deletions
+10
View File
@@ -0,0 +1,10 @@
diff --git a/index.js b/index.js
index 0480a96d718c997b0a5a54b775e635e2e048e796..85f71b13d3f0f31c3c2140581d1e4051afb21dc3 100644
--- a/index.js
+++ b/index.js
@@ -1,3 +1,5 @@
import * as queryString from './base.js';
export default queryString;
+
+export * from './base.js';
+6 -3
View File
@@ -12,6 +12,9 @@ patchedDependencies:
expo-notifications@55.0.27:
hash: ce20843a3daad4185d7e8571788fa323ba4d11984936188790858650a61749c0
path: patches/expo-notifications@55.0.27.patch
query-string@9.5.1:
hash: 8624f1beedd0705bfdaf287519ed6363662a0c96f01fd594508b34583bf30d8b
path: patches/query-string@9.5.1.patch
react-native-webview@13.16.2:
hash: de6761dfa76a5491a23e49f1262566a8831cab26736a336fdffc5d4e7d05ff27
path: patches/react-native-webview@13.16.2.patch
@@ -9966,7 +9969,7 @@ snapshots:
escape-string-regexp: 4.0.0
fast-deep-equal: 3.1.3
nanoid: 3.3.18
query-string: 9.5.1
query-string: 9.5.1(patch_hash=8624f1beedd0705bfdaf287519ed6363662a0c96f01fd594508b34583bf30d8b)
react: 19.2.8
react-is: 19.2.6
use-latest-callback: 0.2.6(react@19.2.8)
@@ -12230,7 +12233,7 @@ snapshots:
fast-deep-equal: 3.1.3
invariant: 2.2.4
nanoid: 3.3.18
query-string: 9.5.1
query-string: 9.5.1(patch_hash=8624f1beedd0705bfdaf287519ed6363662a0c96f01fd594508b34583bf30d8b)
react: 19.2.8
react-fast-compare: 3.2.2
react-native: 0.83.10(patch_hash=44876634a8efbb0f2c3f66cd4332be170ec821d1cbfc0264ac80680983e8513d)(@babel/core@7.29.7)(@react-native/metro-config@0.85.2(@babel/core@7.29.7))(@types/react@19.2.14)(react@19.2.8)
@@ -14283,7 +14286,7 @@ snapshots:
pure-rand@6.1.0: {}
query-string@9.5.1:
query-string@9.5.1(patch_hash=8624f1beedd0705bfdaf287519ed6363662a0c96f01fd594508b34583bf30d8b):
dependencies:
decode-uri-component: 0.5.0
filter-obj: 5.1.0
+1
View File
@@ -9,5 +9,6 @@ overrides:
patchedDependencies:
expo-notifications@55.0.27: patches/expo-notifications@55.0.27.patch
query-string@9.5.1: patches/query-string@9.5.1.patch
react-native-webview@13.16.2: patches/react-native-webview@13.16.2.patch
react-native@0.83.10: patches/react-native@0.83.10.patch
@@ -0,0 +1,28 @@
import { execFileSync } from 'node:child_process'
import { createRequire } from 'node:module'
import { pathToFileURL } from 'node:url'
import { describe, expect, it } from 'vitest'
/**
* expo-router and React Navigation serialise route params through `import * as queryString from
* 'query-string'`. The lockfile overrides `query-string` to 9.x for a `decode-uri-component`
* advisory, and 9.x's entry has a default export only, so without `patches/query-string@9.5.1.patch`
* every push carrying a param outside the path pattern throws `queryString.stringify is not a
* function` and every href with a query throws on `parse`. Resolved from expo-router's own location,
* the way Metro and the web bundler resolve it for that consumer, and imported by a plain Node
* child: vitest's default-export interop would paper over the missing names in-process.
*/
describe('query-string, as expo-router resolves it', () => {
it('exposes the named API the namespace import needs', () => {
const requireFromHere = createRequire(import.meta.url)
const requireFromExpoRouter = createRequire(requireFromHere.resolve('expo-router/package.json'))
const entry = pathToFileURL(requireFromExpoRouter.resolve('query-string')).href
const script = `const ns = await import(${JSON.stringify(entry)}); process.stdout.write(JSON.stringify({ names: Object.keys(ns).sort(), stringified: typeof ns.stringify === 'function' ? ns.stringify({ from: 'worktrees' }) : null }))`
const output = execFileSync(process.execPath, ['--input-type=module', '-e', script], {
encoding: 'utf8'
})
const { names, stringified } = JSON.parse(output)
expect(names).toEqual(expect.arrayContaining(['parse', 'stringify']))
expect(stringified).toBe('from=worktrees')
})
})
@@ -27,6 +27,7 @@ type OpenCodeSessionUsageRow = {
tokens_output: number
tokens_reasoning: number
tokens_cache_read: number
tokens_cache_write: number
}
function getProjectJoin(db: Database.Database): string {
@@ -46,6 +47,7 @@ function getAssistantSessionMessageCount(db: Database.Database): number {
const assistantPredicate = columnExists(db, 'session_message', 'type')
? "type = 'assistant' AND json_extract(data, '$.tokens.input') IS NOT NULL"
: "json_extract(data, '$.tokens.input') IS NOT NULL"
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SQLite aggregate rows are validated by the typed count field below.
const row = db
.prepare(`SELECT COUNT(*) AS count FROM session_message WHERE ${assistantPredicate}`)
.get() as { count?: number } | undefined
@@ -61,16 +63,29 @@ function canReadSessionUsageRows(db: Database.Database): boolean {
)
}
function getSessionCacheWriteSelect(db: Database.Database): string {
return columnExists(db, 'session', 'tokens_cache_write') ? 's.tokens_cache_write' : '0'
}
function getSessionTokenTotalExpression(db: Database.Database): string {
const cacheWrite = columnExists(db, 'session', 'tokens_cache_write')
? ' + tokens_cache_write'
: ''
return `tokens_input + tokens_output + tokens_reasoning + tokens_cache_read${cacheWrite}`
}
function getSessionUsageRowCount(db: Database.Database): number {
if (!canReadSessionUsageRows(db)) {
return 0
}
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SQLite aggregate rows are validated by the typed count field below.
const row = db
.prepare(
`SELECT COUNT(*) AS count
FROM session
WHERE tokens_input + tokens_output + tokens_reasoning + tokens_cache_read > 0`
WHERE ${getSessionTokenTotalExpression(db)} > 0`
)
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SQLite aggregate rows are validated by the typed count field below.
.get() as { count?: number } | undefined
return row?.count ?? 0
}
@@ -78,14 +93,18 @@ function getSessionUsageRowCount(db: Database.Database): number {
function selectSessionUsageRows(db: Database.Database): OpenCodeUsageRow[] {
const projectJoin = getProjectJoin(db)
const sessionModelSelect = getSessionModelSelect(db)
const cacheWriteSelect = getSessionCacheWriteSelect(db)
const tokenTotalExpression = getSessionTokenTotalExpression(db)
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: SELECT aliases match OpenCodeSessionUsageRow across supported schemas.
const rows = db
.prepare(
`SELECT s.id, s.id AS session_id, s.time_created, s.time_updated,
s.directory, s.title, p.worktree, ${sessionModelSelect},
s.cost, s.tokens_input, s.tokens_output, s.tokens_reasoning, s.tokens_cache_read
s.cost, s.tokens_input, s.tokens_output, s.tokens_reasoning, s.tokens_cache_read,
${cacheWriteSelect} AS tokens_cache_write
FROM session s
${projectJoin}
WHERE s.tokens_input + s.tokens_output + s.tokens_reasoning + s.tokens_cache_read > 0
WHERE ${tokenTotalExpression.replaceAll('tokens_', 's.tokens_')} > 0
ORDER BY s.time_created, s.id`
)
.all() as OpenCodeSessionUsageRow[]
@@ -105,10 +124,15 @@ function selectSessionUsageRows(db: Database.Database): OpenCodeUsageRow[] {
input: row.tokens_input,
output: row.tokens_output,
reasoning: row.tokens_reasoning,
total: row.tokens_input + row.tokens_output + row.tokens_reasoning,
total:
row.tokens_input +
row.tokens_output +
row.tokens_reasoning +
row.tokens_cache_read +
row.tokens_cache_write,
cache: {
read: row.tokens_cache_read,
write: 0
write: row.tokens_cache_write
}
}
})
+10 -6
View File
@@ -43,6 +43,7 @@ function createSessionTotalsSchema(db: Database.Database): void {
tokens_output INTEGER,
tokens_reasoning INTEGER,
tokens_cache_read INTEGER,
tokens_cache_write INTEGER,
time_created INTEGER,
time_updated INTEGER
);
@@ -57,9 +58,9 @@ function insertSessionTotalsRow(
db.prepare(
`INSERT INTO session (
id, directory, title, model, cost,
tokens_input, tokens_output, tokens_reasoning, tokens_cache_read,
tokens_input, tokens_output, tokens_reasoning, tokens_cache_read, tokens_cache_write,
time_created, time_updated
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
).run(
sessionId,
`${WORKTREE}/packages/app`,
@@ -70,6 +71,7 @@ function insertSessionTotalsRow(
100,
0,
0,
0,
1_777_777_700_000,
1_777_777_800_000
)
@@ -235,6 +237,7 @@ describe('parseOpenCodeUsageDatabase', () => {
tokens_output INTEGER,
tokens_reasoning INTEGER,
tokens_cache_read INTEGER,
tokens_cache_write INTEGER,
time_created INTEGER,
time_updated INTEGER
);
@@ -243,9 +246,9 @@ describe('parseOpenCodeUsageDatabase', () => {
db.prepare(
`INSERT INTO session (
id, project_id, directory, title, model, cost,
tokens_input, tokens_output, tokens_reasoning, tokens_cache_read,
tokens_input, tokens_output, tokens_reasoning, tokens_cache_read, tokens_cache_write,
time_created, time_updated
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`
).run(
'session-1',
'project-1',
@@ -257,6 +260,7 @@ describe('parseOpenCodeUsageDatabase', () => {
500,
100,
250,
75,
1_777_777_700_000,
1_777_777_800_000
)
@@ -274,7 +278,7 @@ describe('parseOpenCodeUsageDatabase', () => {
totalCachedInputTokens: 250,
totalOutputTokens: 500,
totalReasoningOutputTokens: 100,
totalTokens: 1850,
totalTokens: 1925,
estimatedCostUsd: 0.06
})
expect(parsed.dailyAggregates).toEqual([
@@ -284,7 +288,7 @@ describe('parseOpenCodeUsageDatabase', () => {
cachedInputTokens: 250,
outputTokens: 500,
reasoningOutputTokens: 100,
totalTokens: 1850,
totalTokens: 1925,
estimatedCostUsd: 0.06
})
])
@@ -3,7 +3,7 @@ import {
AGENT_PROMPT_BRACKETED_PASTE_END,
AGENT_PROMPT_BRACKETED_PASTE_START,
buildAgentPromptPasteBytes,
getAgentPromptSubmitDelayMs
resolveAgentPromptSubmitDelayForAgent
} from '../../../shared/agent-prompt-injection'
import { TUI_AGENT_CONFIG } from '../../../shared/tui-agent-config'
import type { TuiAgent } from '../../../shared/tui-agent'
@@ -610,9 +610,13 @@ describe('OrcaRuntimeService', () => {
launchAgent: agent
})
const submitDelayMs = getAgentPromptSubmitDelayMs(
// The agent's own policy, not the byte-only delay: antigravity adds a per-line settle
// (#21665), and advancing fake timers by less than the policy waits leaves the submit
// pending until the real 30 s timeout.
const submitDelayMs = resolveAgentPromptSubmitDelayForAgent(
process.platform,
Buffer.byteLength(buildAgentPromptPasteBytes('review this change'), 'utf8')
'review this change',
agent
)
const sendPromise = runtime.sendTerminalAgentPrompt(handle, 'review this change')
if (agent === 'omp') {
+12
View File
@@ -1074,17 +1074,24 @@
},
"settings": {
"AccountsPane": {
"0023cc336e": "Paste either the raw token value (e.g.",
"15e831350e": "Configure MiniMax usage tracking from platform.minimax.io.",
"1fd1b1b6b4": "Cookie not set",
"338820326a": ") or the full cookie header (e.g.",
"3455cf43fa": "Claude login.",
"350b2a1aa7": "Use your current",
"4e32e030b2": "Stored locally. Orca sends it only to platform.minimax.io for usage refreshes.",
"566d9a99ab": "_token=…; minimax_group_id_v2=…",
"5e08b0fe57": "Stored locally and sent only to platform.minimax.io for usage refreshes.",
"79418c782a": "Open platform.minimax.io/console/usage in your browser, sign in, then copy the Cookie request header from DevTools (Network → any remains request → Cookie).",
"7ce0e1907c": "). Find it in your browser's DevTools → Network → any opencode.ai request → Cookie header. OpenCode Go auth is web-based and shared across Windows and WSL terminals.",
"8951c5309f": "auth=Fe26.2**…",
"9107406589": "Could not load Claude accounts.",
"922b51e02d": "Fe26.2**…",
"a7e38affcd": "Fe26.2**… token or auth=Fe26.2**… header",
"b10cb4f696": "adding",
"b11078a9c2": "wsl",
"b2b1aa936d": "Paste your opencode.ai session cookie for rate limit fetching.",
"b43e761fe5": "MiniMax cookie update failed.",
"b8c2905c2b": "Could not load Codex accounts.",
"f5d8d2a6a1": "Open platform.minimax.io/console/usage in your browser and sign in."
@@ -1557,6 +1564,11 @@
"7c3bb36706": "remove",
"e2b0ee267f": "stale"
},
"accounts": {
"search": {
"d1d2ae383c": "Paste your opencode.ai session cookie for rate limit fetching."
}
},
"agent-awake-copy": {
"95d3031db2": "Keeps this computer and display awake while agents are working. Lid-close behavior follows this device's power settings.",
"a42f6fbdd8": "Keeps this computer and display awake while agents are working. Orca also asks this device to stay awake when the lid is closed, subject to its power policy.",