Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion docs/reference/orcad-operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -165,7 +165,12 @@ An external supervisor (systemd, launchd, a process manager). orcad conforms to
to **stdout**; the supervisor owns capture and rotation. The daemon, being detached, writes
its own NDJSON lifecycle log to `<data-root>/logs/daemon.log` (suppressed by
`ORCA_DIAGNOSTICS_DISABLED=1`). Rotation of that file is not implemented — see
[What is not covered](#what-is-not-covered).
[What is not covered](#what-is-not-covered). orcad records every trace span it emits
(git commands, worktree paths, terminal spawns, structured-chat failures and the rest) to
`<data-root>/logs/orcad.trace.ndjson`, rotated at 10 MB × 10 files, private to its user and
redacted for secret-shaped strings. It stays on the host: a desktop's diagnostics bundle does
not collect it. `ORCA_DIAGNOSTICS_DISABLED=1` turns it off, and a logs folder orcad cannot
open leaves it off with one stderr warning rather than stopping orcad.

### orcad supervising the daemon

Expand Down
3 changes: 3 additions & 0 deletions src/main/agent-hooks/first-work-branch-rename.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ import {
noUpstreamError,
workingEvent
} from './first-work-branch-rename-test-harness'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'

function makeDeps(overrides: Partial<FirstWorkBranchRenameDeps> = {}) {
return makeBranchRenameDeps(vi.fn, overrides)
Expand Down Expand Up @@ -117,6 +118,7 @@ describe('maybeAutoRenameBranchOnFirstWork', () => {
}
})
const feed = new StructuredAgentSessionStatusFeed({
logger: createStructuredAgentSessionLogger(),
sessions: new Map([
[
'session',
Expand Down Expand Up @@ -215,6 +217,7 @@ describe('maybeAutoRenameBranchOnFirstWork', () => {
}
const pending: Promise<void>[] = []
const feed = new StructuredAgentSessionStatusFeed({
logger: createStructuredAgentSessionLogger(),
sessions: new Map([['session', { journal, params: { location, provider: 'codex' } }]]),
getRecord: () => null,
now: () => 1,
Expand Down
2 changes: 2 additions & 0 deletions src/main/claude/claude-api-retry-idle-sweep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '../native-chat/agent-session-wire/structured-agent-session-host-test-data'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'

const SWEEP_MS = 5
const RETRY_GAP_MS = 10 * 60_000
Expand Down Expand Up @@ -77,6 +78,7 @@ beforeEach(async () => {
setOption: async () => undefined
}
host = new StructuredAgentSessionHost({
logger: createStructuredAgentSessionLogger(),
store,
adapter,
journalDatabase: openTestJournalHostDatabase(root),
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-api-retry-row.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { createDeferredStructuredAgentSessionEventSink } from '../native-chat/ag
import { unhandledProviderFrameJournalItem } from '../native-chat/agent-session-wire/unhandled-provider-frame'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

const IDENTITY: AgentSessionJournalIdentity = {
sessionId: 'session-1',
Expand Down Expand Up @@ -54,7 +55,7 @@ async function statusRowsFor(frames: Record<string, unknown>[]) {
now: () => 1_700_000_000_000,
mintEpoch: () => 'epoch-1'
})
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind({ journal, fence: 1, publish: vi.fn() })
const translator = createClaudeJournalTranslator({ sink: deferred.sink, fallbackIdPrefix: '1' })
for (const frame of frames) {
Expand Down
2 changes: 2 additions & 0 deletions src/main/claude/claude-background-wake-retention.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { backgroundWakeCapture } from './claude-captured-fold-steer-frames.test-
import { MOVED_TO_BACKGROUND } from './claude-captured-task-frames.test-fixture'
import { hostWithParent, parent, producer } from './claude-child-work-producer-harness.test-fixture'
import { PROVIDER_SESSION_ID } from './claude-structured-session-test-support'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'

vi.mock('../telemetry/client', () => ({ track: vi.fn() }))
vi.mock('../telemetry/cohort-classifier', () => ({ getCohortAtEmit: vi.fn(() => ({})) }))
Expand All @@ -40,6 +41,7 @@ async function wiredSession() {
})
}
const feed = new StructuredAgentSessionStatusFeed({
logger: createStructuredAgentSessionLogger(),
sessions: new Map([
[
parent.sessionId,
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-context-usage-restart.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { settleStaleStructuredAgentSessionState } from '../native-chat/agent-ses
import { readAgentJournalTurn } from '../../shared/agent-session-turn-record'
import { bindClaudeContextUsageCapture } from './claude-context-usage'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

const journals = createTrackedJournalOpener()
let root: string
Expand Down Expand Up @@ -112,7 +113,7 @@ async function openJournal(): Promise<AgentSessionJournal> {

/** One acquisition: a fresh sink and translator over the session's journal. */
function acquire(journal: AgentSessionJournal) {
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
const translator = createClaudeJournalTranslator({ sink: deferred.sink, coalesceMs: 0 })
deferred.bind({ journal, fence: 1, publish: () => {} })
const answers: ((value: unknown) => void)[] = []
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-context-usage-unloaded-turn.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import {
userFrame
} from './claude-context-usage-test-support'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

const SESSION = 'orca-session'
const journals = createTrackedJournalOpener()
Expand Down Expand Up @@ -56,7 +57,7 @@ async function openJournal(): Promise<AgentSessionJournal> {
}

function translate(journal: AgentSessionJournal) {
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
const translator = createClaudeJournalTranslator({ sink: deferred.sink, coalesceMs: 0 })
deferred.bind({ journal, fence: 1, publish: () => {} })
const settle = async (): Promise<void> => {
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-stream-json-connection.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import { readClaudeStructuredSessionOptions } from './claude-structured-session-
import type { ClaudeSession } from './claude-structured-session-state'
import { CLAUDE_STRUCTURED_BASE_OPTIONS } from './claude-structured-launch-resolution'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

// These drive the real SDK against the scripted fake CLI, so every assertion is
// about the environment, argv and frames a real child actually saw.
Expand Down Expand Up @@ -385,7 +386,7 @@ describe('Claude stream-json connection', () => {
now: () => 1_700_000_000_000,
mintEpoch: () => 'epoch-1'
})
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind({ journal, fence: 1, publish: vi.fn() })
const translator = createClaudeJournalTranslator({ sink: deferred.sink })
let settled = false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
import type { AgentSessionJournal } from '../native-chat/agent-session-journal/journal-store'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { blockOf } from './claude-background-task-row-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

// The frames below are the ones the reported session actually carried: two real
// failures that printed THREE red rows whose visible text was the wire opcode,
Expand Down Expand Up @@ -179,6 +180,7 @@ describe('claude journal translation — background task rows', () => {
return appendItem(...args)
})
const deferred = createDeferredStructuredAgentSessionEventSink({
...testEventSinkLogging(),
watermarks: {
pauseQueuedOperations: 1,
maxQueuedOperations: 4,
Expand Down Expand Up @@ -252,7 +254,7 @@ describe('claude journal translation — background task rows', () => {

it('coalesces an unbound overflow patch and aliased final notification', async () => {
const persisted = new Map<string, AgentJournalItemBody>()
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
const translator = createClaudeJournalTranslator({
sink: deferred.sink,
fallbackIdPrefix: 'test'
Expand Down Expand Up @@ -292,7 +294,7 @@ describe('claude journal translation — background task rows', () => {

it('reconciles an aliased notification after a parentless overflow patch was persisted', async () => {
const persisted = new Map<string, AgentJournalItemBody>()
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind(persistedTarget(persisted))
const first = createClaudeJournalTranslator({ sink: deferred.sink, fallbackIdPrefix: 'first' })
fillLiveTaskRows(first)
Expand Down Expand Up @@ -353,7 +355,7 @@ describe('claude journal translation — background task rows', () => {

it('resolves a queued restart identity after the sink rebinds', async () => {
const persisted = new Map<string, AgentJournalItemBody>()
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind(persistedTarget(persisted))

const first = createClaudeJournalTranslator({ sink: deferred.sink, fallbackIdPrefix: 'first' })
Expand All @@ -371,7 +373,7 @@ describe('claude journal translation — background task rows', () => {
first.dispose()
await deferred.drained()

const restarted = createDeferredStructuredAgentSessionEventSink()
const restarted = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
const second = createClaudeJournalTranslator({
sink: restarted.sink,
fallbackIdPrefix: 'second'
Expand All @@ -397,7 +399,7 @@ describe('claude journal translation — background task rows', () => {

it('keeps pending writes from distinct runs when a translator is recreated', async () => {
const persisted = new Map<string, AgentJournalItemBody>()
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())

const first = createClaudeJournalTranslator({ sink: deferred.sink, fallbackIdPrefix: 'first' })
spawnToolCall(first, 'toolu-first')
Expand Down
5 changes: 3 additions & 2 deletions src/main/claude/claude-structured-journal-translation.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type { ClaudePendingPrompt } from './claude-structured-prompt-replies'
import { readAgentJournalTurn } from '../../shared/agent-session-turn-record'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

function sinkState() {
const items: { identity: AgentJournalItemIdentity; body: AgentJournalItemBody }[] = []
Expand Down Expand Up @@ -258,7 +259,7 @@ describe('Claude structured journal translation', () => {
now: () => 1_700_000_000_000,
mintEpoch: () => 'epoch-1'
})
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind({ journal, fence: 1, publish: vi.fn() })
let scheduled: (() => void) | null = null
const translator = createClaudeJournalTranslator({
Expand Down Expand Up @@ -317,7 +318,7 @@ describe('Claude structured journal translation', () => {
now: () => 1_700_000_000_000,
mintEpoch: () => 'epoch-1'
})
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind({ journal, fence: 1, publish: vi.fn() })
const translator = createClaudeJournalTranslator({ sink: deferred.sink })
const approval = prompt({
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-structured-provider-fallback.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { createDeferredStructuredAgentSessionEventSink } from '../native-chat/ag
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import type { ClaudeStructuredSessionEvent } from './claude-structured-session-state'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

const IDENTITY: AgentSessionJournalIdentity = {
sessionId: 'session-1',
Expand Down Expand Up @@ -80,7 +81,7 @@ describe('Claude provider fallback', () => {
now: () => 1_700_000_000_000,
mintEpoch: () => 'epoch-1'
})
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind({
journal,
fence: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
identityFor,
PROVIDER_SESSION_ID
} from './claude-structured-session-test-support'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

function controlledSink(): {
sink: StructuredAgentSessionEventSink
Expand Down Expand Up @@ -212,6 +213,7 @@ describe('Claude structured reading control', () => {
const persisted = new Map<string, AgentJournalItemBody>()
const target = persistedTarget(persisted)
const deferred = createDeferredStructuredAgentSessionEventSink({
...testEventSinkLogging(),
watermarks: {
pauseQueuedOperations: 1,
maxQueuedOperations: 4,
Expand Down
5 changes: 3 additions & 2 deletions src/main/claude/claude-subagent-resume-after-restart.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import { createTrackedJournalOpener } from '../native-chat/agent-session-journal
import { createDeferredStructuredAgentSessionEventSink } from '../native-chat/agent-session-wire/structured-agent-session-event-sink'
import { createClaudeJournalTranslator } from './claude-structured-journal-translation'
import { claudeSubagentGroupBody, claudeSubagentGroupIdentity } from './claude-subagent-group-row'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

// Frame orders are real sessions', scrubbed. A resumed agent's frames still name its ORIGINAL
// spawn call while the announcement names the message call that resumed it, and a new provider
Expand Down Expand Up @@ -137,7 +138,7 @@ async function openJournal(): Promise<AgentSessionJournal> {

/** One provider process: a fresh sink and translator over the session's journal. */
function acquire(journal: AgentSessionJournal) {
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
const translator = createClaudeJournalTranslator({ sink: deferred.sink, coalesceMs: 0 })
deferred.bind({ journal, fence: 1, publish: () => {} })
const settle = async (): Promise<void> => {
Expand Down Expand Up @@ -190,7 +191,7 @@ const rosterIds = (journal: AgentSessionJournal): Set<string> =>
/** An older build re-rostered a resumed child in the later turn's row, so two rows list it. */
async function journalAnOlderBuildListedTwice(): Promise<AgentSessionJournal> {
const journal = await openJournal()
const older = createDeferredStructuredAgentSessionEventSink()
const older = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
older.bind({ journal, fence: 1, publish: () => {} })
const listed = (id: string, state: NativeChatSubagentEntry['state']) => ({
id,
Expand Down
3 changes: 2 additions & 1 deletion src/main/claude/claude-subagent-roster.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
type StructuredAgentSessionEventSink
} from '../native-chat/agent-session-wire/structured-agent-session-event-sink'
import { ClaudeSubagentRoster } from './claude-subagent-roster'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

const TURN_1 = 'claude-session:turn-1'

Expand Down Expand Up @@ -462,7 +463,7 @@ describe('ClaudeSubagentRoster — through the real sink queue', () => {
},
appendTombstone: async () => ({ epoch: 'e', sequence: 0 })
} as unknown as AgentSessionJournal
const deferred = createDeferredStructuredAgentSessionEventSink()
const deferred = createDeferredStructuredAgentSessionEventSink(testEventSinkLogging())
deferred.bind({
journal,
fence: 1,
Expand Down
2 changes: 2 additions & 0 deletions src/main/codex/codex-provider-retry-idle-sweep.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '../native-chat/agent-session-wire/structured-agent-session-host-test-data'
import { createCodexJournalTranslator } from './codex-structured-journal-translation'
import { openTestJournalHostDatabase } from '../native-chat/agent-session-journal/journal-host-database-test-support'
import { createStructuredAgentSessionLogger } from '../native-chat/agent-session-wire/structured-agent-session-logger'

const SWEEP_MS = 5
const RETRY_GAP_MS = 10 * 60_000
Expand Down Expand Up @@ -75,6 +76,7 @@ beforeEach(async () => {
setOption: async () => undefined
}
host = new StructuredAgentSessionHost({
logger: createStructuredAgentSessionLogger(),
store,
adapter,
journalDatabase: openTestJournalHostDatabase(root),
Expand Down
8 changes: 6 additions & 2 deletions src/main/codex/codex-structured-journal-goal-resume.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
} from '../native-chat/agent-session-wire/structured-agent-session-event-sink'
import { CodexJournalGoals } from './codex-structured-journal-goals'
import { MAX_CODEX_GOAL_THREADS } from './codex-structured-journal-limits'
import { testEventSinkLogging } from '../native-chat/agent-session-wire/structured-agent-session-logger-test-support'

const THREAD = '01a08cc2-f96e-76d0-bb74-88b9bc0b03fc'

Expand All @@ -34,7 +35,7 @@ function goalFrame(goal: Record<string, unknown> = {}): Record<string, unknown>
}

function goalJournal(
options: Parameters<typeof createDeferredStructuredAgentSessionEventSink>[0] = {}
options: Partial<Parameters<typeof createDeferredStructuredAgentSessionEventSink>[0]> = {}
) {
let rowSequence = 0
let publishes = 0
Expand All @@ -43,7 +44,10 @@ function goalJournal(
let visitedItems = 0
const rows = new Map<string, AgentJournalRenderItem>()
const writes: string[] = []
const deferred = createDeferredStructuredAgentSessionEventSink(options)
const deferred = createDeferredStructuredAgentSessionEventSink({
...testEventSinkLogging(),
...options
})
// oxlint-disable-next-line typescript/consistent-type-assertions -- SAFETY: a fake journal exposing only the members the goal translator and deferred sink call.
const journal = {
get epoch() {
Expand Down
Loading
Loading