mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 00:02:31 +00:00
Merge remote-tracking branch 'origin/main' into brennanb2025/terminal-prompt-delivery
This commit is contained in:
@@ -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';
|
||||
Generated
+6
-3
@@ -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
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
@@ -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
@@ -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.",
|
||||
|
||||
Reference in New Issue
Block a user