mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 05:45:51 +00:00
feat: 问就是封包
This commit is contained in:
@@ -1755,4 +1755,4 @@ export function getPromptId(): string | null {
|
||||
export function setPromptId(id: string | null): void {
|
||||
STATE.promptId = id
|
||||
}
|
||||
export type isReplBridgeActive = any;
|
||||
export function isReplBridgeActive(): boolean { return false; }
|
||||
|
||||
@@ -159,7 +159,7 @@ export async function authLogin({
|
||||
|
||||
const orgResult = await validateForceLoginOrg()
|
||||
if (!orgResult.valid) {
|
||||
process.stderr.write(orgResult.message + '\n')
|
||||
process.stderr.write((orgResult as { valid: false; message: string }).message + '\n')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
@@ -209,7 +209,7 @@ export async function authLogin({
|
||||
|
||||
const orgResult = await validateForceLoginOrg()
|
||||
if (!orgResult.valid) {
|
||||
process.stderr.write(orgResult.message + '\n')
|
||||
process.stderr.write((orgResult as { valid: false; message: string }).message + '\n')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
|
||||
@@ -178,9 +178,9 @@ export async function mcpListHandler(): Promise<void> {
|
||||
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
||||
console.log(`${name}: ${server.url} - ${status}`);
|
||||
} else if (!server.type || server.type === 'stdio') {
|
||||
const args = Array.isArray(server.args) ? server.args : [];
|
||||
const args = Array.isArray((server as any).args) ? (server as any).args : [];
|
||||
// biome-ignore lint/suspicious/noConsole:: intentional console output
|
||||
console.log(`${name}: ${server.command} ${args.join(' ')} - ${status}`);
|
||||
console.log(`${name}: ${(server as any).command} ${args.join(' ')} - ${status}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1243,7 +1243,7 @@ function runHeadlessStreaming(
|
||||
uuid: crumb.uuid,
|
||||
timestamp: crumb.timestamp,
|
||||
isReplay: true,
|
||||
} satisfies SDKUserMessageReplay)
|
||||
} as SDKUserMessageReplay)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1980,7 +1980,7 @@ function runHeadlessStreaming(
|
||||
parent_tool_use_id: null,
|
||||
uuid: c.uuid as string,
|
||||
isReplay: true,
|
||||
} satisfies SDKUserMessageReplay)
|
||||
} as SDKUserMessageReplay)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2265,8 +2265,8 @@ function runHeadlessStreaming(
|
||||
output.enqueue({
|
||||
type: 'system' as const,
|
||||
subtype: 'files_persisted' as const,
|
||||
files: result.persistedFiles,
|
||||
failed: result.failedFiles,
|
||||
files: (result as any).persistedFiles,
|
||||
failed: (result as any).failedFiles,
|
||||
processed_at: new Date().toISOString(),
|
||||
uuid: randomUUID(),
|
||||
session_id: getSessionId(),
|
||||
|
||||
@@ -375,7 +375,7 @@ export class CCRClient {
|
||||
if (!result.ok) {
|
||||
throw new RetryableError(
|
||||
'client event POST failed',
|
||||
result.retryAfterMs,
|
||||
(result as any).retryAfterMs,
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -398,7 +398,7 @@ export class CCRClient {
|
||||
if (!result.ok) {
|
||||
throw new RetryableError(
|
||||
'internal event POST failed',
|
||||
result.retryAfterMs,
|
||||
(result as any).retryAfterMs,
|
||||
)
|
||||
}
|
||||
},
|
||||
@@ -427,7 +427,7 @@ export class CCRClient {
|
||||
'delivery batch',
|
||||
)
|
||||
if (!result.ok) {
|
||||
throw new RetryableError('delivery POST failed', result.retryAfterMs)
|
||||
throw new RetryableError('delivery POST failed', (result as any).retryAfterMs)
|
||||
}
|
||||
},
|
||||
baseDelayMs: 500,
|
||||
|
||||
@@ -38,7 +38,7 @@ type TranscriptEntry = TranscriptMessage & {
|
||||
export function deriveFirstPrompt(
|
||||
firstUserMessage: Extract<SerializedMessage, { type: 'user' }> | undefined,
|
||||
): string {
|
||||
const content = firstUserMessage?.message?.content
|
||||
const content = (firstUserMessage as any)?.message?.content
|
||||
if (!content) return 'Branched conversation'
|
||||
const raw =
|
||||
typeof content === 'string'
|
||||
@@ -240,7 +240,7 @@ export async function call(
|
||||
// Build LogOption for resume
|
||||
const now = new Date()
|
||||
const firstPrompt = deriveFirstPrompt(
|
||||
serializedMessages.find(m => m.type === 'user'),
|
||||
serializedMessages.find(m => m.type === 'user') as Extract<SerializedMessage, { type: 'user' }> | undefined,
|
||||
)
|
||||
|
||||
// Save custom title - use provided title or firstPrompt as default
|
||||
|
||||
@@ -140,7 +140,7 @@ export function BrowseMarketplace({
|
||||
} of marketplaces_0) {
|
||||
if (marketplace) {
|
||||
// Count how many plugins from this marketplace are installed
|
||||
const installedFromThisMarketplace = count(marketplace.plugins, plugin => isPluginInstalled(createPluginId(plugin.name, name)));
|
||||
const installedFromThisMarketplace = count(marketplace.plugins, (plugin: any) => isPluginInstalled(createPluginId(plugin.name, name)));
|
||||
marketplaceInfos.push({
|
||||
name,
|
||||
totalPlugins: marketplace.plugins.length,
|
||||
@@ -334,7 +334,7 @@ export function BrowseMarketplace({
|
||||
failureCount++;
|
||||
newFailedPlugins.push({
|
||||
name: plugin_1.entry.name,
|
||||
reason: result.error
|
||||
reason: (result as { success: false; error: string }).error
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -397,7 +397,7 @@ export function BrowseMarketplace({
|
||||
});
|
||||
} else {
|
||||
setIsInstalling(false);
|
||||
setInstallError(result_0.error);
|
||||
setInstallError((result_0 as { success: false; error: string }).error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -248,7 +248,7 @@ export function DiscoverPlugins({
|
||||
failureCount++;
|
||||
newFailedPlugins.push({
|
||||
name: plugin_0.entry.name,
|
||||
reason: result.error
|
||||
reason: (result as { success: false; error: string }).error
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -306,7 +306,7 @@ export function DiscoverPlugins({
|
||||
});
|
||||
} else {
|
||||
setIsInstalling(false);
|
||||
setInstallError(result_0.error);
|
||||
setInstallError((result_0 as { success: false; error: string }).error);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -130,11 +130,12 @@ function Web({
|
||||
});
|
||||
const result = await importGithubToken(token);
|
||||
if (!result.ok) {
|
||||
const importErr = (result as { ok: false; error: ImportTokenError }).error;
|
||||
logEvent('tengu_remote_setup_result', {
|
||||
result: 'import_failed' as SafeString,
|
||||
error_kind: result.error.kind as SafeString
|
||||
error_kind: importErr.kind as SafeString
|
||||
});
|
||||
onDone(errorMessage(result.error, getCodeWebUrl()));
|
||||
onDone(errorMessage(importErr, getCodeWebUrl()));
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// Auto-generated type stub — replace with real implementation
|
||||
export type resetLimits = any;
|
||||
export type resetLimitsNonInteractive = any;
|
||||
// Auto-generated stub — replace with real implementation
|
||||
const stub = { isEnabled: () => false, isHidden: true, name: 'stub' };
|
||||
export const resetLimits = stub;
|
||||
export const resetLimitsNonInteractive = stub;
|
||||
|
||||
@@ -154,11 +154,12 @@ function ResumeCommand({
|
||||
}
|
||||
|
||||
// Different project - show command instead of resuming
|
||||
const raw = await setClipboard(crossProjectCheck.command);
|
||||
const crossCmd = (crossProjectCheck as { isCrossProject: true; isSameRepoWorktree: false; command: string }).command;
|
||||
const raw = await setClipboard(crossCmd);
|
||||
if (raw) process.stdout.write(raw);
|
||||
|
||||
// Format the output message
|
||||
const message = ['', 'This conversation is from a different directory.', '', 'To resume, run:', ` ${crossProjectCheck.command}`, '', '(Command copied to clipboard)', ''].join('\n');
|
||||
const message = ['', 'This conversation is from a different directory.', '', 'To resume, run:', ` ${crossCmd}`, '', '(Command copied to clipboard)', ''].join('\n');
|
||||
onDone(message, {
|
||||
display: 'user'
|
||||
});
|
||||
|
||||
@@ -136,7 +136,7 @@ export async function launchRemoteReview(
|
||||
// consume at session creation routes billing: first N zero-rate, then
|
||||
// anthropic:cccr org-service-key (overage-only).
|
||||
if (!eligibility.eligible) {
|
||||
const blockers = eligibility.errors.filter(
|
||||
const blockers = (eligibility as { eligible: false; errors: Array<{ type: string }> }).errors.filter(
|
||||
e => e.type !== 'no_remote_environment',
|
||||
)
|
||||
if (blockers.length > 0) {
|
||||
|
||||
@@ -314,11 +314,12 @@ async function launchDetached(opts: {
|
||||
const model = getUltraplanModel();
|
||||
const eligibility = await checkRemoteAgentEligibility();
|
||||
if (!eligibility.eligible) {
|
||||
const eligErrors = (eligibility as { eligible: false; errors: Array<{ type: string }> }).errors;
|
||||
logEvent('tengu_ultraplan_create_failed', {
|
||||
reason: 'precondition' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
precondition_errors: eligibility.errors.map(e => e.type).join(',') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
|
||||
precondition_errors: eligErrors.map(e => e.type).join(',') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS
|
||||
});
|
||||
const reasons = eligibility.errors.map(formatPreconditionError).join('\n');
|
||||
const reasons = eligErrors.map(formatPreconditionError).join('\n');
|
||||
enqueuePendingNotification({
|
||||
value: `ultraplan: cannot launch remote session —\n${reasons}`,
|
||||
mode: 'task-notification'
|
||||
|
||||
@@ -235,7 +235,7 @@ export function ConsoleOAuthFlow({
|
||||
await installOAuthTokens(result);
|
||||
const orgResult = await validateForceLoginOrg();
|
||||
if (!orgResult.valid) {
|
||||
throw new Error(orgResult.message);
|
||||
throw new Error((orgResult as { valid: false; message: string }).message);
|
||||
}
|
||||
setOAuthStatus({
|
||||
state: 'success'
|
||||
|
||||
@@ -59,8 +59,11 @@ type FeedbackData = {
|
||||
description: string;
|
||||
platform: string;
|
||||
gitRepo: boolean;
|
||||
terminal: string;
|
||||
version: string | null;
|
||||
transcript: Message[];
|
||||
errors: unknown;
|
||||
lastApiRequest: unknown;
|
||||
subagentTranscripts?: {
|
||||
[agentId: string]: Message[];
|
||||
};
|
||||
@@ -203,8 +206,8 @@ export function Feedback({
|
||||
...diskTranscripts,
|
||||
...teammateTranscripts
|
||||
};
|
||||
const reportData = {
|
||||
latestAssistantMessageId: lastAssistantMessageId,
|
||||
const reportData: FeedbackData = {
|
||||
latestAssistantMessageId: lastAssistantMessageId as string | null,
|
||||
message_count: messages.length,
|
||||
datetime: new Date().toISOString(),
|
||||
description,
|
||||
|
||||
@@ -50,7 +50,7 @@ export function FileEditToolDiff(props) {
|
||||
}
|
||||
return t2;
|
||||
}
|
||||
function DiffBody(t0) {
|
||||
function DiffBody(t0: { promise: Promise<DiffData>; file_path: string }) {
|
||||
const $ = _c(6);
|
||||
const {
|
||||
promise,
|
||||
|
||||
@@ -134,7 +134,7 @@ function Highlighted(t0) {
|
||||
} else {
|
||||
t1 = $[0];
|
||||
}
|
||||
const hl = use(t1);
|
||||
const hl = use(t1) as NonNullable<Awaited<ReturnType<typeof getCliHighlightPromise>>> | null;
|
||||
let t2;
|
||||
if ($[1] !== codeWithSpaces || $[2] !== hl || $[3] !== language) {
|
||||
bb0: {
|
||||
|
||||
@@ -129,7 +129,7 @@ function MarkdownBody(t0) {
|
||||
} = t0;
|
||||
const [theme] = useTheme();
|
||||
configureMarked();
|
||||
let elements;
|
||||
let elements: React.ReactNode[];
|
||||
if ($[0] !== children || $[1] !== dimColor || $[2] !== highlight || $[3] !== theme) {
|
||||
const tokens = cachedLexer(stripPromptXMLTags(children));
|
||||
elements = [];
|
||||
@@ -156,7 +156,7 @@ function MarkdownBody(t0) {
|
||||
$[3] = theme;
|
||||
$[4] = elements;
|
||||
} else {
|
||||
elements = $[4];
|
||||
elements = $[4] as React.ReactNode[];
|
||||
}
|
||||
const elements_0 = elements;
|
||||
let t1;
|
||||
|
||||
@@ -606,7 +606,7 @@ export function areMessagePropsEqual(prev: Props, next: Props): boolean {
|
||||
// Only re-render on lastThinkingBlockId change if this message actually
|
||||
// has thinking content — otherwise every message in scrollback re-renders
|
||||
// whenever streaming thinking starts/stops (CC-941).
|
||||
if (prev.lastThinkingBlockId !== next.lastThinkingBlockId && hasThinkingContent(next.message)) {
|
||||
if (prev.lastThinkingBlockId !== next.lastThinkingBlockId && hasThinkingContent(next.message as any)) {
|
||||
return false;
|
||||
}
|
||||
// Verbose toggle changes thinking block visibility/expansion
|
||||
|
||||
@@ -334,7 +334,7 @@ export function MessageSelector({
|
||||
<Box flexDirection="column" paddingLeft={1} borderStyle="single" borderRight={false} borderTop={false} borderBottom={false} borderLeft={true} borderLeftDimColor>
|
||||
<UserMessageOption userMessage={messageToRestore} color="text" isCurrent={false} />
|
||||
<Text dimColor>
|
||||
({formatRelativeTimeAgo(new Date(messageToRestore.timestamp))})
|
||||
({formatRelativeTimeAgo(new Date(messageToRestore.timestamp as number))})
|
||||
</Text>
|
||||
</Box>
|
||||
<RestoreOptionDescription selectedRestoreOption={selectedRestoreOption} canRestoreCode={!!canRestoreCode_0} diffStatsForRestore={diffStatsForRestore} />
|
||||
|
||||
@@ -95,7 +95,8 @@ export function Settings(t0) {
|
||||
}
|
||||
let t7;
|
||||
if ($[13] !== contentHeight) {
|
||||
t7 = false ? [<Tab key="gates" title="Gates"><Gates onOwnsEscChange={setGatesOwnsEsc} contentHeight={contentHeight} /></Tab>] : [];
|
||||
const GatesComponent = Gates as any;
|
||||
t7 = false ? [<Tab key="gates" title="Gates"><GatesComponent onOwnsEscChange={setGatesOwnsEsc} contentHeight={contentHeight} /></Tab>] : [];
|
||||
$[13] = contentHeight;
|
||||
$[14] = t7;
|
||||
} else {
|
||||
|
||||
@@ -206,7 +206,7 @@ function Diagnostics(t0) {
|
||||
const {
|
||||
promise
|
||||
} = t0;
|
||||
const diagnostics = use(promise);
|
||||
const diagnostics = use(promise) as any[];
|
||||
if (diagnostics.length === 0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -272,10 +272,10 @@ export function GlimmerMessage(t0) {
|
||||
$[57] = shim;
|
||||
$[58] = colPos;
|
||||
} else {
|
||||
before = $[55];
|
||||
after = $[56];
|
||||
shim = $[57];
|
||||
colPos = $[58];
|
||||
before = $[55] as string;
|
||||
after = $[56] as string;
|
||||
shim = $[57] as string;
|
||||
colPos = $[58] as number;
|
||||
}
|
||||
let t3;
|
||||
if ($[59] !== before || $[60] !== messageColor) {
|
||||
|
||||
@@ -31,7 +31,7 @@ export function StatusNotices(t0) {
|
||||
const context = {
|
||||
config: t1,
|
||||
agentDefinitions,
|
||||
memoryFiles: use(t2)
|
||||
memoryFiles: use(t2) as any
|
||||
};
|
||||
const activeNotices = getActiveNotices(context);
|
||||
if (activeNotices.length === 0) {
|
||||
|
||||
@@ -45,9 +45,9 @@ export default function TextInput(props: Props): React.ReactNode {
|
||||
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
|
||||
useVoiceState(s => s.voiceState) : 'idle' as const;
|
||||
const isVoiceRecording = voiceState === 'recording';
|
||||
const audioLevels = feature('VOICE_MODE') ?
|
||||
const audioLevels = (feature('VOICE_MODE') ?
|
||||
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
|
||||
useVoiceState(s_0 => s_0.voiceAudioLevels) : [];
|
||||
useVoiceState(s_0 => s_0.voiceAudioLevels) : []) as number[];
|
||||
const smoothedRef = useRef<number[]>(new Array(CURSOR_WAVEFORM_WIDTH).fill(0));
|
||||
const needsAnimation = isVoiceRecording && !reducedMotion;
|
||||
const [animRef, animTime] = feature('VOICE_MODE') ?
|
||||
|
||||
@@ -72,7 +72,7 @@ export function ThemePicker(t0) {
|
||||
} = usePreviewTheme();
|
||||
const syntaxHighlightingDisabled = useAppState(_temp) ?? false;
|
||||
const setAppState = useSetAppState();
|
||||
useRegisterKeybindingContext("ThemePicker");
|
||||
useRegisterKeybindingContext("ThemePicker", undefined);
|
||||
const syntaxToggleShortcut = useShortcutDisplay("theme:toggleSyntaxHighlighting", "ThemePicker", "ctrl+t");
|
||||
let t8;
|
||||
if ($[3] !== setAppState || $[4] !== syntaxHighlightingDisabled) {
|
||||
|
||||
@@ -16,7 +16,7 @@ const HEADROOM = 3;
|
||||
import { logForDebugging } from '../utils/debug.js';
|
||||
import { sleep } from '../utils/sleep.js';
|
||||
import { renderableSearchText } from '../utils/transcriptSearch.js';
|
||||
import { isNavigableMessage, type MessageActionsNav, type MessageActionsState, type NavigableMessage, stripSystemReminders, toolCallOf } from './messageActions.js';
|
||||
import { isNavigableMessage, type MessageActionsNav, type MessageActionsState, type NavigableMessage, type NavigableType, stripSystemReminders, toolCallOf } from './messageActions.js';
|
||||
|
||||
// Fallback extractor: lower + cache here for callers without the
|
||||
// Messages.tsx tool-lookup path (tests, static contexts). Messages.tsx
|
||||
@@ -151,7 +151,7 @@ function computeStickyPromptText(msg: RenderableMessage): string | null {
|
||||
raw = block.text;
|
||||
} else if (msg.type === 'attachment' && msg.attachment.type === 'queued_command' && msg.attachment.commandMode !== 'task-notification' && !msg.attachment.isMeta) {
|
||||
const p = msg.attachment.prompt;
|
||||
raw = typeof p === 'string' ? p : p.flatMap(b => b.type === 'text' ? [b.text] : []).join('\n');
|
||||
raw = typeof p === 'string' ? p : (p as any[]).flatMap(b => b.type === 'text' ? [b.text] : []).join('\n');
|
||||
}
|
||||
if (raw === null) return null;
|
||||
const t = stripSystemReminders(raw);
|
||||
@@ -345,7 +345,7 @@ export function VirtualMessageList({
|
||||
useImperativeHandle(cursorNavRef, (): MessageActionsNav => {
|
||||
const select = (m: NavigableMessage) => setCursor?.({
|
||||
uuid: m.uuid,
|
||||
msgType: m.type,
|
||||
msgType: m.type as NavigableType,
|
||||
expanded: false,
|
||||
toolName: toolCallOf(m)?.name
|
||||
});
|
||||
|
||||
@@ -251,7 +251,7 @@ export function ToolSelector(t0) {
|
||||
let t9;
|
||||
if ($[22] !== selectedSet) {
|
||||
t9 = bucketTools => {
|
||||
const selected = count(bucketTools, t_5 => selectedSet.has(t_5.name));
|
||||
const selected = count(bucketTools, (t_5: any) => selectedSet.has(t_5.name));
|
||||
const needsSelection = selected < bucketTools.length;
|
||||
return () => {
|
||||
const toolNames_1 = bucketTools.map(_temp4);
|
||||
@@ -321,7 +321,7 @@ export function ToolSelector(t0) {
|
||||
if (bucketTools_0.length === 0) {
|
||||
return;
|
||||
}
|
||||
const selected_0 = count(bucketTools_0, t_8 => selectedSet.has(t_8.name));
|
||||
const selected_0 = count(bucketTools_0, (t_8: any) => selectedSet.has(t_8.name));
|
||||
const isFullySelected = selected_0 === bucketTools_0.length;
|
||||
navigableItems.push({
|
||||
id,
|
||||
|
||||
@@ -47,7 +47,7 @@ export function MemoryFileSelector(t0) {
|
||||
onSelect,
|
||||
onCancel
|
||||
} = t0;
|
||||
const existingMemoryFiles = use(getMemoryFiles());
|
||||
const existingMemoryFiles = use(getMemoryFiles()) as MemoryFileInfo[];
|
||||
const userMemoryPath = join(getClaudeConfigHomeDir(), "CLAUDE.md");
|
||||
const projectMemoryPath = join(getOriginalCwd(), "CLAUDE.md");
|
||||
const hasUserMemory = existingMemoryFiles.some(f => f.path === userMemoryPath);
|
||||
|
||||
@@ -337,7 +337,7 @@ function renderToolUseProgressMessage(tool: Tool, tools: Tools, lookups: ReturnT
|
||||
columns: number;
|
||||
rows: number;
|
||||
}): React.ReactNode {
|
||||
const toolProgressMessages = progressMessagesForMessage.filter((msg): msg is ProgressMessage<ToolProgressData> => msg.data.type !== 'hook_progress');
|
||||
const toolProgressMessages = progressMessagesForMessage.filter((msg): msg is ProgressMessage<ToolProgressData> => (msg.data as { type?: string }).type !== 'hook_progress');
|
||||
try {
|
||||
const toolMessages = tool.renderToolUseProgressMessage?.(toolProgressMessages, {
|
||||
tools,
|
||||
|
||||
@@ -40,8 +40,6 @@ const NULL_RENDERING_TYPES = [
|
||||
'auto_mode',
|
||||
'auto_mode_exit',
|
||||
'output_token_usage',
|
||||
'pen_mode_enter',
|
||||
'pen_mode_exit',
|
||||
'verify_plan_reminder',
|
||||
'current_session_memory',
|
||||
'compaction_reminder',
|
||||
@@ -65,6 +63,6 @@ export function isNullRenderingAttachment(
|
||||
): boolean {
|
||||
return (
|
||||
msg.type === 'attachment' &&
|
||||
NULL_RENDERING_ATTACHMENT_TYPES.has(msg.attachment.type)
|
||||
NULL_RENDERING_ATTACHMENT_TYPES.has(msg.attachment.type as Attachment['type'])
|
||||
)
|
||||
}
|
||||
|
||||
@@ -140,7 +140,7 @@ function AskUserQuestionPermissionRequestBody(t0) {
|
||||
$[10] = theme;
|
||||
$[11] = maxHeight;
|
||||
} else {
|
||||
maxHeight = $[11];
|
||||
maxHeight = $[11] as number;
|
||||
}
|
||||
const t3 = Math.min(Math.max(maxHeight, MIN_CONTENT_HEIGHT), maxAllowedHeight);
|
||||
const t4 = Math.max(maxWidth, MIN_CONTENT_WIDTH);
|
||||
@@ -177,7 +177,7 @@ function AskUserQuestionPermissionRequestBody(t0) {
|
||||
const pasteId = nextPasteIdRef.current;
|
||||
const newContent = {
|
||||
id: pasteId,
|
||||
type: "image",
|
||||
type: "image" as const,
|
||||
content: base64Image,
|
||||
mediaType: mediaType || "image/png",
|
||||
filename: filename || "Pasted image",
|
||||
|
||||
@@ -151,7 +151,7 @@ export function ExitPlanModePermissionRequest({
|
||||
const options = useMemo(() => buildPlanApprovalOptions({
|
||||
showClearContext,
|
||||
showUltraplan,
|
||||
usedPercent: showClearContext ? getContextUsedPercent(usage, mode) : null,
|
||||
usedPercent: showClearContext ? getContextUsedPercent(usage as any, mode) : null,
|
||||
isAutoModeAvailable,
|
||||
isBypassPermissionsModeAvailable,
|
||||
onFeedbackChange: setPlanFeedback
|
||||
|
||||
@@ -62,7 +62,7 @@ function PermissionDecisionInfoItem(t0) {
|
||||
return <Box flexDirection="column">{Array.from(decisionReason.reasons.entries()).map(t2 => {
|
||||
const [subcommand, result] = t2 as [string, { behavior: string; decisionReason?: { type: string }; suggestions?: unknown }];
|
||||
const icon = result.behavior === "allow" ? color("success", theme)(figures.tick) : color("error", theme)(figures.cross);
|
||||
return <Box flexDirection="column" key={subcommand}><Text>{icon} {subcommand}</Text>{result.decisionReason !== undefined && result.decisionReason.type !== "subcommandResults" && <Text><Text dimColor={true}>{" "}⎿{" "}</Text><Ansi>{decisionReasonDisplayString(result.decisionReason)}</Ansi></Text>}{result.behavior === "ask" && <SuggestedRules suggestions={result.suggestions} />}</Box>;
|
||||
return <Box flexDirection="column" key={subcommand}><Text>{icon} {subcommand}</Text>{result.decisionReason !== undefined && result.decisionReason.type !== "subcommandResults" && <Text><Text dimColor={true}>{" "}⎿{" "}</Text><Ansi>{decisionReasonDisplayString(result.decisionReason as any)}</Ansi></Text>}{result.behavior === "ask" && <SuggestedRules suggestions={result.suggestions} />}</Box>;
|
||||
})}</Box>;
|
||||
}
|
||||
default:
|
||||
|
||||
@@ -102,7 +102,7 @@ function SedEditPermissionRequestInner(t0) {
|
||||
const {
|
||||
oldContent,
|
||||
fileExists
|
||||
} = use(contentPromise);
|
||||
} = use(contentPromise) as any;
|
||||
let t1;
|
||||
if ($[4] !== oldContent || $[5] !== sedInfo) {
|
||||
t1 = applySedSubstitution(oldContent, sedInfo);
|
||||
|
||||
@@ -310,7 +310,7 @@ function ShellOutputContent(t0) {
|
||||
const {
|
||||
content,
|
||||
bytesTotal
|
||||
} = use(outputPromise);
|
||||
} = use(outputPromise) as any;
|
||||
if (!content) {
|
||||
let t1;
|
||||
if ($[0] === Symbol.for("react.memo_cache_sentinel")) {
|
||||
|
||||
@@ -132,11 +132,11 @@ function useCanUseTool(setToolUseConfirmQueue, setToolPermissionContext) {
|
||||
if (ctx.resolveIfAborted(resolve)) {
|
||||
return;
|
||||
}
|
||||
if (raceResult.type === "result" && raceResult.result.matches && raceResult.result.confidence === "high" && feature("BASH_CLASSIFIER")) {
|
||||
if ((raceResult as any).type === "result" && (raceResult as any).result.matches && (raceResult as any).result.confidence === "high" && feature("BASH_CLASSIFIER")) {
|
||||
consumeSpeculativeClassifierCheck((input as {
|
||||
command: string;
|
||||
}).command);
|
||||
const matchedRule = raceResult.result.matchedDescription ?? undefined;
|
||||
const matchedRule = (raceResult as any).result.matchedDescription ?? undefined;
|
||||
if (matchedRule) {
|
||||
setClassifierApproval(toolUseID, matchedRule);
|
||||
}
|
||||
@@ -150,7 +150,7 @@ function useCanUseTool(setToolUseConfirmQueue, setToolPermissionContext) {
|
||||
decisionReason: {
|
||||
type: "classifier" as const,
|
||||
classifier: "bash_allow" as const,
|
||||
reason: `Allowed by prompt rule: "${raceResult.result.matchedDescription}"`
|
||||
reason: `Allowed by prompt rule: "${(raceResult as any).result.matchedDescription}"`
|
||||
}
|
||||
}));
|
||||
return;
|
||||
|
||||
@@ -370,7 +370,7 @@ export function useReplBridge(messages: Message[], setMessages: (action: React.S
|
||||
|
||||
// Dispatch incoming control_response messages to registered handlers
|
||||
function handlePermissionResponse(msg_0: SDKControlResponse): void {
|
||||
const requestId = msg_0.response?.request_id;
|
||||
const requestId = (msg_0 as any).response?.request_id;
|
||||
if (!requestId) return;
|
||||
const handler = pendingPermissionHandlers.get(requestId);
|
||||
if (!handler) {
|
||||
@@ -379,7 +379,7 @@ export function useReplBridge(messages: Message[], setMessages: (action: React.S
|
||||
}
|
||||
pendingPermissionHandlers.delete(requestId);
|
||||
// Extract the permission decision from the control_response payload
|
||||
const inner = msg_0.response;
|
||||
const inner = (msg_0 as any).response;
|
||||
if (inner.subtype === 'success' && inner.response && isBridgePermissionResponse(inner.response)) {
|
||||
handler(inner.response);
|
||||
}
|
||||
|
||||
@@ -225,9 +225,9 @@ export function useVoiceIntegration({
|
||||
const voiceState = feature('VOICE_MODE') ?
|
||||
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
|
||||
useVoiceState(s => s.voiceState) : 'idle' as const;
|
||||
const voiceInterimTranscript = feature('VOICE_MODE') ?
|
||||
const voiceInterimTranscript: string = feature('VOICE_MODE') ?
|
||||
// biome-ignore lint/correctness/useHookAtTopLevel: feature() is a compile-time constant
|
||||
useVoiceState(s_0 => s_0.voiceInterimTranscript) : '';
|
||||
useVoiceState(s_0 => s_0.voiceInterimTranscript) as string : '';
|
||||
|
||||
// Set the voice anchor for focus mode (where recording starts via terminal
|
||||
// focus, not key hold). Key-hold sets the anchor in stripTrailing.
|
||||
|
||||
@@ -29,7 +29,7 @@ type SpanProps = {
|
||||
*
|
||||
* Memoized to prevent re-renders when parent changes but children string is the same.
|
||||
*/
|
||||
export const Ansi = React.memo(function Ansi(t0) {
|
||||
export const Ansi = React.memo(function Ansi(t0: { children: React.ReactNode; dimColor?: boolean }) {
|
||||
const $ = _c(12);
|
||||
const {
|
||||
children,
|
||||
|
||||
@@ -159,7 +159,7 @@ export async function getAnthropicClient({
|
||||
? process.env.ANTHROPIC_SMALL_FAST_MODEL_AWS_REGION
|
||||
: getAWSRegion()
|
||||
|
||||
const bedrockArgs: ConstructorParameters<typeof AnthropicBedrock>[0] = {
|
||||
const bedrockArgs: any = {
|
||||
...ARGS,
|
||||
awsRegion,
|
||||
...(isEnvTruthy(process.env.CLAUDE_CODE_SKIP_BEDROCK_AUTH) && {
|
||||
@@ -290,7 +290,7 @@ export async function getAnthropicClient({
|
||||
const vertexArgs: ConstructorParameters<typeof AnthropicVertex>[0] = {
|
||||
...ARGS,
|
||||
region: getVertexRegionForModel(model),
|
||||
googleAuth,
|
||||
googleAuth: googleAuth as any,
|
||||
...(isDebugToStdErr() && { logger: createStderrLogger() }),
|
||||
}
|
||||
// we have always been lying about the return type - this doesn't support batching or models
|
||||
|
||||
@@ -108,7 +108,7 @@ export function getPromptTooLongTokenGap(
|
||||
return undefined
|
||||
}
|
||||
const { actualTokens, limitTokens } = parsePromptTooLongTokenCounts(
|
||||
msg.errorDetails,
|
||||
msg.errorDetails as string,
|
||||
)
|
||||
if (actualTokens === undefined || limitTokens === undefined) {
|
||||
return undefined
|
||||
@@ -148,7 +148,7 @@ export function isMediaSizeErrorMessage(msg: AssistantMessage): boolean {
|
||||
return (
|
||||
msg.isApiErrorMessage === true &&
|
||||
msg.errorDetails !== undefined &&
|
||||
isMediaSizeError(msg.errorDetails)
|
||||
isMediaSizeError(msg.errorDetails as string)
|
||||
)
|
||||
}
|
||||
export const CREDIT_BALANCE_TOO_LOW_ERROR_MESSAGE = 'Credit balance is too low'
|
||||
|
||||
@@ -1279,7 +1279,7 @@ export async function getAllMcpConfigs(): Promise<{
|
||||
// Keys never collide (`slack` vs `claude.ai Slack`) so the merge below
|
||||
// won't catch this — need content-based dedup by URL signature.
|
||||
const { servers: dedupedClaudeAi } = dedupClaudeAiMcpServers(
|
||||
claudeaiMcpServers,
|
||||
claudeaiMcpServers as Record<string, ScopedMcpServerConfig>,
|
||||
claudeCodeServers,
|
||||
)
|
||||
|
||||
@@ -1351,6 +1351,7 @@ export function parseMcpConfig(params: {
|
||||
if (
|
||||
getPlatform() === 'windows' &&
|
||||
(!configToCheck.type || configToCheck.type === 'stdio') &&
|
||||
('command' in configToCheck) &&
|
||||
(configToCheck.command === 'npx' ||
|
||||
configToCheck.command.endsWith('\\npx') ||
|
||||
configToCheck.command.endsWith('/npx'))
|
||||
|
||||
@@ -99,7 +99,7 @@ export async function* runPostToolUseHooks<Input extends AnyObject, Output>(
|
||||
result.message.attachment.type === 'hook_blocking_error'
|
||||
)
|
||||
) {
|
||||
yield { message: result.message }
|
||||
yield { message: result.message as AttachmentMessage | ProgressMessage<HookProgress> }
|
||||
}
|
||||
|
||||
if (result.blockingError) {
|
||||
@@ -251,7 +251,7 @@ export async function* runPostToolUseFailureHooks<Input extends AnyObject>(
|
||||
result.message.attachment.type === 'hook_blocking_error'
|
||||
)
|
||||
) {
|
||||
yield { message: result.message }
|
||||
yield { message: result.message as AttachmentMessage | ProgressMessage<HookProgress> }
|
||||
}
|
||||
|
||||
if (result.blockingError) {
|
||||
@@ -476,7 +476,7 @@ export async function* runPreToolUseHooks(
|
||||
)) {
|
||||
try {
|
||||
if (result.message) {
|
||||
yield { type: 'message', message: { message: result.message } }
|
||||
yield { type: 'message', message: { message: result.message as AttachmentMessage | ProgressMessage<HookProgress> } }
|
||||
}
|
||||
if (result.blockingError) {
|
||||
const denialMessage = getPreToolHookBlockingMessage(
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { BetaContentBlock } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
|
||||
import type { BetaContentBlock, BetaUsage } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
|
||||
import { createHash, randomUUID, type UUID } from 'crypto'
|
||||
import { mkdir, readFile, writeFile } from 'fs/promises'
|
||||
import isPlainObject from 'lodash-es/isPlainObject.js'
|
||||
@@ -166,8 +166,8 @@ function addCachedCostToTotalSessionCost(
|
||||
if (message.type === 'stream_event') {
|
||||
return
|
||||
}
|
||||
const model = message.message.model
|
||||
const usage = message.message.usage
|
||||
const model = (message as AssistantMessage).message.model as string
|
||||
const usage = (message as AssistantMessage).message.usage as BetaUsage
|
||||
const costUSD = calculateUSDCost(model, usage)
|
||||
addToTotalSessionCost(costUSD, usage, model)
|
||||
}
|
||||
@@ -251,7 +251,7 @@ function mapAssistantMessage(
|
||||
timestamp: message.timestamp,
|
||||
message: {
|
||||
...message.message,
|
||||
content: message.message.content
|
||||
content: (message.message.content as BetaContentBlock[])
|
||||
.map(_ => {
|
||||
switch (_.type) {
|
||||
case 'text':
|
||||
@@ -269,7 +269,7 @@ function mapAssistantMessage(
|
||||
return _ // Handle other block types unchanged
|
||||
}
|
||||
})
|
||||
.filter(Boolean) as BetaContentBlock[],
|
||||
.filter(Boolean) as any,
|
||||
},
|
||||
type: 'assistant',
|
||||
}
|
||||
@@ -282,7 +282,7 @@ function mapMessage(
|
||||
uuid?: UUID,
|
||||
): AssistantMessage | SystemAPIErrorMessage | StreamEvent {
|
||||
if (message.type === 'assistant') {
|
||||
return mapAssistantMessage(message, f, index, uuid)
|
||||
return mapAssistantMessage(message as AssistantMessage, f, index, uuid)
|
||||
} else {
|
||||
return message
|
||||
}
|
||||
|
||||
@@ -107,7 +107,7 @@ function enqueueShellNotification(taskId: string, description: string, status: '
|
||||
// If the task was already marked as notified (e.g., by TaskStopTool), skip
|
||||
// enqueueing to avoid sending redundant messages to the model.
|
||||
let shouldEnqueue = false;
|
||||
updateTaskState(taskId, setAppState, task => {
|
||||
updateTaskState<LocalShellTaskState>(taskId, setAppState, task => {
|
||||
if (task.notified) {
|
||||
return task;
|
||||
}
|
||||
@@ -479,7 +479,7 @@ export function backgroundExistingForegroundTask(taskId: string, shellCommand: S
|
||||
* carries the full output, so the <task_notification> would be redundant.
|
||||
*/
|
||||
export function markTaskNotified(taskId: string, setAppState: SetAppState): void {
|
||||
updateTaskState(taskId, setAppState, t => t.notified ? t : {
|
||||
updateTaskState<LocalShellTaskState>(taskId, setAppState, t => t.notified ? t : {
|
||||
...t,
|
||||
notified: true
|
||||
});
|
||||
|
||||
@@ -760,17 +760,17 @@ export async function* runAgent({
|
||||
// so TTFT/OTPS update during subagent execution.
|
||||
if (
|
||||
message.type === 'stream_event' &&
|
||||
message.event.type === 'message_start' &&
|
||||
message.ttftMs != null
|
||||
(message as any).event.type === 'message_start' &&
|
||||
(message as any).ttftMs != null
|
||||
) {
|
||||
toolUseContext.pushApiMetricsEntry?.(message.ttftMs)
|
||||
toolUseContext.pushApiMetricsEntry?.((message as any).ttftMs)
|
||||
continue
|
||||
}
|
||||
|
||||
// Yield attachment messages (e.g., structured_output) without recording them
|
||||
if (message.type === 'attachment') {
|
||||
// Handle max turns reached signal from query.ts
|
||||
if (message.attachment.type === 'max_turns_reached') {
|
||||
if ((message as any).attachment.type === 'max_turns_reached') {
|
||||
logForDebugging(
|
||||
`[Agent
|
||||
: $
|
||||
@@ -779,13 +779,13 @@ export async function* runAgent({
|
||||
}
|
||||
] Reached max turns limit ($
|
||||
{
|
||||
message.attachment.maxTurns
|
||||
(message as any).attachment.maxTurns
|
||||
}
|
||||
)`,
|
||||
)
|
||||
break
|
||||
}
|
||||
yield message
|
||||
yield message as Message
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
@@ -222,7 +222,7 @@ function EditRejectionBody(t0) {
|
||||
patch,
|
||||
firstLine,
|
||||
fileContent
|
||||
} = use(promise);
|
||||
} = use(promise) as any;
|
||||
let t1;
|
||||
if ($[0] !== fileContent || $[1] !== filePath || $[2] !== firstLine || $[3] !== patch || $[4] !== style || $[5] !== verbose) {
|
||||
t1 = <FileEditToolUseRejectedMessage file_path={filePath} operation="update" patch={patch} firstLine={firstLine} fileContent={fileContent} style={style} verbose={verbose} />;
|
||||
|
||||
@@ -899,11 +899,11 @@ async function callInner(
|
||||
parsedRange ?? undefined,
|
||||
)
|
||||
if (!extractResult.success) {
|
||||
throw new Error(extractResult.error.message)
|
||||
throw new Error((extractResult as any).error.message)
|
||||
}
|
||||
logEvent('tengu_pdf_page_extraction', {
|
||||
success: true,
|
||||
pageCount: extractResult.data.file.count,
|
||||
pageCount: (extractResult as any).data.file.count,
|
||||
fileSize: extractResult.data.file.originalSize,
|
||||
hasPageRange: true,
|
||||
})
|
||||
@@ -970,7 +970,7 @@ async function callInner(
|
||||
} else {
|
||||
logEvent('tengu_pdf_page_extraction', {
|
||||
success: false,
|
||||
available: extractResult.error.reason !== 'unavailable',
|
||||
available: (extractResult as any).error.reason !== 'unavailable',
|
||||
fileSize: stats.size,
|
||||
})
|
||||
}
|
||||
@@ -986,7 +986,7 @@ async function callInner(
|
||||
|
||||
const readResult = await readPDF(resolvedFilePath)
|
||||
if (!readResult.success) {
|
||||
throw new Error(readResult.error.message)
|
||||
throw new Error((readResult as any).error.message)
|
||||
}
|
||||
const pdfData = readResult.data
|
||||
logFileOperation({
|
||||
@@ -1158,12 +1158,12 @@ export async function readImageWithTokenBudget(
|
||||
const sharpModule = await import('sharp')
|
||||
const sharp =
|
||||
(
|
||||
sharpModule as {
|
||||
sharpModule as unknown as {
|
||||
default?: typeof sharpModule
|
||||
} & typeof sharpModule
|
||||
).default || sharpModule
|
||||
|
||||
const fallbackBuffer = await sharp(imageBuffer)
|
||||
const fallbackBuffer = await (sharp as any)(imageBuffer)
|
||||
.resize(400, 400, {
|
||||
fit: 'inside',
|
||||
withoutEnlargement: true,
|
||||
|
||||
@@ -826,7 +826,7 @@ export const SendMessageTool: Tool<InputSchema, SendMessageToolOutput> =
|
||||
prompt: input.message,
|
||||
toolUseContext: context,
|
||||
canUseTool,
|
||||
invokingRequestId: assistantMessage?.requestId,
|
||||
invokingRequestId: assistantMessage?.requestId as string | undefined,
|
||||
})
|
||||
return {
|
||||
data: {
|
||||
@@ -853,7 +853,7 @@ export const SendMessageTool: Tool<InputSchema, SendMessageToolOutput> =
|
||||
prompt: input.message,
|
||||
toolUseContext: context,
|
||||
canUseTool,
|
||||
invokingRequestId: assistantMessage?.requestId,
|
||||
invokingRequestId: assistantMessage?.requestId as string | undefined,
|
||||
})
|
||||
return {
|
||||
data: {
|
||||
|
||||
11
src/types/global.d.ts
vendored
11
src/types/global.d.ts
vendored
@@ -67,6 +67,17 @@ declare const BUILD_TARGET: string
|
||||
declare const BUILD_ENV: string
|
||||
declare const INTERFACE_TYPE: string
|
||||
|
||||
// ============================================================================
|
||||
// Ink custom JSX intrinsic elements — used by the internal Ink framework
|
||||
declare namespace JSX {
|
||||
interface IntrinsicElements {
|
||||
'ink-box': any;
|
||||
'ink-text': any;
|
||||
'ink-link': any;
|
||||
'ink-raw-ansi': any;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Bun text/file loaders — allow importing non-TS assets as strings
|
||||
declare module '*.md' {
|
||||
|
||||
@@ -262,7 +262,7 @@ export async function startNodeRelay(
|
||||
},
|
||||
end: () => sock.end(),
|
||||
}
|
||||
sock.on('data', data =>
|
||||
sock.on('data', (data: Buffer) =>
|
||||
handleData(adapter, st, data, wsUrl, authHeader, wsAuthHeader),
|
||||
)
|
||||
sock.on('close', () => cleanupConn(states.get(sock)))
|
||||
@@ -381,7 +381,7 @@ function openTunnel(
|
||||
// responds with its own "HTTP/1.1 200" over the tunnel; we just pipe it.
|
||||
const head =
|
||||
`${connectLine}\r\n` + `Proxy-Authorization: ${authHeader}\r\n` + `\r\n`
|
||||
ws.send(encodeChunk(Buffer.from(head, 'utf8')))
|
||||
ws.send(encodeChunk(new Uint8Array(Buffer.from(head, 'utf8'))) as any)
|
||||
// Flush anything that arrived while the WS handshake was in flight —
|
||||
// trailing bytes from the CONNECT packet and any data() callbacks that
|
||||
// fired before onopen.
|
||||
@@ -429,15 +429,15 @@ function openTunnel(
|
||||
|
||||
function sendKeepalive(ws: WebSocketLike): void {
|
||||
if (ws.readyState === WebSocket.OPEN) {
|
||||
ws.send(encodeChunk(new Uint8Array(0)))
|
||||
ws.send(encodeChunk(new Uint8Array(0)) as any)
|
||||
}
|
||||
}
|
||||
|
||||
function forwardToWs(ws: WebSocketLike, data: Buffer): void {
|
||||
if (ws.readyState !== WebSocket.OPEN) return
|
||||
for (let off = 0; off < data.length; off += MAX_CHUNK_BYTES) {
|
||||
const slice = data.subarray(off, off + MAX_CHUNK_BYTES)
|
||||
ws.send(encodeChunk(slice))
|
||||
const slice = new Uint8Array(data.subarray(off, off + MAX_CHUNK_BYTES))
|
||||
ws.send(encodeChunk(slice) as any)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -553,8 +553,8 @@ export function buildMissedTaskNotification(missed: CronTask[]): string {
|
||||
// Use a fence one longer than any backtick run in the prompt so a
|
||||
// prompt containing ``` cannot close the fence early and un-wrap the
|
||||
// trailing text (CommonMark fence-matching rule).
|
||||
const longestRun = (t.prompt.match(/`+/g) ?? []).reduce(
|
||||
(max, run) => Math.max(max, run.length),
|
||||
const longestRun = (t.prompt.match(/`+/g) ?? ([] as string[])).reduce(
|
||||
(max: number, run: string) => Math.max(max, run.length),
|
||||
0,
|
||||
)
|
||||
const fence = '`'.repeat(Math.max(3, longestRun + 1))
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { McpbManifest } from '@anthropic-ai/mcpb'
|
||||
import type { McpbManifestAny } from '@anthropic-ai/mcpb'
|
||||
import { errorMessage } from '../errors.js'
|
||||
import { jsonParse } from '../slowOperations.js'
|
||||
|
||||
@@ -12,15 +12,15 @@ import { jsonParse } from '../slowOperations.js'
|
||||
*/
|
||||
export async function validateManifest(
|
||||
manifestJson: unknown,
|
||||
): Promise<McpbManifest> {
|
||||
const { McpbManifestSchema } = await import('@anthropic-ai/mcpb')
|
||||
const parseResult = McpbManifestSchema.safeParse(manifestJson)
|
||||
): Promise<McpbManifestAny> {
|
||||
const { vAny } = await import('@anthropic-ai/mcpb')
|
||||
const parseResult = vAny.McpbManifestSchema.safeParse(manifestJson)
|
||||
|
||||
if (!parseResult.success) {
|
||||
const errors = parseResult.error.flatten()
|
||||
const errorMessages = [
|
||||
...Object.entries(errors.fieldErrors).map(
|
||||
([field, errs]) => `${field}: ${errs?.join(', ')}`,
|
||||
([field, errs]) => `${field}: ${(errs as any)?.join(', ')}`,
|
||||
),
|
||||
...(errors.formErrors || []),
|
||||
]
|
||||
@@ -38,7 +38,7 @@ export async function validateManifest(
|
||||
*/
|
||||
export async function parseAndValidateManifestFromText(
|
||||
manifestText: string,
|
||||
): Promise<McpbManifest> {
|
||||
): Promise<McpbManifestAny> {
|
||||
let manifestJson: unknown
|
||||
|
||||
try {
|
||||
@@ -55,7 +55,7 @@ export async function parseAndValidateManifestFromText(
|
||||
*/
|
||||
export async function parseAndValidateManifestFromBytes(
|
||||
manifestData: Uint8Array,
|
||||
): Promise<McpbManifest> {
|
||||
): Promise<McpbManifestAny> {
|
||||
const manifestText = new TextDecoder().decode(manifestData)
|
||||
return parseAndValidateManifestFromText(manifestText)
|
||||
}
|
||||
@@ -65,7 +65,7 @@ export async function parseAndValidateManifestFromBytes(
|
||||
* Uses the same algorithm as the directory backend for consistency.
|
||||
*/
|
||||
export function generateExtensionId(
|
||||
manifest: McpbManifest,
|
||||
manifest: McpbManifestAny,
|
||||
prefix?: 'local.unpacked' | 'local.dxt',
|
||||
): string {
|
||||
const sanitize = (str: string) =>
|
||||
|
||||
@@ -64,12 +64,12 @@ export async function findModifiedFiles(
|
||||
outputsDir: string,
|
||||
): Promise<string[]> {
|
||||
// Use recursive flag to get all entries in one call
|
||||
let entries: Awaited<ReturnType<typeof fs.readdir>>
|
||||
let entries: Awaited<ReturnType<typeof fs.readdir>> | any[]
|
||||
try {
|
||||
entries = await fs.readdir(outputsDir, {
|
||||
withFileTypes: true,
|
||||
recursive: true,
|
||||
})
|
||||
}) as any[]
|
||||
} catch {
|
||||
// Directory doesn't exist or is not accessible
|
||||
return []
|
||||
@@ -113,7 +113,7 @@ export async function findModifiedFiles(
|
||||
// Filter to files modified since turn start
|
||||
const modifiedFiles: string[] = []
|
||||
for (const result of statResults) {
|
||||
if (result && result.mtimeMs >= turnStartTime) {
|
||||
if (result && result.mtimeMs >= (turnStartTime as any as number)) {
|
||||
modifiedFiles.push(result.filePath)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -558,10 +558,10 @@ export async function runForkedAgent({
|
||||
if (message.type === 'stream_event') {
|
||||
if (
|
||||
'event' in message &&
|
||||
message.event?.type === 'message_delta' &&
|
||||
message.event.usage
|
||||
(message as any).event?.type === 'message_delta' &&
|
||||
(message as any).event.usage
|
||||
) {
|
||||
const turnUsage = updateUsage({ ...EMPTY_USAGE }, message.event.usage)
|
||||
const turnUsage = updateUsage({ ...EMPTY_USAGE }, (message as any).event.usage)
|
||||
totalUsage = accumulateUsage(totalUsage, turnUsage)
|
||||
}
|
||||
continue
|
||||
|
||||
@@ -1325,14 +1325,15 @@ export function checkWritePermissionForTool<Input extends AnyObject>(
|
||||
},
|
||||
]
|
||||
: generateSuggestions(path, 'write', toolPermissionContext, pathsToCheck)
|
||||
const failedCheck = safetyCheck as { safe: false; message: string; classifierApprovable: boolean }
|
||||
return {
|
||||
behavior: 'ask',
|
||||
message: safetyCheck.message,
|
||||
message: failedCheck.message,
|
||||
suggestions: safetySuggestions,
|
||||
decisionReason: {
|
||||
type: 'safetyCheck',
|
||||
reason: safetyCheck.message,
|
||||
classifierApprovable: safetyCheck.classifierApprovable,
|
||||
reason: failedCheck.message,
|
||||
classifierApprovable: failedCheck.classifierApprovable,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,8 +112,8 @@ export function isPathInSandboxWriteAllowlist(resolvedPath: string): boolean {
|
||||
// their resolution to avoid N × config.length redundant syscalls per
|
||||
// command with N write targets (matching getResolvedWorkingDirPaths).
|
||||
const pathsToCheck = getPathsForPermissionCheck(resolvedPath)
|
||||
const resolvedAllow = allowOnly.flatMap(getResolvedSandboxConfigPath)
|
||||
const resolvedDeny = denyWithinAllow.flatMap(getResolvedSandboxConfigPath)
|
||||
const resolvedAllow = allowOnly.flatMap(getResolvedSandboxConfigPath) as string[]
|
||||
const resolvedDeny = denyWithinAllow.flatMap(getResolvedSandboxConfigPath) as string[]
|
||||
return pathsToCheck.every(p => {
|
||||
for (const denyPath of resolvedDeny) {
|
||||
if (pathInWorkingPath(p, denyPath)) return false
|
||||
@@ -184,12 +184,13 @@ export function isPathAllowed(
|
||||
precomputedPathsToCheck,
|
||||
)
|
||||
if (!safetyCheck.safe) {
|
||||
const failedCheck = safetyCheck as { safe: false; message: string; classifierApprovable: boolean }
|
||||
return {
|
||||
allowed: false,
|
||||
decisionReason: {
|
||||
type: 'safetyCheck',
|
||||
reason: safetyCheck.message,
|
||||
classifierApprovable: safetyCheck.classifierApprovable,
|
||||
reason: failedCheck.message,
|
||||
classifierApprovable: failedCheck.classifierApprovable,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -412,7 +412,7 @@ async function runPermissionRequestHooksForHeadlessAgent(
|
||||
input,
|
||||
context,
|
||||
permissionMode,
|
||||
suggestions,
|
||||
suggestions as any,
|
||||
context.abortController.signal,
|
||||
)) {
|
||||
if (!hookResult.permissionRequestResult) {
|
||||
@@ -423,12 +423,12 @@ async function runPermissionRequestHooksForHeadlessAgent(
|
||||
const finalInput = decision.updatedInput ?? input
|
||||
// Persist permission updates if provided
|
||||
if (decision.updatedPermissions?.length) {
|
||||
persistPermissionUpdates(decision.updatedPermissions)
|
||||
persistPermissionUpdates(decision.updatedPermissions as any)
|
||||
context.setAppState(prev => ({
|
||||
...prev,
|
||||
toolPermissionContext: applyPermissionUpdates(
|
||||
prev.toolPermissionContext,
|
||||
decision.updatedPermissions!,
|
||||
decision.updatedPermissions as any,
|
||||
),
|
||||
}))
|
||||
}
|
||||
|
||||
@@ -251,12 +251,12 @@ export async function processUserInput({
|
||||
...hookResult.message,
|
||||
attachment: {
|
||||
...hookResult.message.attachment,
|
||||
content: applyTruncation(hookResult.message.attachment.content),
|
||||
content: applyTruncation(hookResult.message.attachment.content as string),
|
||||
},
|
||||
})
|
||||
} as AttachmentMessage)
|
||||
break
|
||||
default:
|
||||
result.messages.push(hookResult.message)
|
||||
result.messages.push(hookResult.message as AttachmentMessage)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ ${question}`
|
||||
function extractSideQuestionResponse(messages: Message[]): string | null {
|
||||
// Flatten all assistant content blocks across the per-block messages.
|
||||
const assistantBlocks = messages.flatMap(m =>
|
||||
m.type === 'assistant' ? m.message.content : [],
|
||||
m.type === 'assistant' ? (m.message.content as unknown as Array<{ type: string; [key: string]: unknown }>) : [],
|
||||
)
|
||||
|
||||
if (assistantBlocks.length > 0) {
|
||||
@@ -136,7 +136,7 @@ function extractSideQuestionResponse(messages: Message[]): string | null {
|
||||
// No text — check if the model tried to call a tool despite instructions.
|
||||
const toolUse = assistantBlocks.find(b => b.type === 'tool_use')
|
||||
if (toolUse) {
|
||||
const toolName = 'name' in toolUse ? toolUse.name : 'a tool'
|
||||
const toolName = 'name' in toolUse ? (toolUse as any).name : 'a tool'
|
||||
return `(The model tried to call ${toolName} instead of answering directly. Try rephrasing or ask in the main conversation.)`
|
||||
}
|
||||
}
|
||||
@@ -148,7 +148,7 @@ function extractSideQuestionResponse(messages: Message[]): string | null {
|
||||
m.type === 'system' && 'subtype' in m && m.subtype === 'api_error',
|
||||
)
|
||||
if (apiErr) {
|
||||
return `(API error: ${formatAPIError(apiErr.error)})`
|
||||
return `(API error: ${formatAPIError(apiErr.error as any)})`
|
||||
}
|
||||
|
||||
return null
|
||||
|
||||
@@ -43,7 +43,7 @@ export default function sliceAnsi(
|
||||
// pass start/end in display cells (via stringWidth), so position must
|
||||
// track the same units.
|
||||
const width =
|
||||
token.type === 'ansi' ? 0 : token.fullWidth ? 2 : stringWidth(token.value)
|
||||
token.type === 'ansi' ? 0 : token.type === 'char' ? (token.fullWidth ? 2 : stringWidth(token.value)) : 0
|
||||
|
||||
// Break AFTER trailing zero-width marks — a combining mark attaches to
|
||||
// the preceding base char, so "भा" (भ + ा, 1 display cell) sliced at
|
||||
@@ -77,7 +77,7 @@ export default function sliceAnsi(
|
||||
}
|
||||
|
||||
if (include) {
|
||||
result += token.value
|
||||
result += (token as any).value
|
||||
}
|
||||
|
||||
position += width
|
||||
|
||||
@@ -231,16 +231,17 @@ export async function createAndUploadGitBundle(
|
||||
)
|
||||
|
||||
if (!bundle.ok) {
|
||||
logForDebugging(`[gitBundle] ${bundle.error}`)
|
||||
const failedBundle = bundle as { ok: false; error: string; failReason: BundleFailReason }
|
||||
logForDebugging(`[gitBundle] ${failedBundle.error}`)
|
||||
logEvent('tengu_ccr_bundle_upload', {
|
||||
outcome:
|
||||
bundle.failReason as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
failedBundle.failReason as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
max_bytes: maxBytes,
|
||||
})
|
||||
return {
|
||||
success: false,
|
||||
error: bundle.error,
|
||||
failReason: bundle.failReason,
|
||||
error: failedBundle.error,
|
||||
failReason: failedBundle.failReason,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -254,7 +255,7 @@ export async function createAndUploadGitBundle(
|
||||
outcome:
|
||||
'failed' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
})
|
||||
return { success: false, error: upload.error }
|
||||
return { success: false, error: (upload as { success: false; error: string }).error }
|
||||
}
|
||||
|
||||
logForDebugging(
|
||||
|
||||
@@ -551,7 +551,7 @@ export function extractDiscoveredToolNames(messages: Message[]): Set<string> {
|
||||
// check rather than isCompactBoundaryMessage — utils/messages.ts imports
|
||||
// from this file, so importing back would be circular.
|
||||
if (msg.type === 'system' && msg.subtype === 'compact_boundary') {
|
||||
const carried = msg.compactMetadata?.preCompactDiscoveredTools
|
||||
const carried = (msg as any).compactMetadata?.preCompactDiscoveredTools as string[] | undefined
|
||||
if (carried) {
|
||||
for (const name of carried) discoveredTools.add(name)
|
||||
carriedFromBoundary += carried.length
|
||||
@@ -658,8 +658,8 @@ export function getDeferredToolsDelta(
|
||||
attachmentTypesSeen.add(msg.attachment.type)
|
||||
if (msg.attachment.type !== 'deferred_tools_delta') continue
|
||||
dtdCount++
|
||||
for (const n of msg.attachment.addedNames) announced.add(n)
|
||||
for (const n of msg.attachment.removedNames) announced.delete(n)
|
||||
for (const n of (msg.attachment as any).addedNames) announced.add(n)
|
||||
for (const n of (msg.attachment as any).removedNames) announced.delete(n)
|
||||
}
|
||||
|
||||
const deferred: Tool[] = tools.filter(isDeferredTool)
|
||||
|
||||
Reference in New Issue
Block a user