mirror of
https://github.com/stablyai/orca.git
synced 2026-10-15 16:02:49 +00:00
fix: attribute dotdot-prefixed usage paths
This commit is contained in:
@@ -228,6 +228,36 @@ describe('attributeCodexUsageEvent', () => {
|
||||
expect(attributed?.worktreeId).toBe('repo-2::/workspace/repo/app2')
|
||||
})
|
||||
|
||||
it('attributes cwd paths under dotdot-prefixed child directories to the worktree', async () => {
|
||||
const attributed = await attributeCodexUsageEvent(
|
||||
{
|
||||
sessionId: 'session-1',
|
||||
timestamp: '2026-04-09T10:00:00.000Z',
|
||||
cwd: '/workspace/repo/..fixtures/session',
|
||||
model: 'gpt-5.2-codex',
|
||||
hasInferredPricing: false,
|
||||
inputTokens: 100,
|
||||
cachedInputTokens: 10,
|
||||
outputTokens: 25,
|
||||
reasoningOutputTokens: 10,
|
||||
totalTokens: 125
|
||||
},
|
||||
[
|
||||
{
|
||||
repoId: 'repo-1',
|
||||
worktreeId: 'repo-1::/workspace/repo',
|
||||
path: '/workspace/repo',
|
||||
displayName: 'Repo',
|
||||
canonicalPath: '/workspace/repo'
|
||||
}
|
||||
]
|
||||
)
|
||||
|
||||
expect(attributed?.projectKey).toBe('worktree:repo-1::/workspace/repo')
|
||||
expect(attributed?.projectLabel).toBe('Repo')
|
||||
expect(attributed?.worktreeId).toBe('repo-1::/workspace/repo')
|
||||
})
|
||||
|
||||
it('does not treat different Windows drives as containing paths', async () => {
|
||||
const attributed = await attributeCodexUsageEvent(
|
||||
{
|
||||
|
||||
@@ -454,7 +454,14 @@ function isContainingPath(candidatePath: string, targetPath: string): boolean {
|
||||
const isAbsoluteRelative = useWin32
|
||||
? win32.isAbsolute(relativePath)
|
||||
: posix.isAbsolute(relativePath)
|
||||
return !isAbsoluteRelative && !relativePath.startsWith('..') && relativePath !== '.'
|
||||
const parentPrefix = useWin32 ? `..${win32.sep}` : `..${posix.sep}`
|
||||
// Why: `..name` is a valid child path; only `..` and `../...` escape.
|
||||
return (
|
||||
!isAbsoluteRelative &&
|
||||
relativePath !== '..' &&
|
||||
!relativePath.startsWith(parentPrefix) &&
|
||||
relativePath !== '.'
|
||||
)
|
||||
}
|
||||
|
||||
function findContainingWorktree(
|
||||
|
||||
@@ -3,7 +3,11 @@ import { mkdtempSync, rmSync } from 'fs'
|
||||
import { tmpdir } from 'os'
|
||||
import { join } from 'path'
|
||||
import { afterEach, describe, expect, it } from 'vitest'
|
||||
import { parseOpenCodeUsageDatabase, parseOpenCodeUsageRow } from './scanner'
|
||||
import {
|
||||
attributeOpenCodeUsageEvent,
|
||||
parseOpenCodeUsageDatabase,
|
||||
parseOpenCodeUsageRow
|
||||
} from './scanner'
|
||||
|
||||
const WORKTREE = '/workspace/repo'
|
||||
|
||||
@@ -72,6 +76,30 @@ describe('parseOpenCodeUsageRow', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('attributeOpenCodeUsageEvent', () => {
|
||||
it('attributes cwd paths under dotdot-prefixed child directories to the worktree', async () => {
|
||||
const attributed = await attributeOpenCodeUsageEvent(
|
||||
{
|
||||
sessionId: 'session-1',
|
||||
timestamp: '2026-04-09T10:00:00.000Z',
|
||||
cwd: `${WORKTREE}/..fixtures/session`,
|
||||
model: 'anthropic/claude-sonnet-4-5',
|
||||
estimatedCostUsd: 0.012,
|
||||
inputTokens: 100,
|
||||
cachedInputTokens: 10,
|
||||
outputTokens: 25,
|
||||
reasoningOutputTokens: 10,
|
||||
totalTokens: 125
|
||||
},
|
||||
worktrees()
|
||||
)
|
||||
|
||||
expect(attributed?.projectKey).toBe('worktree:repo-1::/workspace/repo')
|
||||
expect(attributed?.projectLabel).toBe('Repo')
|
||||
expect(attributed?.worktreeId).toBe('repo-1::/workspace/repo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('parseOpenCodeUsageDatabase', () => {
|
||||
afterEach(() => {
|
||||
for (const dir of tempDirs) {
|
||||
|
||||
@@ -428,7 +428,14 @@ function isContainingPath(candidatePath: string, targetPath: string): boolean {
|
||||
const isAbsoluteRelative = useWin32
|
||||
? win32.isAbsolute(relativePath)
|
||||
: posix.isAbsolute(relativePath)
|
||||
return !isAbsoluteRelative && !relativePath.startsWith('..') && relativePath !== '.'
|
||||
const parentPrefix = useWin32 ? `..${win32.sep}` : `..${posix.sep}`
|
||||
// Why: `..name` is a valid child path; only `..` and `../...` escape.
|
||||
return (
|
||||
!isAbsoluteRelative &&
|
||||
relativePath !== '..' &&
|
||||
!relativePath.startsWith(parentPrefix) &&
|
||||
relativePath !== '.'
|
||||
)
|
||||
}
|
||||
|
||||
async function buildWorktreesWithCanonicalPaths(
|
||||
|
||||
Reference in New Issue
Block a user