mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-15 12:55:51 +00:00
fixup: address CodeRabbit review on PR #386
Twelve actionable items (7 Major + 5 Minor) from the CodeRabbit review on claude-code-best/claude-code#386: - docs/internals/autonomy-jira.md: typo "due input close" → "due to input close". - src/utils/autonomyRuns.ts: - selectPersistedAutonomyRuns no longer evicts active (queued/running) runs when the combined list exceeds AUTONOMY_RUNS_MAX. Active runs are kept in full and the inactive history is capped to the remaining budget so persisted ownership for live work survives. - isValidOwnerProcessId now allows pid <= 4_194_304 so a live run owned by the maximum Linux PID is not treated as stale. - src/utils/autonomyAuthority.ts: maskCodeFencedLines tracks the active fence length and only closes the fence when a same-character run of equal-or- greater length appears with no trailing content, so a nested ```yaml inside an outer ```` block no longer leaks fake `tasks:` entries into the parser. - src/cli/print.ts: late-shutdown branches in the cron and scheduled-task paths now call cancelQueuedAutonomyCommands({ commands: [command] }) instead of markAutonomyRunCancelled(...). Updating run state alone left the queue-side record orphaned for resume/recovery. - src/utils/processUserInput/processSlashCommand.tsx: scheduled-task-result notification is enqueued before finalizeAutonomyRunCompleted (which queues follow-up autonomy commands) so both at priority: 'later' land in order and the next autonomy step can not run before the worker's output is observed. - src/screens/REPL.tsx + src/utils/handlePromptSubmit.ts: - onQuery now returns Promise<boolean>: false from the concurrent-guard skip path, true otherwise. Other call sites use `void onQuery(...)` and are unaffected. handlePromptSubmit's onQuery prop type matches. - The autonomy-prompt callsite captures the executed flag, finalizes claim.claimedCommands as { type: 'completed' } only when onQuery actually ran, and runs the completed-finalize in its own try/catch so a failure there does not propagate into the outer catch and trigger a second finalize as { type: 'failed' } for the same commands. - Removed the unsafe `command.value as string` cast; createUserMessage already accepts `string | ContentBlockParam[]`. - createUserMessage mock in src/__tests__/handlePromptSubmit.test.ts now matches the new Promise<boolean> shape. - packages/builtin-tools/src/tools/RemoteTriggerTool/__tests__/ RemoteTriggerTool.test.ts: - Inline auth mock replaced with the shared tests/mocks/auth (added). - The full mock of src/constants/oauth.js is replaced by a narrow side-effect-only mock that overrides the env-reading helpers (getOauthConfig, fileSuffixForOauthConfig, MCP_CLIENT_METADATA_URL) and delegates pure data exports to the real module. - tests/integration/dependency-overrides.test.ts: - mermaid does not export `./package.json` in its exports map, so require.resolve('mermaid/package.json') throws ERR_PACKAGE_PATH_NOT_EXPORTED in runtimes that honor exports semantics. The test now resolves the package entry and walks up to the package root via a small findPackageJson helper. - readFileSync from node:fs is replaced with `await Bun.file(...).text()` to match the project's Bun-API requirement. Validation: - bun run typecheck (clean). - bun test → 3996 pass / 0 fail across 305 test files. Targets PRs: - amDosion/claude-code-bast#8 (fork-internal review) - claude-code-best/claude-code#386 (upstream review, same head branch)
This commit is contained in:
@@ -1,14 +1,43 @@
|
||||
import { describe, expect, test } from 'bun:test'
|
||||
import { mkdtempSync, readFileSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { mkdtempSync, rmSync, writeFileSync } from 'node:fs'
|
||||
import { createRequire } from 'node:module'
|
||||
import { tmpdir } from 'node:os'
|
||||
import { join, resolve } from 'node:path'
|
||||
import { dirname, join, resolve } from 'node:path'
|
||||
import { pathToFileURL } from 'node:url'
|
||||
|
||||
const repoRoot = resolve(import.meta.dir, '..', '..')
|
||||
const uuidV4Pattern =
|
||||
/^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/
|
||||
|
||||
async function findPackageJson(
|
||||
startPath: string,
|
||||
expectedName: string,
|
||||
): Promise<string> {
|
||||
let current = dirname(startPath)
|
||||
for (let depth = 0; depth < 10; depth++) {
|
||||
const candidate = join(current, 'package.json')
|
||||
const file = Bun.file(candidate)
|
||||
if (await file.exists()) {
|
||||
try {
|
||||
const parsed = JSON.parse(await file.text()) as { name?: unknown }
|
||||
if (parsed.name === expectedName) {
|
||||
return candidate
|
||||
}
|
||||
} catch {
|
||||
// ignore parse errors and keep walking up
|
||||
}
|
||||
}
|
||||
const parent = dirname(current)
|
||||
if (parent === current) {
|
||||
break
|
||||
}
|
||||
current = parent
|
||||
}
|
||||
throw new Error(
|
||||
`package.json with name "${expectedName}" not found above ${startPath}`,
|
||||
)
|
||||
}
|
||||
|
||||
describe('dependency security overrides', () => {
|
||||
test('mcpb can load patched inquirer prompts from its package context', async () => {
|
||||
const mcpbRequire = createRequire(import.meta.resolve('@anthropic-ai/mcpb'))
|
||||
@@ -28,10 +57,7 @@ describe('dependency security overrides', () => {
|
||||
)
|
||||
const gaxios = vertexRequire('gaxios') as {
|
||||
request(options: {
|
||||
adapter(options: {
|
||||
headers: Headers
|
||||
url: string
|
||||
}): Promise<{
|
||||
adapter(options: { headers: Headers; url: string }): Promise<{
|
||||
config: unknown
|
||||
data: string
|
||||
headers: Record<string, string>
|
||||
@@ -39,7 +65,7 @@ describe('dependency security overrides', () => {
|
||||
status: number
|
||||
statusText: string
|
||||
}>
|
||||
multipart: Array<{ body: string; headers: Record<string, string> }>
|
||||
multipart: Array<{ body: string; headers: Record<string, string> }>
|
||||
url: string
|
||||
}): Promise<{ status: number }>
|
||||
}
|
||||
@@ -47,8 +73,10 @@ describe('dependency security overrides', () => {
|
||||
|
||||
const response = await gaxios.request({
|
||||
url: 'https://example.com/upload',
|
||||
multipart: [{ body: 'payload', headers: { 'Content-Type': 'text/plain' } }],
|
||||
adapter: async (options) => {
|
||||
multipart: [
|
||||
{ body: 'payload', headers: { 'Content-Type': 'text/plain' } },
|
||||
],
|
||||
adapter: async options => {
|
||||
contentType = options.headers.get('content-type') ?? undefined
|
||||
return {
|
||||
config: options,
|
||||
@@ -62,14 +90,14 @@ describe('dependency security overrides', () => {
|
||||
})
|
||||
|
||||
expect(response.status).toBe(200)
|
||||
expect(contentType).toMatch(
|
||||
/^multipart\/related; boundary=[0-9a-f-]{36}$/,
|
||||
)
|
||||
expect(contentType).toMatch(/^multipart\/related; boundary=[0-9a-f-]{36}$/)
|
||||
expect(contentType?.split('boundary=')[1]).toMatch(uuidV4Pattern)
|
||||
})
|
||||
|
||||
test('azure identity msal guid generation works through its package context', () => {
|
||||
const identityRequire = createRequire(import.meta.resolve('@azure/identity'))
|
||||
const identityRequire = createRequire(
|
||||
import.meta.resolve('@azure/identity'),
|
||||
)
|
||||
const msal = identityRequire('@azure/msal-node') as {
|
||||
CryptoProvider: new () => { createNewGuid(): string }
|
||||
}
|
||||
@@ -91,11 +119,13 @@ describe('dependency security overrides', () => {
|
||||
pathToFileURL(streamdownRequire.resolve('uuid')).href
|
||||
)) as { v4(): string }
|
||||
const mermaidPath = streamdownRequire.resolve('mermaid')
|
||||
const mermaidPackagePath = streamdownRequire.resolve(
|
||||
'mermaid/package.json',
|
||||
)
|
||||
// mermaid does not export ./package.json in its exports map, so resolving
|
||||
// 'mermaid/package.json' throws ERR_PACKAGE_PATH_NOT_EXPORTED in runtimes
|
||||
// that honor exports semantics. Walk up from the resolved entry until a
|
||||
// package.json with name === 'mermaid' is found.
|
||||
const mermaidPackagePath = await findPackageJson(mermaidPath, 'mermaid')
|
||||
const mermaidPackage = JSON.parse(
|
||||
readFileSync(mermaidPackagePath, 'utf8'),
|
||||
await Bun.file(mermaidPackagePath).text(),
|
||||
) as {
|
||||
name?: unknown
|
||||
exports?: { '.'?: { import?: unknown } }
|
||||
|
||||
19
tests/mocks/auth.ts
Normal file
19
tests/mocks/auth.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Shared mock for `src/utils/auth.js`. Use it via:
|
||||
*
|
||||
* import { authMock } from '../../tests/mocks/auth'
|
||||
* mock.module('src/utils/auth.js', authMock)
|
||||
*
|
||||
* Tests that need different return values can override the helper used by
|
||||
* the suite (e.g. by extending this object and re-registering with mock.module).
|
||||
* Always extend here rather than inlining a different shape per test, so the
|
||||
* surface stays consistent when `auth.ts` exports change.
|
||||
*/
|
||||
export const authMock = () => ({
|
||||
checkAndRefreshOAuthTokenIfNeeded: async () => {},
|
||||
getClaudeAIOAuthTokens: () => ({ accessToken: 'token' }),
|
||||
isClaudeAISubscriber: () => true,
|
||||
isProSubscriber: () => false,
|
||||
isMaxSubscriber: () => false,
|
||||
isTeamSubscriber: () => false,
|
||||
})
|
||||
Reference in New Issue
Block a user