| author | |
| committer | |
| log | 343061a0538bde5aa79e6d2c4aca0d42aa7992cb |
| tree | 13b303e193457b27bed0c05fe1e978997ffa0349 |
| parent | 0b40ea62e12ea061bbc8e954cf8dee288e9faf56 |
| signature | Signed by PGP key B5690EEEBB952194 |
Co-authored-by: codex <codex@users.noreply.github.com>13 files changed, 746 insertions(+), 232 deletions(-)
apps/server/package.json+1-1| ... | @@ -22,7 +22,7 @@ | ... | @@ -22,7 +22,7 @@ |
| 22 | "test": "vp test run" | 22 | "test": "vp test run" |
| 23 | }, | 23 | }, |
| 24 | "dependencies": { | 24 | "dependencies": { |
| 25 | "@anthropic-ai/claude-agent-sdk": "^0.3.154", | 25 | "@anthropic-ai/claude-agent-sdk": "^0.3.170", |
| 26 | "@effect/platform-bun": "catalog:", | 26 | "@effect/platform-bun": "catalog:", |
| 27 | "@effect/platform-node": "catalog:", | 27 | "@effect/platform-node": "catalog:", |
| 28 | "@effect/platform-node-shared": "catalog:", | 28 | "@effect/platform-node-shared": "catalog:", |
apps/server/src/provider/Layers/ClaudeAdapter.ts+579-135| ... | @@ -14,6 +14,7 @@ import { | ... | @@ -14,6 +14,7 @@ import { |
| 14 | type PermissionResult, | 14 | type PermissionResult, |
| 15 | type PermissionUpdate, | 15 | type PermissionUpdate, |
| 16 | type SDKMessage, | 16 | type SDKMessage, |
| 17 | type SDKControlGetContextUsageResponse, | ||
| 17 | type SDKResultMessage, | 18 | type SDKResultMessage, |
| 18 | type SettingSource, | 19 | type SettingSource, |
| 19 | type SDKUserMessage, | 20 | type SDKUserMessage, |
| ... | @@ -29,6 +30,7 @@ import { | ... | @@ -29,6 +30,7 @@ import { |
| 29 | type ProviderApprovalDecision, | 30 | type ProviderApprovalDecision, |
| 30 | ProviderDriverKind, | 31 | ProviderDriverKind, |
| 31 | ProviderInstanceId, | 32 | ProviderInstanceId, |
| 33 | type ModelSelection, | ||
| 32 | ProviderItemId, | 34 | ProviderItemId, |
| 33 | type ProviderRuntimeEvent, | 35 | type ProviderRuntimeEvent, |
| 34 | type ProviderRuntimeTurnStatus, | 36 | type ProviderRuntimeTurnStatus, |
| ... | @@ -159,6 +161,13 @@ interface ToolInFlight { | ... | @@ -159,6 +161,13 @@ interface ToolInFlight { |
| 159 | readonly lastEmittedInputFingerprint?: string; | 161 | readonly lastEmittedInputFingerprint?: string; |
| 160 | } | 162 | } |
| 161 | 163 | ||
| 164 | interface ClaudeTaskState { | ||
| 165 | readonly id: string; | ||
| 166 | subject: string; | ||
| 167 | status: PlanStep["status"]; | ||
| 168 | readonly blockedBy: Set<string>; | ||
| 169 | } | ||
| 170 | |||
| 162 | interface ClaudeSessionContext { | 171 | interface ClaudeSessionContext { |
| 163 | session: ProviderSession; | 172 | session: ProviderSession; |
| 164 | readonly promptQueue: Queue.Queue<PromptQueueItem>; | 173 | readonly promptQueue: Queue.Queue<PromptQueueItem>; |
| ... | @@ -175,9 +184,11 @@ interface ClaudeSessionContext { | ... | @@ -175,9 +184,11 @@ interface ClaudeSessionContext { |
| 175 | items: Array<unknown>; | 184 | items: Array<unknown>; |
| 176 | }>; | 185 | }>; |
| 177 | readonly inFlightTools: Map<number, ToolInFlight>; | 186 | readonly inFlightTools: Map<number, ToolInFlight>; |
| 187 | readonly claudeTasks: Map<string, ClaudeTaskState>; | ||
| 178 | turnState: ClaudeTurnState | undefined; | 188 | turnState: ClaudeTurnState | undefined; |
| 179 | lastKnownContextWindow: number | undefined; | 189 | lastKnownContextWindow: number | undefined; |
| 180 | lastKnownTokenUsage: ThreadTokenUsageSnapshot | undefined; | 190 | lastKnownTokenUsage: ThreadTokenUsageSnapshot | undefined; |
| 191 | lastKnownTotalProcessedTokens: number | undefined; | ||
| 181 | lastAssistantUuid: string | undefined; | 192 | lastAssistantUuid: string | undefined; |
| 182 | lastThreadStartedId: string | undefined; | 193 | lastThreadStartedId: string | undefined; |
| 183 | stopped: boolean; | 194 | stopped: boolean; |
| ... | @@ -188,6 +199,7 @@ interface ClaudeQueryRuntime extends AsyncIterable<SDKMessage> { | ... | @@ -188,6 +199,7 @@ interface ClaudeQueryRuntime extends AsyncIterable<SDKMessage> { |
| 188 | readonly setModel: (model?: string) => Promise<void>; | 199 | readonly setModel: (model?: string) => Promise<void>; |
| 189 | readonly setPermissionMode: (mode: PermissionMode) => Promise<void>; | 200 | readonly setPermissionMode: (mode: PermissionMode) => Promise<void>; |
| 190 | readonly setMaxThinkingTokens: (maxThinkingTokens: number | null) => Promise<void>; | 201 | readonly setMaxThinkingTokens: (maxThinkingTokens: number | null) => Promise<void>; |
| 202 | readonly getContextUsage?: () => Promise<SDKControlGetContextUsageResponse>; | ||
| 191 | readonly close: () => void; | 203 | readonly close: () => void; |
| 192 | } | 204 | } |
| 193 | 205 | ||
| ... | @@ -337,60 +349,220 @@ function maxClaudeContextWindowFromModelUsage( | ... | @@ -337,60 +349,220 @@ function maxClaudeContextWindowFromModelUsage( |
| 337 | return maxContextWindow; | 349 | return maxContextWindow; |
| 338 | } | 350 | } |
| 339 | 351 | ||
| 340 | function normalizeClaudeTokenUsage( | 352 | function selectedClaudeContextWindow( |
| 341 | value: unknown, | 353 | modelSelection: ModelSelection | undefined, |
| 342 | contextWindow?: number, | 354 | ): number | undefined { |
| 343 | ): ThreadTokenUsageSnapshot | undefined { | 355 | switch (modelSelection?.model) { |
| 344 | if (!value || typeof value !== "object") { | 356 | case "claude-opus-4-8": |
| 357 | case "claude-opus-4-7": | ||
| 358 | return 1_000_000; | ||
| 359 | } | ||
| 360 | |||
| 361 | const optionValue = getModelSelectionStringOptionValue(modelSelection, "contextWindow"); | ||
| 362 | if (optionValue === "1m") { | ||
| 363 | return 1_000_000; | ||
| 364 | } | ||
| 365 | if (optionValue === "200k") { | ||
| 366 | return 200_000; | ||
| 367 | } | ||
| 368 | const caps = getClaudeModelCapabilities(modelSelection?.model); | ||
| 369 | const hasContextWindowOption = getProviderOptionDescriptors({ caps }).some( | ||
| 370 | (descriptor) => descriptor.type === "select" && descriptor.id === "contextWindow", | ||
| 371 | ); | ||
| 372 | if (hasContextWindowOption) { | ||
| 373 | return 200_000; | ||
| 374 | } | ||
| 375 | return undefined; | ||
| 376 | } | ||
| 377 | |||
| 378 | function finiteNonNegativeInteger(value: unknown): number | undefined { | ||
| 379 | return typeof value === "number" && Number.isFinite(value) && value >= 0 | ||
| 380 | ? Math.round(value) | ||
| 381 | : undefined; | ||
| 382 | } | ||
| 383 | |||
| 384 | function finitePositiveInteger(value: unknown): number | undefined { | ||
| 385 | return typeof value === "number" && Number.isFinite(value) && value > 0 | ||
| 386 | ? Math.round(value) | ||
| 387 | : undefined; | ||
| 388 | } | ||
| 389 | |||
| 390 | function claudeUsageInputTokens(usage: Record<string, unknown>): number { | ||
| 391 | return ( | ||
| 392 | (finiteNonNegativeInteger(usage.input_tokens) ?? 0) + | ||
| 393 | (finiteNonNegativeInteger(usage.cache_creation_input_tokens) ?? 0) + | ||
| 394 | (finiteNonNegativeInteger(usage.cache_read_input_tokens) ?? 0) | ||
| 395 | ); | ||
| 396 | } | ||
| 397 | |||
| 398 | function claudeUsageOutputTokens(usage: Record<string, unknown>): number { | ||
| 399 | return finiteNonNegativeInteger(usage.output_tokens) ?? 0; | ||
| 400 | } | ||
| 401 | |||
| 402 | function lastClaudeUsageIteration( | ||
| 403 | value: Record<string, unknown>, | ||
| 404 | ): Record<string, unknown> | undefined { | ||
| 405 | const iterations = Array.isArray(value.iterations) ? value.iterations : []; | ||
| 406 | return iterations.findLast( | ||
| 407 | (iteration): iteration is Record<string, unknown> => | ||
| 408 | iteration !== null && typeof iteration === "object" && !Array.isArray(iteration), | ||
| 409 | ); | ||
| 410 | } | ||
| 411 | |||
| 412 | function claudeTotalProcessedTokens(value: unknown): number | undefined { | ||
| 413 | if (!value || typeof value !== "object" || Array.isArray(value)) { | ||
| 345 | return undefined; | 414 | return undefined; |
| 346 | } | 415 | } |
| 347 | 416 | ||
| 348 | const usage = value as Record<string, unknown>; | 417 | const usage = value as Record<string, unknown>; |
| 349 | const inputTokens = | 418 | const explicitTotal = finiteNonNegativeInteger(usage.total_tokens); |
| 350 | (typeof usage.input_tokens === "number" && Number.isFinite(usage.input_tokens) | 419 | if (explicitTotal !== undefined && explicitTotal > 0) { |
| 351 | ? usage.input_tokens | 420 | return explicitTotal; |
| 352 | : 0) + | 421 | } |
| 353 | (typeof usage.cache_creation_input_tokens === "number" && | 422 | |
| 354 | Number.isFinite(usage.cache_creation_input_tokens) | 423 | const total = claudeUsageInputTokens(usage) + claudeUsageOutputTokens(usage); |
| 355 | ? usage.cache_creation_input_tokens | 424 | return total > 0 ? total : undefined; |
| 356 | : 0) + | 425 | } |
| 357 | (typeof usage.cache_read_input_tokens === "number" && | 426 | |
| 358 | Number.isFinite(usage.cache_read_input_tokens) | 427 | function makeClaudeTokenUsageSnapshot(input: { |
| 359 | ? usage.cache_read_input_tokens | 428 | readonly activeTokens: number; |
| 360 | : 0); | 429 | readonly inputTokens?: number; |
| 361 | const outputTokens = | 430 | readonly outputTokens?: number; |
| 362 | typeof usage.output_tokens === "number" && Number.isFinite(usage.output_tokens) | 431 | readonly contextWindow?: number; |
| 363 | ? usage.output_tokens | 432 | readonly totalProcessedTokens?: number; |
| 364 | : 0; | 433 | readonly lastUsedTokens?: number; |
| 365 | const derivedTotalProcessedTokens = inputTokens + outputTokens; | 434 | readonly compactsAutomatically?: boolean; |
| 366 | const totalProcessedTokens = | 435 | }): ThreadTokenUsageSnapshot | undefined { |
| 367 | (typeof usage.total_tokens === "number" && Number.isFinite(usage.total_tokens) | 436 | const activeTokens = finiteNonNegativeInteger(input.activeTokens); |
| 368 | ? usage.total_tokens | 437 | if (activeTokens === undefined || activeTokens <= 0) { |
| 369 | : undefined) ?? (derivedTotalProcessedTokens > 0 ? derivedTotalProcessedTokens : undefined); | ||
| 370 | if (totalProcessedTokens === undefined || totalProcessedTokens <= 0) { | ||
| 371 | return undefined; | 438 | return undefined; |
| 372 | } | 439 | } |
| 373 | 440 | ||
| 374 | const maxTokens = | 441 | const maxTokens = finitePositiveInteger(input.contextWindow); |
| 375 | typeof contextWindow === "number" && Number.isFinite(contextWindow) && contextWindow > 0 | 442 | const usedTokens = maxTokens !== undefined ? Math.min(activeTokens, maxTokens) : activeTokens; |
| 376 | ? contextWindow | 443 | const lastUsedTokens = |
| 377 | : undefined; | 444 | finiteNonNegativeInteger(input.lastUsedTokens) ?? |
| 378 | const usedTokens = | 445 | (maxTokens !== undefined ? Math.min(activeTokens, maxTokens) : activeTokens); |
| 379 | maxTokens !== undefined ? Math.min(totalProcessedTokens, maxTokens) : totalProcessedTokens; | 446 | const totalProcessedTokens = finiteNonNegativeInteger(input.totalProcessedTokens); |
| 447 | const inputTokens = finiteNonNegativeInteger(input.inputTokens); | ||
| 448 | const outputTokens = finiteNonNegativeInteger(input.outputTokens); | ||
| 380 | 449 | ||
| 381 | return { | 450 | return { |
| 382 | usedTokens, | 451 | usedTokens, |
| 383 | lastUsedTokens: usedTokens, | 452 | lastUsedTokens, |
| 384 | ...(totalProcessedTokens > usedTokens ? { totalProcessedTokens } : {}), | 453 | ...(totalProcessedTokens !== undefined && totalProcessedTokens > usedTokens |
| 385 | ...(inputTokens > 0 ? { inputTokens } : {}), | 454 | ? { totalProcessedTokens } |
| 386 | ...(outputTokens > 0 ? { outputTokens } : {}), | 455 | : {}), |
| 456 | ...(inputTokens !== undefined && inputTokens > 0 ? { inputTokens } : {}), | ||
| 457 | ...(outputTokens !== undefined && outputTokens > 0 ? { outputTokens } : {}), | ||
| 387 | ...(maxTokens !== undefined ? { maxTokens } : {}), | 458 | ...(maxTokens !== undefined ? { maxTokens } : {}), |
| 388 | ...(typeof usage.tool_uses === "number" && Number.isFinite(usage.tool_uses) | 459 | ...(input.compactsAutomatically !== undefined |
| 389 | ? { toolUses: usage.tool_uses } | 460 | ? { compactsAutomatically: input.compactsAutomatically } |
| 390 | : {}), | 461 | : {}), |
| 391 | ...(typeof usage.duration_ms === "number" && Number.isFinite(usage.duration_ms) | 462 | }; |
| 392 | ? { durationMs: usage.duration_ms } | 463 | } |
| 464 | |||
| 465 | function normalizeClaudeActiveTokenUsage( | ||
| 466 | value: unknown, | ||
| 467 | contextWindow?: number, | ||
| 468 | totalProcessedTokens?: number, | ||
| 469 | ): ThreadTokenUsageSnapshot | undefined { | ||
| 470 | if (!value || typeof value !== "object") { | ||
| 471 | return undefined; | ||
| 472 | } | ||
| 473 | |||
| 474 | const usage = value as Record<string, unknown>; | ||
| 475 | const activeUsage = lastClaudeUsageIteration(usage) ?? usage; | ||
| 476 | const inputTokens = claudeUsageInputTokens(activeUsage); | ||
| 477 | const outputTokens = claudeUsageOutputTokens(activeUsage); | ||
| 478 | const activeTokens = claudeTotalProcessedTokens(activeUsage) ?? inputTokens + outputTokens; | ||
| 479 | if (activeTokens <= 0) { | ||
| 480 | return undefined; | ||
| 481 | } | ||
| 482 | |||
| 483 | return makeClaudeTokenUsageSnapshot({ | ||
| 484 | activeTokens, | ||
| 485 | inputTokens, | ||
| 486 | outputTokens, | ||
| 487 | ...(contextWindow !== undefined ? { contextWindow } : {}), | ||
| 488 | ...(totalProcessedTokens !== undefined ? { totalProcessedTokens } : {}), | ||
| 489 | }); | ||
| 490 | } | ||
| 491 | |||
| 492 | function normalizeClaudeContextUsageApiSnapshot( | ||
| 493 | value: SDKControlGetContextUsageResponse, | ||
| 494 | totalProcessedTokens?: number, | ||
| 495 | ): ThreadTokenUsageSnapshot | undefined { | ||
| 496 | return makeClaudeTokenUsageSnapshot({ | ||
| 497 | activeTokens: value.totalTokens, | ||
| 498 | contextWindow: value.maxTokens, | ||
| 499 | ...(totalProcessedTokens !== undefined ? { totalProcessedTokens } : {}), | ||
| 500 | compactsAutomatically: value.isAutoCompactEnabled, | ||
| 501 | }); | ||
| 502 | } | ||
| 503 | |||
| 504 | function compactBoundaryTokenUsageSnapshot( | ||
| 505 | message: Record<string, unknown>, | ||
| 506 | contextWindow?: number, | ||
| 507 | totalProcessedTokens?: number, | ||
| 508 | ): ThreadTokenUsageSnapshot | undefined { | ||
| 509 | const metadata = message.compact_metadata; | ||
| 510 | if (!metadata || typeof metadata !== "object" || Array.isArray(metadata)) { | ||
| 511 | return undefined; | ||
| 512 | } | ||
| 513 | |||
| 514 | const compactMetadata = metadata as Record<string, unknown>; | ||
| 515 | const postTokens = finiteNonNegativeInteger(compactMetadata.post_tokens); | ||
| 516 | if (postTokens === undefined || postTokens <= 0) { | ||
| 517 | return undefined; | ||
| 518 | } | ||
| 519 | |||
| 520 | const preTokens = finiteNonNegativeInteger(compactMetadata.pre_tokens); | ||
| 521 | return makeClaudeTokenUsageSnapshot({ | ||
| 522 | activeTokens: postTokens, | ||
| 523 | ...(preTokens !== undefined ? { lastUsedTokens: preTokens } : {}), | ||
| 524 | ...(contextWindow !== undefined ? { contextWindow } : {}), | ||
| 525 | ...(totalProcessedTokens !== undefined ? { totalProcessedTokens } : {}), | ||
| 526 | }); | ||
| 527 | } | ||
| 528 | |||
| 529 | function normalizeClaudeTaskProgressTokenUsage( | ||
| 530 | value: unknown, | ||
| 531 | context: ClaudeSessionContext, | ||
| 532 | ): ThreadTokenUsageSnapshot | undefined { | ||
| 533 | const totalTokens = claudeTotalProcessedTokens(value); | ||
| 534 | if (totalTokens === undefined || totalTokens <= 0) { | ||
| 535 | return undefined; | ||
| 536 | } | ||
| 537 | |||
| 538 | const lastUsedTokens = context.lastKnownTokenUsage?.usedTokens; | ||
| 539 | const activeTokens = | ||
| 540 | lastUsedTokens !== undefined ? Math.max(totalTokens, lastUsedTokens) : totalTokens; | ||
| 541 | if (lastUsedTokens !== undefined && activeTokens === lastUsedTokens) { | ||
| 542 | return undefined; | ||
| 543 | } | ||
| 544 | |||
| 545 | const usage = value as Record<string, unknown>; | ||
| 546 | const snapshot = makeClaudeTokenUsageSnapshot({ | ||
| 547 | activeTokens, | ||
| 548 | ...(context.lastKnownContextWindow !== undefined | ||
| 549 | ? { contextWindow: context.lastKnownContextWindow } | ||
| 393 | : {}), | 550 | : {}), |
| 551 | totalProcessedTokens: Math.max( | ||
| 552 | totalTokens, | ||
| 553 | context.lastKnownTotalProcessedTokens ?? totalTokens, | ||
| 554 | ), | ||
| 555 | }); | ||
| 556 | if (!snapshot) { | ||
| 557 | return undefined; | ||
| 558 | } | ||
| 559 | |||
| 560 | const toolUses = finiteNonNegativeInteger(usage.tool_uses); | ||
| 561 | const durationMs = finiteNonNegativeInteger(usage.duration_ms); | ||
| 562 | return { | ||
| 563 | ...snapshot, | ||
| 564 | ...(toolUses !== undefined ? { toolUses } : {}), | ||
| 565 | ...(durationMs !== undefined ? { durationMs } : {}), | ||
| 394 | }; | 566 | }; |
| 395 | } | 567 | } |
| 396 | 568 | ||
| ... | @@ -539,6 +711,140 @@ function extractPlanStepsFromTodoInput(input: Record<string, unknown>): PlanStep | ... | @@ -539,6 +711,140 @@ function extractPlanStepsFromTodoInput(input: Record<string, unknown>): PlanStep |
| 539 | })); | 711 | })); |
| 540 | } | 712 | } |
| 541 | 713 | ||
| 714 | function isClaudeTaskTool(toolName: string): boolean { | ||
| 715 | return toolName === "TaskCreate" || toolName === "TaskUpdate" || toolName === "TaskList"; | ||
| 716 | } | ||
| 717 | |||
| 718 | function normalizeClaudeTaskStatus(value: unknown): PlanStep["status"] { | ||
| 719 | return value === "completed" ? "completed" : value === "in_progress" ? "inProgress" : "pending"; | ||
| 720 | } | ||
| 721 | |||
| 722 | function readString(value: unknown): string | undefined { | ||
| 723 | return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined; | ||
| 724 | } | ||
| 725 | |||
| 726 | function readStringArray(value: unknown): Array<string> { | ||
| 727 | return Array.isArray(value) | ||
| 728 | ? value.filter((entry): entry is string => typeof entry === "string" && entry.length > 0) | ||
| 729 | : []; | ||
| 730 | } | ||
| 731 | |||
| 732 | function readClaudeToolUseResult(message: SDKMessage): Record<string, unknown> | undefined { | ||
| 733 | if (message.type !== "user") { | ||
| 734 | return undefined; | ||
| 735 | } | ||
| 736 | const result = (message as { readonly tool_use_result?: unknown }).tool_use_result; | ||
| 737 | return result !== null && typeof result === "object" && !Array.isArray(result) | ||
| 738 | ? (result as Record<string, unknown>) | ||
| 739 | : undefined; | ||
| 740 | } | ||
| 741 | |||
| 742 | function readClaudeTaskFromResult( | ||
| 743 | result: Record<string, unknown> | undefined, | ||
| 744 | ): Record<string, unknown> | undefined { | ||
| 745 | const task = result?.task; | ||
| 746 | return task !== null && typeof task === "object" && !Array.isArray(task) | ||
| 747 | ? (task as Record<string, unknown>) | ||
| 748 | : undefined; | ||
| 749 | } | ||
| 750 | |||
| 751 | function applyClaudeTaskToolResult( | ||
| 752 | tasks: Map<string, ClaudeTaskState>, | ||
| 753 | tool: ToolInFlight, | ||
| 754 | result: Record<string, unknown> | undefined, | ||
| 755 | ): boolean { | ||
| 756 | if (!isClaudeTaskTool(tool.toolName)) { | ||
| 757 | return false; | ||
| 758 | } | ||
| 759 | |||
| 760 | let changed = false; | ||
| 761 | if (tool.toolName === "TaskList") { | ||
| 762 | const resultTasks = result?.tasks; | ||
| 763 | if (!Array.isArray(resultTasks)) { | ||
| 764 | return false; | ||
| 765 | } | ||
| 766 | tasks.clear(); | ||
| 767 | for (const entry of resultTasks) { | ||
| 768 | if (entry === null || typeof entry !== "object" || Array.isArray(entry)) { | ||
| 769 | continue; | ||
| 770 | } | ||
| 771 | const task = entry as Record<string, unknown>; | ||
| 772 | const id = readString(task.id); | ||
| 773 | const subject = readString(task.subject); | ||
| 774 | if (!id || !subject) { | ||
| 775 | continue; | ||
| 776 | } | ||
| 777 | tasks.set(id, { | ||
| 778 | id, | ||
| 779 | subject, | ||
| 780 | status: normalizeClaudeTaskStatus(task.status), | ||
| 781 | blockedBy: new Set(readStringArray(task.blockedBy)), | ||
| 782 | }); | ||
| 783 | } | ||
| 784 | return tasks.size > 0; | ||
| 785 | } | ||
| 786 | |||
| 787 | if (tool.toolName === "TaskCreate") { | ||
| 788 | const resultTask = readClaudeTaskFromResult(result); | ||
| 789 | const id = readString(resultTask?.id); | ||
| 790 | const subject = readString(resultTask?.subject) ?? readString(tool.input.subject); | ||
| 791 | if (!id || !subject) { | ||
| 792 | return false; | ||
| 793 | } | ||
| 794 | tasks.set(id, { | ||
| 795 | id, | ||
| 796 | subject, | ||
| 797 | status: normalizeClaudeTaskStatus(tool.input.status), | ||
| 798 | blockedBy: new Set(readStringArray(tool.input.blockedBy)), | ||
| 799 | }); | ||
| 800 | return true; | ||
| 801 | } | ||
| 802 | |||
| 803 | const taskId = readString(tool.input.taskId) ?? readString(result?.taskId); | ||
| 804 | if (!taskId) { | ||
| 805 | return false; | ||
| 806 | } | ||
| 807 | const task = tasks.get(taskId); | ||
| 808 | if (!task) { | ||
| 809 | return false; | ||
| 810 | } | ||
| 811 | const subject = readString(tool.input.subject); | ||
| 812 | if (subject && task.subject !== subject) { | ||
| 813 | task.subject = subject; | ||
| 814 | changed = true; | ||
| 815 | } | ||
| 816 | if (typeof tool.input.status === "string") { | ||
| 817 | const status = normalizeClaudeTaskStatus(tool.input.status); | ||
| 818 | if (task.status !== status) { | ||
| 819 | task.status = status; | ||
| 820 | changed = true; | ||
| 821 | } | ||
| 822 | } | ||
| 823 | for (const dependency of readStringArray(tool.input.addBlockedBy)) { | ||
| 824 | if (!task.blockedBy.has(dependency)) { | ||
| 825 | task.blockedBy.add(dependency); | ||
| 826 | changed = true; | ||
| 827 | } | ||
| 828 | } | ||
| 829 | for (const dependency of readStringArray(tool.input.removeBlockedBy)) { | ||
| 830 | if (task.blockedBy.delete(dependency)) { | ||
| 831 | changed = true; | ||
| 832 | } | ||
| 833 | } | ||
| 834 | return changed; | ||
| 835 | } | ||
| 836 | |||
| 837 | function planStepsFromClaudeTasks(tasks: Map<string, ClaudeTaskState>): PlanStep[] { | ||
| 838 | return Array.from(tasks.values()).map((task) => { | ||
| 839 | const blockedBy = Array.from(task.blockedBy); | ||
| 840 | const blockedSuffix = blockedBy.length > 0 ? ` (blocked by #${blockedBy.join(", #")})` : ""; | ||
| 841 | return { | ||
| 842 | step: `${task.subject}${blockedSuffix}`, | ||
| 843 | status: task.status, | ||
| 844 | }; | ||
| 845 | }); | ||
| 846 | } | ||
| 847 | |||
| 542 | function summarizeToolRequest(toolName: string, input: Record<string, unknown>): string { | 848 | function summarizeToolRequest(toolName: string, input: Record<string, unknown>): string { |
| 543 | const commandValue = input.command ?? input.cmd; | 849 | const commandValue = input.command ?? input.cmd; |
| 544 | const command = typeof commandValue === "string" ? commandValue : undefined; | 850 | const command = typeof commandValue === "string" ? commandValue : undefined; |
| ... | @@ -1438,6 +1744,70 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -1438,6 +1744,70 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 1438 | }); | 1744 | }); |
| 1439 | }); | 1745 | }); |
| 1440 | 1746 | ||
| 1747 | const emitThreadTokenUsage = Effect.fn("emitThreadTokenUsage")(function* ( | ||
| 1748 | context: ClaudeSessionContext, | ||
| 1749 | usage: ThreadTokenUsageSnapshot | undefined, | ||
| 1750 | options?: { | ||
| 1751 | readonly rawMethod?: string; | ||
| 1752 | readonly rawPayload?: unknown; | ||
| 1753 | }, | ||
| 1754 | ) { | ||
| 1755 | if (!usage) { | ||
| 1756 | return; | ||
| 1757 | } | ||
| 1758 | |||
| 1759 | context.lastKnownTokenUsage = usage; | ||
| 1760 | context.lastKnownTotalProcessedTokens = | ||
| 1761 | usage.totalProcessedTokens ?? context.lastKnownTotalProcessedTokens; | ||
| 1762 | |||
| 1763 | const turnState = context.turnState; | ||
| 1764 | const stamp = yield* makeEventStamp(); | ||
| 1765 | yield* offerRuntimeEvent({ | ||
| 1766 | type: "thread.token-usage.updated", | ||
| 1767 | eventId: stamp.eventId, | ||
| 1768 | provider: PROVIDER, | ||
| 1769 | createdAt: stamp.createdAt, | ||
| 1770 | threadId: context.session.threadId, | ||
| 1771 | ...(turnState ? { turnId: turnState.turnId } : {}), | ||
| 1772 | payload: { | ||
| 1773 | usage, | ||
| 1774 | }, | ||
| 1775 | providerRefs: nativeProviderRefs(context), | ||
| 1776 | ...(options?.rawMethod || options?.rawPayload | ||
| 1777 | ? { | ||
| 1778 | raw: { | ||
| 1779 | source: "claude.sdk.message" as const, | ||
| 1780 | ...(options.rawMethod ? { method: options.rawMethod } : {}), | ||
| 1781 | payload: options.rawPayload, | ||
| 1782 | }, | ||
| 1783 | } | ||
| 1784 | : {}), | ||
| 1785 | }); | ||
| 1786 | }); | ||
| 1787 | |||
| 1788 | const queryCurrentContextUsage = Effect.fn("queryCurrentContextUsage")(function* ( | ||
| 1789 | context: ClaudeSessionContext, | ||
| 1790 | totalProcessedTokens?: number, | ||
| 1791 | ) { | ||
| 1792 | if (!context.query.getContextUsage) { | ||
| 1793 | return undefined; | ||
| 1794 | } | ||
| 1795 | |||
| 1796 | const usage = yield* Effect.promise(async () => { | ||
| 1797 | try { | ||
| 1798 | return await context.query.getContextUsage?.(); | ||
| 1799 | } catch { | ||
| 1800 | return undefined; | ||
| 1801 | } | ||
| 1802 | }); | ||
| 1803 | if (!usage) { | ||
| 1804 | return undefined; | ||
| 1805 | } | ||
| 1806 | |||
| 1807 | context.lastKnownContextWindow = usage.maxTokens; | ||
| 1808 | return normalizeClaudeContextUsageApiSnapshot(usage, totalProcessedTokens); | ||
| 1809 | }); | ||
| 1810 | |||
| 1441 | const emitProposedPlanCompleted = Effect.fn("emitProposedPlanCompleted")(function* ( | 1811 | const emitProposedPlanCompleted = Effect.fn("emitProposedPlanCompleted")(function* ( |
| 1442 | context: ClaudeSessionContext, | 1812 | context: ClaudeSessionContext, |
| 1443 | input: { | 1813 | input: { |
| ... | @@ -1485,6 +1855,42 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -1485,6 +1855,42 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 1485 | }); | 1855 | }); |
| 1486 | }); | 1856 | }); |
| 1487 | 1857 | ||
| 1858 | const emitClaudeTaskPlanUpdated = Effect.fn("emitClaudeTaskPlanUpdated")(function* ( | ||
| 1859 | context: ClaudeSessionContext, | ||
| 1860 | input: { | ||
| 1861 | readonly toolUseId: string; | ||
| 1862 | readonly rawMethod: string; | ||
| 1863 | readonly rawPayload: unknown; | ||
| 1864 | }, | ||
| 1865 | ) { | ||
| 1866 | const plan = planStepsFromClaudeTasks(context.claudeTasks); | ||
| 1867 | if (plan.length === 0) { | ||
| 1868 | return; | ||
| 1869 | } | ||
| 1870 | |||
| 1871 | const stamp = yield* makeEventStamp(); | ||
| 1872 | yield* offerRuntimeEvent({ | ||
| 1873 | type: "turn.plan.updated", | ||
| 1874 | eventId: stamp.eventId, | ||
| 1875 | provider: PROVIDER, | ||
| 1876 | createdAt: stamp.createdAt, | ||
| 1877 | threadId: context.session.threadId, | ||
| 1878 | ...(context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {}), | ||
| 1879 | payload: { | ||
| 1880 | explanation: "Claude Tasks", | ||
| 1881 | plan, | ||
| 1882 | }, | ||
| 1883 | providerRefs: nativeProviderRefs(context, { | ||
| 1884 | providerItemId: input.toolUseId, | ||
| 1885 | }), | ||
| 1886 | raw: { | ||
| 1887 | source: "claude.sdk.message", | ||
| 1888 | method: input.rawMethod, | ||
| 1889 | payload: input.rawPayload, | ||
| 1890 | }, | ||
| 1891 | }); | ||
| 1892 | }); | ||
| 1893 | |||
| 1488 | const completeTurn = Effect.fn("completeTurn")(function* ( | 1894 | const completeTurn = Effect.fn("completeTurn")(function* ( |
| 1489 | context: ClaudeSessionContext, | 1895 | context: ClaudeSessionContext, |
| 1490 | status: ProviderRuntimeTurnStatus, | 1896 | status: ProviderRuntimeTurnStatus, |
| ... | @@ -1496,51 +1902,77 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -1496,51 +1902,77 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 1496 | context.lastKnownContextWindow = resultContextWindow; | 1902 | context.lastKnownContextWindow = resultContextWindow; |
| 1497 | } | 1903 | } |
| 1498 | 1904 | ||
| 1499 | // The SDK result.usage contains *accumulated* totals across all API calls | 1905 | const maxTokens = resultContextWindow ?? context.lastKnownContextWindow; |
| 1500 | // (input_tokens, cache_read_input_tokens, etc. summed over every request). | 1906 | const accumulatedTotalProcessedTokens = claudeTotalProcessedTokens(result?.usage); |
| 1501 | // This does NOT represent the current context window size. | 1907 | if (accumulatedTotalProcessedTokens !== undefined) { |
| 1502 | // Instead, use the last known context-window-accurate usage from task_progress | 1908 | context.lastKnownTotalProcessedTokens = accumulatedTotalProcessedTokens; |
| 1503 | // events and treat the accumulated total as totalProcessedTokens. | 1909 | } |
| 1504 | const accumulatedSnapshot = normalizeClaudeTokenUsage( | 1910 | |
| 1505 | result?.usage, | 1911 | const contextUsageSnapshot = yield* queryCurrentContextUsage( |
| 1506 | resultContextWindow ?? context.lastKnownContextWindow, | 1912 | context, |
| 1913 | accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens, | ||
| 1507 | ); | 1914 | ); |
| 1508 | const accumulatedTotalProcessedTokens = | 1915 | const resultUsageRecord = |
| 1509 | accumulatedSnapshot?.totalProcessedTokens ?? accumulatedSnapshot?.usedTokens; | 1916 | result?.usage && typeof result.usage === "object" && !Array.isArray(result.usage) |
| 1917 | ? (result.usage as Record<string, unknown>) | ||
| 1918 | : undefined; | ||
| 1919 | const hasResultUsageIteration = | ||
| 1920 | resultUsageRecord !== undefined && lastClaudeUsageIteration(resultUsageRecord) !== undefined; | ||
| 1921 | const resultHasActiveUsage = | ||
| 1922 | resultUsageRecord !== undefined && | ||
| 1923 | (hasResultUsageIteration || | ||
| 1924 | claudeUsageInputTokens(resultUsageRecord) + claudeUsageOutputTokens(resultUsageRecord) > 0); | ||
| 1925 | const resultTotalOnly = | ||
| 1926 | resultUsageRecord !== undefined && | ||
| 1927 | !resultHasActiveUsage && | ||
| 1928 | claudeTotalProcessedTokens(resultUsageRecord) !== undefined; | ||
| 1929 | const resultIterationSnapshot = resultUsageRecord | ||
| 1930 | ? normalizeClaudeActiveTokenUsage( | ||
| 1931 | resultUsageRecord, | ||
| 1932 | maxTokens, | ||
| 1933 | accumulatedTotalProcessedTokens ?? context.lastKnownTotalProcessedTokens, | ||
| 1934 | ) | ||
| 1935 | : undefined; | ||
| 1510 | const lastGoodUsage = context.lastKnownTokenUsage; | 1936 | const lastGoodUsage = context.lastKnownTokenUsage; |
| 1511 | const maxTokens = resultContextWindow ?? context.lastKnownContextWindow; | 1937 | const usageSnapshot: ThreadTokenUsageSnapshot | undefined = |
| 1512 | const usageSnapshot: ThreadTokenUsageSnapshot | undefined = lastGoodUsage | 1938 | contextUsageSnapshot ?? |
| 1513 | ? { | 1939 | (resultTotalOnly && lastGoodUsage |
| 1514 | ...lastGoodUsage, | 1940 | ? { |
| 1515 | ...(typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0 | 1941 | ...lastGoodUsage, |
| 1516 | ? { maxTokens } | 1942 | ...(typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0 |
| 1517 | : {}), | 1943 | ? { maxTokens } |
| 1518 | ...(typeof accumulatedTotalProcessedTokens === "number" && | 1944 | : {}), |
| 1519 | Number.isFinite(accumulatedTotalProcessedTokens) && | 1945 | ...(typeof accumulatedTotalProcessedTokens === "number" && |
| 1520 | accumulatedTotalProcessedTokens > lastGoodUsage.usedTokens | 1946 | Number.isFinite(accumulatedTotalProcessedTokens) && |
| 1521 | ? { | 1947 | accumulatedTotalProcessedTokens > lastGoodUsage.usedTokens |
| 1522 | totalProcessedTokens: accumulatedTotalProcessedTokens, | 1948 | ? { |
| 1523 | } | 1949 | totalProcessedTokens: accumulatedTotalProcessedTokens, |
| 1524 | : {}), | 1950 | } |
| 1525 | } | 1951 | : {}), |
| 1526 | : accumulatedSnapshot; | 1952 | } |
| 1953 | : resultIterationSnapshot) ?? | ||
| 1954 | (lastGoodUsage | ||
| 1955 | ? { | ||
| 1956 | ...lastGoodUsage, | ||
| 1957 | ...(typeof maxTokens === "number" && Number.isFinite(maxTokens) && maxTokens > 0 | ||
| 1958 | ? { maxTokens } | ||
| 1959 | : {}), | ||
| 1960 | ...(typeof accumulatedTotalProcessedTokens === "number" && | ||
| 1961 | Number.isFinite(accumulatedTotalProcessedTokens) && | ||
| 1962 | accumulatedTotalProcessedTokens > lastGoodUsage.usedTokens | ||
| 1963 | ? { | ||
| 1964 | totalProcessedTokens: accumulatedTotalProcessedTokens, | ||
| 1965 | } | ||
| 1966 | : {}), | ||
| 1967 | } | ||
| 1968 | : undefined); | ||
| 1527 | 1969 | ||
| 1528 | const turnState = context.turnState; | 1970 | const turnState = context.turnState; |
| 1529 | if (!turnState) { | 1971 | if (!turnState) { |
| 1530 | if (usageSnapshot) { | 1972 | yield* emitThreadTokenUsage(context, usageSnapshot, { |
| 1531 | const usageStamp = yield* makeEventStamp(); | 1973 | rawMethod: "claude/result", |
| 1532 | yield* offerRuntimeEvent({ | 1974 | rawPayload: result ?? { status }, |
| 1533 | type: "thread.token-usage.updated", | 1975 | }); |
| 1534 | eventId: usageStamp.eventId, | ||
| 1535 | provider: PROVIDER, | ||
| 1536 | createdAt: usageStamp.createdAt, | ||
| 1537 | threadId: context.session.threadId, | ||
| 1538 | payload: { | ||
| 1539 | usage: usageSnapshot, | ||
| 1540 | }, | ||
| 1541 | providerRefs: {}, | ||
| 1542 | }); | ||
| 1543 | } | ||
| 1544 | 1976 | ||
| 1545 | const stamp = yield* makeEventStamp(); | 1977 | const stamp = yield* makeEventStamp(); |
| 1546 | yield* offerRuntimeEvent({ | 1978 | yield* offerRuntimeEvent({ |
| ... | @@ -1611,21 +2043,10 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -1611,21 +2043,10 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 1611 | items: [...turnState.items], | 2043 | items: [...turnState.items], |
| 1612 | }); | 2044 | }); |
| 1613 | 2045 | ||
| 1614 | if (usageSnapshot) { | 2046 | yield* emitThreadTokenUsage(context, usageSnapshot, { |
| 1615 | const usageStamp = yield* makeEventStamp(); | 2047 | rawMethod: "claude/result", |
| 1616 | yield* offerRuntimeEvent({ | 2048 | rawPayload: result ?? { status }, |
| 1617 | type: "thread.token-usage.updated", | 2049 | }); |
| 1618 | eventId: usageStamp.eventId, | ||
| 1619 | provider: PROVIDER, | ||
| 1620 | createdAt: usageStamp.createdAt, | ||
| 1621 | threadId: context.session.threadId, | ||
| 1622 | turnId: turnState.turnId, | ||
| 1623 | payload: { | ||
| 1624 | usage: usageSnapshot, | ||
| 1625 | }, | ||
| 1626 | providerRefs: nativeProviderRefs(context), | ||
| 1627 | }); | ||
| 1628 | } | ||
| 1629 | 2050 | ||
| 1630 | const stamp = yield* makeEventStamp(); | 2051 | const stamp = yield* makeEventStamp(); |
| 1631 | yield* offerRuntimeEvent({ | 2052 | yield* offerRuntimeEvent({ |
| ... | @@ -1670,6 +2091,23 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -1670,6 +2091,23 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 1670 | 2091 | ||
| 1671 | const { event } = message; | 2092 | const { event } = message; |
| 1672 | 2093 | ||
| 2094 | if (event.type === "message_delta") { | ||
| 2095 | if (message.parent_tool_use_id !== null && message.parent_tool_use_id !== undefined) { | ||
| 2096 | return; | ||
| 2097 | } | ||
| 2098 | |||
| 2099 | const snapshot = normalizeClaudeActiveTokenUsage( | ||
| 2100 | event.usage, | ||
| 2101 | context.lastKnownContextWindow, | ||
| 2102 | context.lastKnownTotalProcessedTokens, | ||
| 2103 | ); | ||
| 2104 | yield* emitThreadTokenUsage(context, snapshot, { | ||
| 2105 | rawMethod: "claude/stream_event/message_delta", | ||
| 2106 | rawPayload: message, | ||
| 2107 | }); | ||
| 2108 | return; | ||
| 2109 | } | ||
| 2110 | |||
| 1673 | if (event.type === "content_block_delta") { | 2111 | if (event.type === "content_block_delta") { |
| 1674 | if ( | 2112 | if ( |
| 1675 | (event.delta.type === "text_delta" || event.delta.type === "thinking_delta") && | 2113 | (event.delta.type === "text_delta" || event.delta.type === "thinking_delta") && |
| ... | @@ -1932,6 +2370,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -1932,6 +2370,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 1932 | 2370 | ||
| 1933 | const [index, tool] = toolEntry; | 2371 | const [index, tool] = toolEntry; |
| 1934 | const itemStatus = toolResult.isError ? "failed" : "completed"; | 2372 | const itemStatus = toolResult.isError ? "failed" : "completed"; |
| 2373 | const toolUseResult = readClaudeToolUseResult(message); | ||
| 1935 | const toolData = { | 2374 | const toolData = { |
| 1936 | toolName: tool.toolName, | 2375 | toolName: tool.toolName, |
| 1937 | input: tool.input, | 2376 | input: tool.input, |
| ... | @@ -2016,6 +2455,17 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2016,6 +2455,17 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2016 | }, | 2455 | }, |
| 2017 | }); | 2456 | }); |
| 2018 | 2457 | ||
| 2458 | if ( | ||
| 2459 | !toolResult.isError && | ||
| 2460 | applyClaudeTaskToolResult(context.claudeTasks, tool, toolUseResult) | ||
| 2461 | ) { | ||
| 2462 | yield* emitClaudeTaskPlanUpdated(context, { | ||
| 2463 | toolUseId: tool.itemId, | ||
| 2464 | rawMethod: "claude/user", | ||
| 2465 | rawPayload: message, | ||
| 2466 | }); | ||
| 2467 | } | ||
| 2468 | |||
| 2019 | context.inFlightTools.delete(index); | 2469 | context.inFlightTools.delete(index); |
| 2020 | } | 2470 | } |
| 2021 | }); | 2471 | }); |
| ... | @@ -2171,6 +2621,18 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2171,6 +2621,18 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2171 | }); | 2621 | }); |
| 2172 | return; | 2622 | return; |
| 2173 | case "compact_boundary": | 2623 | case "compact_boundary": |
| 2624 | yield* emitThreadTokenUsage( | ||
| 2625 | context, | ||
| 2626 | compactBoundaryTokenUsageSnapshot( | ||
| 2627 | message as unknown as Record<string, unknown>, | ||
| 2628 | context.lastKnownContextWindow, | ||
| 2629 | context.lastKnownTotalProcessedTokens, | ||
| 2630 | ), | ||
| 2631 | { | ||
| 2632 | rawMethod: "claude/system/compact_boundary", | ||
| 2633 | rawPayload: message, | ||
| 2634 | }, | ||
| 2635 | ); | ||
| 2174 | yield* offerRuntimeEvent({ | 2636 | yield* offerRuntimeEvent({ |
| 2175 | ...base, | 2637 | ...base, |
| 2176 | type: "thread.state.changed", | 2638 | type: "thread.state.changed", |
| ... | @@ -2229,25 +2691,14 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2229,25 +2691,14 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2229 | }); | 2691 | }); |
| 2230 | return; | 2692 | return; |
| 2231 | case "task_progress": | 2693 | case "task_progress": |
| 2232 | if (message.usage) { | 2694 | yield* emitThreadTokenUsage( |
| 2233 | const normalizedUsage = normalizeClaudeTokenUsage( | 2695 | context, |
| 2234 | message.usage, | 2696 | normalizeClaudeTaskProgressTokenUsage(message.usage, context), |
| 2235 | context.lastKnownContextWindow, | 2697 | { |
| 2236 | ); | 2698 | rawMethod: "claude/system/task_progress", |
| 2237 | if (normalizedUsage) { | 2699 | rawPayload: message, |
| 2238 | context.lastKnownTokenUsage = normalizedUsage; | 2700 | }, |
| 2239 | const usageStamp = yield* makeEventStamp(); | 2701 | ); |
| 2240 | yield* offerRuntimeEvent({ | ||
| 2241 | ...base, | ||
| 2242 | eventId: usageStamp.eventId, | ||
| 2243 | createdAt: usageStamp.createdAt, | ||
| 2244 | type: "thread.token-usage.updated", | ||
| 2245 | payload: { | ||
| 2246 | usage: normalizedUsage, | ||
| 2247 | }, | ||
| 2248 | }); | ||
| 2249 | } | ||
| 2250 | } | ||
| 2251 | yield* offerRuntimeEvent({ | 2702 | yield* offerRuntimeEvent({ |
| 2252 | ...base, | 2703 | ...base, |
| 2253 | type: "task.progress", | 2704 | type: "task.progress", |
| ... | @@ -2261,25 +2712,14 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2261,25 +2712,14 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2261 | }); | 2712 | }); |
| 2262 | return; | 2713 | return; |
| 2263 | case "task_notification": | 2714 | case "task_notification": |
| 2264 | if (message.usage) { | 2715 | yield* emitThreadTokenUsage( |
| 2265 | const normalizedUsage = normalizeClaudeTokenUsage( | 2716 | context, |
| 2266 | message.usage, | 2717 | normalizeClaudeTaskProgressTokenUsage(message.usage, context), |
| 2267 | context.lastKnownContextWindow, | 2718 | { |
| 2268 | ); | 2719 | rawMethod: "claude/system/task_notification", |
| 2269 | if (normalizedUsage) { | 2720 | rawPayload: message, |
| 2270 | context.lastKnownTokenUsage = normalizedUsage; | 2721 | }, |
| 2271 | const usageStamp = yield* makeEventStamp(); | 2722 | ); |
| 2272 | yield* offerRuntimeEvent({ | ||
| 2273 | ...base, | ||
| 2274 | eventId: usageStamp.eventId, | ||
| 2275 | createdAt: usageStamp.createdAt, | ||
| 2276 | type: "thread.token-usage.updated", | ||
| 2277 | payload: { | ||
| 2278 | usage: normalizedUsage, | ||
| 2279 | }, | ||
| 2280 | }); | ||
| 2281 | } | ||
| 2282 | } | ||
| 2283 | yield* offerRuntimeEvent({ | 2723 | yield* offerRuntimeEvent({ |
| 2284 | ...base, | 2724 | ...base, |
| 2285 | type: "task.completed", | 2725 | type: "task.completed", |
| ... | @@ -2669,6 +3109,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2669,6 +3109,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2669 | const pendingApprovals = new Map<ApprovalRequestId, PendingApproval>(); | 3109 | const pendingApprovals = new Map<ApprovalRequestId, PendingApproval>(); |
| 2670 | const pendingUserInputs = new Map<ApprovalRequestId, PendingUserInput>(); | 3110 | const pendingUserInputs = new Map<ApprovalRequestId, PendingUserInput>(); |
| 2671 | const inFlightTools = new Map<number, ToolInFlight>(); | 3111 | const inFlightTools = new Map<number, ToolInFlight>(); |
| 3112 | const claudeTasks = new Map<string, ClaudeTaskState>(); | ||
| 2672 | 3113 | ||
| 2673 | const contextRef = yield* Ref.make<ClaudeSessionContext | undefined>(undefined); | 3114 | const contextRef = yield* Ref.make<ClaudeSessionContext | undefined>(undefined); |
| 2674 | 3115 | ||
| ... | @@ -2969,6 +3410,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -2969,6 +3410,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 2969 | const caps = getClaudeModelCapabilities(modelSelection?.model); | 3410 | const caps = getClaudeModelCapabilities(modelSelection?.model); |
| 2970 | const descriptors = getProviderOptionDescriptors({ caps }); | 3411 | const descriptors = getProviderOptionDescriptors({ caps }); |
| 2971 | const apiModelId = modelSelection ? resolveClaudeApiModelId(modelSelection) : undefined; | 3412 | const apiModelId = modelSelection ? resolveClaudeApiModelId(modelSelection) : undefined; |
| 3413 | const initialContextWindow = selectedClaudeContextWindow(modelSelection); | ||
| 2972 | const rawEffort = getModelSelectionStringOptionValue(modelSelection, "effort"); | 3414 | const rawEffort = getModelSelectionStringOptionValue(modelSelection, "effort"); |
| 2973 | const effort = resolveClaudeEffort(caps, rawEffort) ?? null; | 3415 | const effort = resolveClaudeEffort(caps, rawEffort) ?? null; |
| 2974 | const fastModeSupported = descriptors.some( | 3416 | const fastModeSupported = descriptors.some( |
| ... | @@ -3094,9 +3536,11 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( | ... | @@ -3094,9 +3536,11 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( |
| 3094 | pendingUserInputs, | 3536 | pendingUserInputs, |
| 3095 | turns: [], | 3537 | turns: [], |
| 3096 | inFlightTools, | 3538 | inFlightTools, |
| 3539 | claudeTasks, | ||
| 3097 | turnState: undefined, | 3540 | turnState: undefined, |
| 3098 | lastKnownContextWindow: undefined, | 3541 | lastKnownContextWindow: initialContextWindow, |
| 3099 | lastKnownTokenUsage: undefined, | 3542 | lastKnownTokenUsage: undefined, |
| 3543 | lastKnownTotalProcessedTokens: undefined, | ||
| 3100 | lastAssistantUuid: resumeState?.resumeSessionAt, | 3544 | lastAssistantUuid: resumeState?.resumeSessionAt, |
| 3101 | lastThreadStartedId: undefined, | 3545 | lastThreadStartedId: undefined, |
| 3102 | stopped: false, | 3546 | stopped: false, |
apps/server/src/provider/Layers/ClaudeProvider.ts-16| ... | @@ -108,14 +108,6 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [ | ... | @@ -108,14 +108,6 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [ |
| 108 | id: "fastMode", | 108 | id: "fastMode", |
| 109 | label: "Fast Mode", | 109 | label: "Fast Mode", |
| 110 | }), | 110 | }), |
| 111 | buildSelectOptionDescriptor({ | ||
| 112 | id: "contextWindow", | ||
| 113 | label: "Context Window", | ||
| 114 | options: [ | ||
| 115 | { value: "200k", label: "200k", isDefault: true }, | ||
| 116 | { value: "1m", label: "1M" }, | ||
| 117 | ], | ||
| 118 | }), | ||
| 119 | ], | 111 | ], |
| 120 | }), | 112 | }), |
| 121 | }, | 113 | }, |
| ... | @@ -142,14 +134,6 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [ | ... | @@ -142,14 +134,6 @@ const BUILT_IN_MODELS: ReadonlyArray<ServerProviderModel> = [ |
| 142 | id: "fastMode", | 134 | id: "fastMode", |
| 143 | label: "Fast Mode", | 135 | label: "Fast Mode", |
| 144 | }), | 136 | }), |
| 145 | buildSelectOptionDescriptor({ | ||
| 146 | id: "contextWindow", | ||
| 147 | label: "Context Window", | ||
| 148 | options: [ | ||
| 149 | { value: "200k", label: "200k", isDefault: true }, | ||
| 150 | { value: "1m", label: "1M" }, | ||
| 151 | ], | ||
| 152 | }), | ||
| 153 | ], | 137 | ], |
| 154 | }), | 138 | }), |
| 155 | }, | 139 | }, |
apps/web/src/components/ChatMarkdown.tsx+5-1| ... | @@ -665,6 +665,7 @@ function UncachedShikiCodeBlock({ | ... | @@ -665,6 +665,7 @@ function UncachedShikiCodeBlock({ |
| 665 | interface MarkdownFileLinkProps { | 665 | interface MarkdownFileLinkProps { |
| 666 | href: string; | 666 | href: string; |
| 667 | targetPath: string; | 667 | targetPath: string; |
| 668 | iconPath: string; | ||
| 668 | displayPath: string; | 669 | displayPath: string; |
| 669 | label: string; | 670 | label: string; |
| 670 | copyMarkdown: string; | 671 | copyMarkdown: string; |
| ... | @@ -938,6 +939,7 @@ function MarkdownExternalLinkContent({ | ... | @@ -938,6 +939,7 @@ function MarkdownExternalLinkContent({ |
| 938 | const MarkdownFileLink = memo(function MarkdownFileLink({ | 939 | const MarkdownFileLink = memo(function MarkdownFileLink({ |
| 939 | href, | 940 | href, |
| 940 | targetPath, | 941 | targetPath, |
| 942 | iconPath, | ||
| 941 | displayPath, | 943 | displayPath, |
| 942 | label, | 944 | label, |
| 943 | copyMarkdown, | 945 | copyMarkdown, |
| ... | @@ -1044,7 +1046,7 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ | ... | @@ -1044,7 +1046,7 @@ const MarkdownFileLink = memo(function MarkdownFileLink({ |
| 1044 | }} | 1046 | }} |
| 1045 | onContextMenu={handleContextMenu} | 1047 | onContextMenu={handleContextMenu} |
| 1046 | > | 1048 | > |
| 1047 | <FileTagChipContent path={targetPath} label={label} theme={theme} selectable /> | 1049 | <FileTagChipContent path={iconPath} label={label} theme={theme} selectable /> |
| 1048 | </a> | 1050 | </a> |
| 1049 | } | 1051 | } |
| 1050 | /> | 1052 | /> |
| ... | @@ -1067,6 +1069,7 @@ function areMarkdownFileLinkPropsEqual( | ... | @@ -1067,6 +1069,7 @@ function areMarkdownFileLinkPropsEqual( |
| 1067 | return ( | 1069 | return ( |
| 1068 | previous.href === next.href && | 1070 | previous.href === next.href && |
| 1069 | previous.targetPath === next.targetPath && | 1071 | previous.targetPath === next.targetPath && |
| 1072 | previous.iconPath === next.iconPath && | ||
| 1070 | previous.displayPath === next.displayPath && | 1073 | previous.displayPath === next.displayPath && |
| 1071 | previous.label === next.label && | 1074 | previous.label === next.label && |
| 1072 | previous.copyMarkdown === next.copyMarkdown && | 1075 | previous.copyMarkdown === next.copyMarkdown && |
| ... | @@ -1186,6 +1189,7 @@ function ChatMarkdown({ | ... | @@ -1186,6 +1189,7 @@ function ChatMarkdown({ |
| 1186 | <MarkdownFileLink | 1189 | <MarkdownFileLink |
| 1187 | href={fileLinkMeta.targetPath} | 1190 | href={fileLinkMeta.targetPath} |
| 1188 | targetPath={fileLinkMeta.targetPath} | 1191 | targetPath={fileLinkMeta.targetPath} |
| 1192 | iconPath={fileLinkMeta.filePath} | ||
| 1189 | displayPath={fileLinkMeta.displayPath} | 1193 | displayPath={fileLinkMeta.displayPath} |
| 1190 | label={labelParts.join(" · ")} | 1194 | label={labelParts.join(" · ")} |
| 1191 | copyMarkdown={`[${fileLinkMeta.basename}](${normalizedHref})`} | 1195 | copyMarkdown={`[${fileLinkMeta.basename}](${normalizedHref})`} |
apps/web/src/components/DiffPanel.tsx+35-1| ... | @@ -53,6 +53,8 @@ const DIFF_PANEL_UNSAFE_CSS = ` | ... | @@ -53,6 +53,8 @@ const DIFF_PANEL_UNSAFE_CSS = ` |
| 53 | [data-file], | 53 | [data-file], |
| 54 | [data-error-wrapper], | 54 | [data-error-wrapper], |
| 55 | [data-virtualizer-buffer] { | 55 | [data-virtualizer-buffer] { |
| 56 | --diffs-header-font-family: var(--font-sans) !important; | ||
| 57 | --diffs-font-family: var(--font-mono) !important; | ||
| 56 | --diffs-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important; | 58 | --diffs-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important; |
| 57 | --diffs-light-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important; | 59 | --diffs-light-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important; |
| 58 | --diffs-dark-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important; | 60 | --diffs-dark-bg: color-mix(in srgb, var(--card) 90%, var(--background)) !important; |
| ... | @@ -93,6 +95,37 @@ const DIFF_PANEL_UNSAFE_CSS = ` | ... | @@ -93,6 +95,37 @@ const DIFF_PANEL_UNSAFE_CSS = ` |
| 93 | z-index: 4; | 95 | z-index: 4; |
| 94 | background-color: color-mix(in srgb, var(--card) 94%, var(--foreground)) !important; | 96 | background-color: color-mix(in srgb, var(--card) 94%, var(--foreground)) !important; |
| 95 | border-bottom: 1px solid var(--border) !important; | 97 | border-bottom: 1px solid var(--border) !important; |
| 98 | align-items: center !important; | ||
| 99 | font-family: var(--font-sans) !important; | ||
| 100 | font-size: 12px !important; | ||
| 101 | line-height: 1 !important; | ||
| 102 | min-height: 32px !important; | ||
| 103 | padding-block: 6px !important; | ||
| 104 | } | ||
| 105 | |||
| 106 | [data-diffs-header] [data-header-content] { | ||
| 107 | align-items: center !important; | ||
| 108 | line-height: 1 !important; | ||
| 109 | } | ||
| 110 | |||
| 111 | [data-diffs-header] [data-metadata] { | ||
| 112 | align-items: center !important; | ||
| 113 | line-height: 1 !important; | ||
| 114 | font-variant-numeric: tabular-nums; | ||
| 115 | } | ||
| 116 | |||
| 117 | [data-diffs-header] [data-additions-count], | ||
| 118 | [data-diffs-header] [data-deletions-count] { | ||
| 119 | font-family: var(--font-mono) !important; | ||
| 120 | font-size: 11px !important; | ||
| 121 | font-variant-numeric: tabular-nums; | ||
| 122 | line-height: 1 !important; | ||
| 123 | } | ||
| 124 | |||
| 125 | [data-diffs-header] [data-change-icon], | ||
| 126 | [data-diffs-header] [data-rename-icon] { | ||
| 127 | display: block; | ||
| 128 | flex-shrink: 0; | ||
| 96 | } | 129 | } |
| 97 | 130 | ||
| 98 | [data-title] { | 131 | [data-title] { |
| ... | @@ -103,6 +136,7 @@ const DIFF_PANEL_UNSAFE_CSS = ` | ... | @@ -103,6 +136,7 @@ const DIFF_PANEL_UNSAFE_CSS = ` |
| 103 | text-decoration: underline; | 136 | text-decoration: underline; |
| 104 | text-decoration-color: transparent; | 137 | text-decoration-color: transparent; |
| 105 | text-underline-offset: 2px; | 138 | text-underline-offset: 2px; |
| 139 | font-family: var(--font-sans) !important; | ||
| 106 | } | 140 | } |
| 107 | 141 | ||
| 108 | [data-title]:hover { | 142 | [data-title]:hover { |
| ... | @@ -488,7 +522,7 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { | ... | @@ -488,7 +522,7 @@ export default function DiffPanel({ mode = "inline" }: DiffPanelProps) { |
| 488 | inferredCheckpointTurnCountByTurnId[summary.turnId] ?? | 522 | inferredCheckpointTurnCountByTurnId[summary.turnId] ?? |
| 489 | "?"} | 523 | "?"} |
| 490 | </span> | 524 | </span> |
| 491 | <span className="text-[9px] leading-tight opacity-70"> | 525 | <span className="text-[9px] leading-tight opacity-70 tabular-nums"> |
| 492 | {formatShortTimestamp(summary.completedAt, settings.timestampFormat)} | 526 | {formatShortTimestamp(summary.completedAt, settings.timestampFormat)} |
| 493 | </span> | 527 | </span> |
| 494 | </div> | 528 | </div> |
apps/web/src/components/GitActionsControl.tsx+5-1| ... | @@ -19,6 +19,7 @@ import { | ... | @@ -19,6 +19,7 @@ import { |
| 19 | ChevronDownIcon, | 19 | ChevronDownIcon, |
| 20 | CloudUploadIcon, | 20 | CloudUploadIcon, |
| 21 | ExternalLinkIcon, | 21 | ExternalLinkIcon, |
| 22 | GitBranchPlusIcon, | ||
| 22 | GitCommitIcon, | 23 | GitCommitIcon, |
| 23 | InfoIcon, | 24 | InfoIcon, |
| 24 | LockIcon, | 25 | LockIcon, |
| ... | @@ -1611,7 +1612,10 @@ export default function GitActionsControl({ | ... | @@ -1611,7 +1612,10 @@ export default function GitActionsControl({ |
| 1611 | void initAction.run(); | 1612 | void initAction.run(); |
| 1612 | }} | 1613 | }} |
| 1613 | > | 1614 | > |
| 1614 | {initAction.isPending ? "Initializing..." : "Initialize Git"} | 1615 | <GitBranchPlusIcon className="size-3.5" aria-hidden /> |
| 1616 | <span className="ml-0.5"> | ||
| 1617 | {initAction.isPending ? "Initializing..." : "Initialize Git"} | ||
| 1618 | </span> | ||
| 1615 | </Button> | 1619 | </Button> |
| 1616 | ) : ( | 1620 | ) : ( |
| 1617 | <Group aria-label="Git actions" className="shrink-0"> | 1621 | <Group aria-label="Git actions" className="shrink-0"> |
apps/web/src/components/NoActiveThreadState.tsx+1-1| ... | @@ -30,7 +30,7 @@ export function NoActiveThreadState() { | ... | @@ -30,7 +30,7 @@ export function NoActiveThreadState() { |
| 30 | </header> | 30 | </header> |
| 31 | 31 | ||
| 32 | <Empty className="flex-1"> | 32 | <Empty className="flex-1"> |
| 33 | <div className="w-full max-w-lg rounded-3xl border border-border/55 bg-card/20 px-8 py-12 shadow-sm/5"> | 33 | <div className="w-full max-w-lg px-8 py-12"> |
| 34 | <EmptyHeader className="max-w-none"> | 34 | <EmptyHeader className="max-w-none"> |
| 35 | <EmptyTitle className="text-foreground text-xl">Pick a thread to continue</EmptyTitle> | 35 | <EmptyTitle className="text-foreground text-xl">Pick a thread to continue</EmptyTitle> |
| 36 | <EmptyDescription className="mt-2 text-sm text-muted-foreground/78"> | 36 | <EmptyDescription className="mt-2 text-sm text-muted-foreground/78"> |
apps/web/src/components/PlanSidebar.tsx+8-7| ... | @@ -32,14 +32,14 @@ import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; | ... | @@ -32,14 +32,14 @@ import { useCopyToClipboard } from "~/hooks/useCopyToClipboard"; |
| 32 | function stepStatusIcon(status: string): React.ReactNode { | 32 | function stepStatusIcon(status: string): React.ReactNode { |
| 33 | if (status === "completed") { | 33 | if (status === "completed") { |
| 34 | return ( | 34 | return ( |
| 35 | <span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-emerald-500/15 text-emerald-500"> | 35 | <span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-success/10 text-success-foreground"> |
| 36 | <CheckIcon className="size-3" /> | 36 | <CheckIcon className="size-3" /> |
| 37 | </span> | 37 | </span> |
| 38 | ); | 38 | ); |
| 39 | } | 39 | } |
| 40 | if (status === "inProgress") { | 40 | if (status === "inProgress") { |
| 41 | return ( | 41 | return ( |
| 42 | <span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-blue-500/15 text-blue-400"> | 42 | <span className="flex size-5 shrink-0 items-center justify-center rounded-full bg-primary/10 text-primary"> |
| 43 | <LoaderIcon className="size-3 animate-spin" /> | 43 | <LoaderIcon className="size-3 animate-spin" /> |
| 44 | </span> | 44 | </span> |
| 45 | ); | 45 | ); |
| ... | @@ -139,13 +139,14 @@ const PlanSidebar = memo(function PlanSidebar({ | ... | @@ -139,13 +139,14 @@ const PlanSidebar = memo(function PlanSidebar({ |
| 139 | <div className="flex h-12 shrink-0 items-center justify-between border-b border-border/60 px-3"> | 139 | <div className="flex h-12 shrink-0 items-center justify-between border-b border-border/60 px-3"> |
| 140 | <div className="flex items-center gap-2"> | 140 | <div className="flex items-center gap-2"> |
| 141 | <Badge | 141 | <Badge |
| 142 | variant="secondary" | 142 | variant="info" |
| 143 | className="rounded-md bg-blue-500/10 px-1.5 py-0 text-[10px] font-semibold tracking-wide text-blue-400 uppercase" | 143 | size="sm" |
| 144 | className="rounded-md px-1.5 py-0 font-semibold tracking-wide uppercase" | ||
| 144 | > | 145 | > |
| 145 | {label} | 146 | {label} |
| 146 | </Badge> | 147 | </Badge> |
| 147 | {activePlan ? ( | 148 | {activePlan ? ( |
| 148 | <span className="text-[11px] text-muted-foreground/60"> | 149 | <span className="text-[11px] text-muted-foreground/60 tabular-nums"> |
| 149 | {formatTimestamp(activePlan.createdAt, timestampFormat)} | 150 | {formatTimestamp(activePlan.createdAt, timestampFormat)} |
| 150 | </span> | 151 | </span> |
| 151 | ) : null} | 152 | ) : null} |
| ... | @@ -211,12 +212,12 @@ const PlanSidebar = memo(function PlanSidebar({ | ... | @@ -211,12 +212,12 @@ const PlanSidebar = memo(function PlanSidebar({ |
| 211 | <div | 212 | <div |
| 212 | key={`${step.status}:${step.step}`} | 213 | key={`${step.status}:${step.step}`} |
| 213 | className={cn( | 214 | className={cn( |
| 214 | "flex items-start gap-2.5 rounded-lg px-2.5 py-2 transition-colors duration-200", | 215 | "flex items-center gap-2.5 rounded-lg px-2.5 py-2 transition-colors duration-200", |
| 215 | step.status === "inProgress" && "bg-blue-500/5", | 216 | step.status === "inProgress" && "bg-blue-500/5", |
| 216 | step.status === "completed" && "bg-emerald-500/5", | 217 | step.status === "completed" && "bg-emerald-500/5", |
| 217 | )} | 218 | )} |
| 218 | > | 219 | > |
| 219 | <div className="mt-0.5">{stepStatusIcon(step.status)}</div> | 220 | {stepStatusIcon(step.status)} |
| 220 | <p | 221 | <p |
| 221 | className={cn( | 222 | className={cn( |
| 222 | "text-[13px] leading-snug", | 223 | "text-[13px] leading-snug", |
apps/web/src/components/chat/ChatHeader.tsx+2-16| ... | @@ -10,7 +10,6 @@ import { memo } from "react"; | ... | @@ -10,7 +10,6 @@ import { memo } from "react"; |
| 10 | import GitActionsControl from "../GitActionsControl"; | 10 | import GitActionsControl from "../GitActionsControl"; |
| 11 | import { type DraftId } from "~/composerDraftStore"; | 11 | import { type DraftId } from "~/composerDraftStore"; |
| 12 | import { DiffIcon, TerminalSquareIcon } from "lucide-react"; | 12 | import { DiffIcon, TerminalSquareIcon } from "lucide-react"; |
| 13 | import { Badge } from "../ui/badge"; | ||
| 14 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; | 13 | import { Tooltip, TooltipPopup, TooltipTrigger } from "../ui/tooltip"; |
| 15 | import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScriptsControl"; | 14 | import ProjectScriptsControl, { type NewProjectScriptInput } from "../ProjectScriptsControl"; |
| 16 | import { Toggle } from "../ui/toggle"; | 15 | import { Toggle } from "../ui/toggle"; |
| ... | @@ -105,19 +104,6 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -105,19 +104,6 @@ export const ChatHeader = memo(function ChatHeader({ |
| 105 | /> | 104 | /> |
| 106 | <TooltipPopup side="top">{activeThreadTitle}</TooltipPopup> | 105 | <TooltipPopup side="top">{activeThreadTitle}</TooltipPopup> |
| 107 | </Tooltip> | 106 | </Tooltip> |
| 108 | {activeProjectName && ( | ||
| 109 | <Badge | ||
| 110 | variant="outline" | ||
| 111 | className="min-w-0 max-w-full shrink overflow-hidden sm:max-w-56" | ||
| 112 | > | ||
| 113 | <span className="min-w-0 truncate">{activeProjectName}</span> | ||
| 114 | </Badge> | ||
| 115 | )} | ||
| 116 | {activeProjectName && !isGitRepo && ( | ||
| 117 | <Badge variant="outline" className="shrink-0 text-[10px] text-amber-700"> | ||
| 118 | No Git | ||
| 119 | </Badge> | ||
| 120 | )} | ||
| 121 | </div> | 107 | </div> |
| 122 | <div className="flex min-w-0 flex-wrap items-center justify-start gap-2 sm:shrink-0 sm:justify-end @3xl/header-actions:gap-3"> | 108 | <div className="flex min-w-0 flex-wrap items-center justify-start gap-2 sm:shrink-0 sm:justify-end @3xl/header-actions:gap-3"> |
| 123 | {activeProjectScripts && ( | 109 | {activeProjectScripts && ( |
| ... | @@ -153,7 +139,7 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -153,7 +139,7 @@ export const ChatHeader = memo(function ChatHeader({ |
| 153 | pressed={terminalOpen} | 139 | pressed={terminalOpen} |
| 154 | onPressedChange={onToggleTerminal} | 140 | onPressedChange={onToggleTerminal} |
| 155 | aria-label="Toggle terminal drawer" | 141 | aria-label="Toggle terminal drawer" |
| 156 | variant="outline" | 142 | variant="ghost" |
| 157 | size="xs" | 143 | size="xs" |
| 158 | disabled={!terminalAvailable} | 144 | disabled={!terminalAvailable} |
| 159 | > | 145 | > |
| ... | @@ -177,7 +163,7 @@ export const ChatHeader = memo(function ChatHeader({ | ... | @@ -177,7 +163,7 @@ export const ChatHeader = memo(function ChatHeader({ |
| 177 | pressed={diffOpen} | 163 | pressed={diffOpen} |
| 178 | onPressedChange={onToggleDiff} | 164 | onPressedChange={onToggleDiff} |
| 179 | aria-label="Toggle diff panel" | 165 | aria-label="Toggle diff panel" |
| 180 | variant="outline" | 166 | variant="ghost" |
| 181 | size="xs" | 167 | size="xs" |
| 182 | disabled={!isGitRepo && !diffOpen} | 168 | disabled={!isGitRepo && !diffOpen} |
| 183 | > | 169 | > |
apps/web/src/components/chat/ComposerPlanFollowUpBanner.tsx+8-1| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | import { memo } from "react"; | 1 | import { memo } from "react"; |
| 2 | import { Badge } from "../ui/badge"; | ||
| 2 | 3 | ||
| 3 | export const ComposerPlanFollowUpBanner = memo(function ComposerPlanFollowUpBanner({ | 4 | export const ComposerPlanFollowUpBanner = memo(function ComposerPlanFollowUpBanner({ |
| 4 | planTitle, | 5 | planTitle, |
| ... | @@ -8,7 +9,13 @@ export const ComposerPlanFollowUpBanner = memo(function ComposerPlanFollowUpBann | ... | @@ -8,7 +9,13 @@ export const ComposerPlanFollowUpBanner = memo(function ComposerPlanFollowUpBann |
| 8 | return ( | 9 | return ( |
| 9 | <div className="px-4 py-3.5 sm:px-5 sm:py-4"> | 10 | <div className="px-4 py-3.5 sm:px-5 sm:py-4"> |
| 10 | <div className="flex flex-wrap items-center gap-2"> | 11 | <div className="flex flex-wrap items-center gap-2"> |
| 11 | <span className="uppercase text-sm tracking-[0.2em]">Plan ready</span> | 12 | <Badge |
| 13 | variant="info" | ||
| 14 | size="sm" | ||
| 15 | className="rounded-md px-1.5 py-0 font-semibold tracking-wide uppercase" | ||
| 16 | > | ||
| 17 | Plan Ready | ||
| 18 | </Badge> | ||
| 12 | {planTitle ? ( | 19 | {planTitle ? ( |
| 13 | <span className="min-w-0 flex-1 truncate text-sm font-medium">{planTitle}</span> | 20 | <span className="min-w-0 flex-1 truncate text-sm font-medium">{planTitle}</span> |
| 14 | ) : null} | 21 | ) : null} |
apps/web/src/components/chat/MessagesTimeline.browser.tsx+29| ... | @@ -7,6 +7,8 @@ import { page } from "vite-plus/test/browser"; | ... | @@ -7,6 +7,8 @@ import { page } from "vite-plus/test/browser"; |
| 7 | import { afterEach, describe, expect, it, vi } from "vite-plus/test"; | 7 | import { afterEach, describe, expect, it, vi } from "vite-plus/test"; |
| 8 | import { render } from "vitest-browser-react"; | 8 | import { render } from "vitest-browser-react"; |
| 9 | 9 | ||
| 10 | import { getVscodeIconUrlForEntry } from "../../vscode-icons"; | ||
| 11 | |||
| 10 | const scrollToEndSpy = vi.fn(); | 12 | const scrollToEndSpy = vi.fn(); |
| 11 | const getStateSpy = vi.fn(() => ({ isAtEnd: true })); | 13 | const getStateSpy = vi.fn(() => ({ isAtEnd: true })); |
| 12 | 14 | ||
| ... | @@ -386,4 +388,31 @@ describe("MessagesTimeline", () => { | ... | @@ -386,4 +388,31 @@ describe("MessagesTimeline", () => { |
| 386 | await screen.unmount(); | 388 | await screen.unmount(); |
| 387 | } | 389 | } |
| 388 | }); | 390 | }); |
| 391 | |||
| 392 | it("uses the file path without line suffix for markdown file tag icons", async () => { | ||
| 393 | const fileLink = "[package.json](path/to/package.json:25)"; | ||
| 394 | const screen = await render( | ||
| 395 | <MessagesTimeline | ||
| 396 | {...buildProps()} | ||
| 397 | markdownCwd="/repo/project" | ||
| 398 | timelineEntries={[buildAssistantTimelineEntry(`Updated ${fileLink}`)]} | ||
| 399 | />, | ||
| 400 | ); | ||
| 401 | |||
| 402 | try { | ||
| 403 | const assistantFileLink = document.querySelector( | ||
| 404 | '[data-message-role="assistant"] .chat-markdown-file-link', | ||
| 405 | ); | ||
| 406 | const icon = assistantFileLink?.querySelector("img"); | ||
| 407 | |||
| 408 | expect(assistantFileLink?.textContent).toContain("package.json"); | ||
| 409 | expect(assistantFileLink?.textContent).toContain("L25"); | ||
| 410 | expect(assistantFileLink?.getAttribute("href")).toBe("/repo/project/path/to/package.json:25"); | ||
| 411 | expect(icon?.getAttribute("src")).toBe( | ||
| 412 | getVscodeIconUrlForEntry("/repo/project/path/to/package.json", "file", "dark"), | ||
| 413 | ); | ||
| 414 | } finally { | ||
| 415 | await screen.unmount(); | ||
| 416 | } | ||
| 417 | }); | ||
| 389 | }); | 418 | }); |
apps/web/src/components/ui/toggle.tsx+2| ... | @@ -21,6 +21,8 @@ const toggleVariants = cva( | ... | @@ -21,6 +21,8 @@ const toggleVariants = cva( |
| 21 | }, | 21 | }, |
| 22 | variant: { | 22 | variant: { |
| 23 | default: "border-transparent", | 23 | default: "border-transparent", |
| 24 | ghost: | ||
| 25 | "border-transparent text-foreground shadow-none [:disabled,:active,[data-pressed]]:shadow-none before:shadow-none data-pressed:bg-accent data-pressed:text-accent-foreground disabled:opacity-100 disabled:text-muted-foreground disabled:[&_svg]:opacity-100", | ||
| 24 | outline: | 26 | outline: |
| 25 | "border-input bg-background not-dark:bg-clip-padding shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-input/32 dark:data-pressed:bg-input dark:hover:bg-input/64 dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] dark:not-disabled:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/2%)] [:disabled,:active,[data-pressed]]:shadow-none", | 27 | "border-input bg-background not-dark:bg-clip-padding shadow-xs/5 not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/4%)] dark:bg-input/32 dark:data-pressed:bg-input dark:hover:bg-input/64 dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] dark:not-disabled:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/2%)] [:disabled,:active,[data-pressed]]:shadow-none", |
| 26 | }, | 28 | }, |
pnpm-lock.yaml+71-52| ... | @@ -371,8 +371,8 @@ importers: | ... | @@ -371,8 +371,8 @@ importers: |
| 371 | apps/server: | 371 | apps/server: |
| 372 | dependencies: | 372 | dependencies: |
| 373 | '@anthropic-ai/claude-agent-sdk': | 373 | '@anthropic-ai/claude-agent-sdk': |
| 374 | specifier: ^0.3.154 | 374 | specifier: ^0.3.170 |
| 375 | version: 0.3.159(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3) | 375 | version: 0.3.170(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3) |
| 376 | '@effect/platform-bun': | 376 | '@effect/platform-bun': |
| 377 | specifier: 4.0.0-beta.78 | 377 | specifier: 4.0.0-beta.78 |
| 378 | version: 4.0.0-beta.78(bufferutil@4.1.0)(effect@4.0.0-beta.78(patch_hash=883249d8efbb462e928e21fefef96027b66aec50751178cafdce45f08eee3754))(utf-8-validate@6.0.6) | 378 | version: 4.0.0-beta.78(bufferutil@4.1.0)(effect@4.0.0-beta.78(patch_hash=883249d8efbb462e928e21fefef96027b66aec50751178cafdce45f08eee3754))(utf-8-validate@6.0.6) |
| ... | @@ -854,48 +854,48 @@ packages: | ... | @@ -854,48 +854,48 @@ packages: |
| 854 | '@alchemy.run/node-utils@0.0.4': | 854 | '@alchemy.run/node-utils@0.0.4': |
| 855 | resolution: {integrity: sha512-TiIhPXCTCi3tk0zmdYJJ14CNSesSfsJxXdIOP0HTSItQ1mZWLocrF7qCuEWKyW/IEFzp6kaiOf19aIA/mbCp1g==} | 855 | resolution: {integrity: sha512-TiIhPXCTCi3tk0zmdYJJ14CNSesSfsJxXdIOP0HTSItQ1mZWLocrF7qCuEWKyW/IEFzp6kaiOf19aIA/mbCp1g==} |
| 856 | 856 | ||
| 857 | '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.159': | 857 | '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.170': |
| 858 | resolution: {integrity: sha512-3nnH4yUNJVSyaU5DBlGw2yxc4zlnVvAnc9UOe+La47QVG7/dN+rWAgn4zCbqKk9bWFLDQ1Ek0r56EZE1Qo4UKQ==} | 858 | resolution: {integrity: sha512-rwfgArIa5WI0QPNqFsRBgvtSI0mrtpynUm0oK6+l6/KX4hcgnYGEzciZR1bOeD9/7sSZlTdIgt+T9alKeZmXcg==} |
| 859 | cpu: [arm64] | 859 | cpu: [arm64] |
| 860 | os: [darwin] | 860 | os: [darwin] |
| 861 | 861 | ||
| 862 | '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.159': | 862 | '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.170': |
| 863 | resolution: {integrity: sha512-iv+NRjz+t4Q1R2+kLdDbccSo3b0wedVJ9jMT3noznOVojZHzgkxVpTvt36/XkXV0rqIDQ5H18bBYIZZzOXu7mg==} | 863 | resolution: {integrity: sha512-0e58h8UQMtsQxLGIv9r4foxfBFWKZ7NeDtoplLhuD7EwQonehomw1sBXCch77t/IfUS+q5vQ5zv+fOGmap5nLQ==} |
| 864 | cpu: [x64] | 864 | cpu: [x64] |
| 865 | os: [darwin] | 865 | os: [darwin] |
| 866 | 866 | ||
| 867 | '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.159': | 867 | '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.170': |
| 868 | resolution: {integrity: sha512-WvwiQBWt3tdu5EwqjpDZszI6p2uetYsw4Cxc6ptO/SmLIYXcDienP8nmirZdsZrS+Gzk6imgY0IY5mmNaRhelQ==} | 868 | resolution: {integrity: sha512-SRYfQcsXlOq+CD/FqkQBTSHbaD++w73GnnO+NUV9adLYrca3kfetRwWT1iguY1cNS0l34dCR3rlzCPq78vg1Jg==} |
| 869 | cpu: [arm64] | 869 | cpu: [arm64] |
| 870 | os: [linux] | 870 | os: [linux] |
| 871 | 871 | ||
| 872 | '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.159': | 872 | '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.170': |
| 873 | resolution: {integrity: sha512-FlsS5M4GCpzsQVaNDFF8dRgFGR3QwyAHZFl/xM/2Y2BqVBH+NH17RpKQSJxr1qr41QnsNkinMnu2iSKoc33hKg==} | 873 | resolution: {integrity: sha512-gLbaFqcGppFJQd4DLNV4IXoeahejT/p2/M8bSSvRDbla9GOsBr1AxV5XLRyBn1e7xFGozZIAIQr3+1chp7NJgQ==} |
| 874 | cpu: [arm64] | 874 | cpu: [arm64] |
| 875 | os: [linux] | 875 | os: [linux] |
| 876 | 876 | ||
| 877 | '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.159': | 877 | '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.170': |
| 878 | resolution: {integrity: sha512-kFH6RC2YJbPc8XWRNy/wL4YU7LzdJjSwAdH488sVzIif3q+TrvVrV5y/IW0+MLmta+CKIqtFYpGaucsJYvj7Eg==} | 878 | resolution: {integrity: sha512-m4+I0qBEk7cxRKS+pL+eoWXbXTFOAo83fQ0tQvap4z/mDMm06IWJtEPoYTaMBwsp32GJWLkHWKbZSBCHZnp2DQ==} |
| 879 | cpu: [x64] | 879 | cpu: [x64] |
| 880 | os: [linux] | 880 | os: [linux] |
| 881 | 881 | ||
| 882 | '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.159': | 882 | '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.170': |
| 883 | resolution: {integrity: sha512-uNPEC/iRzVb4bEdzs0KAz1zV7i1PVGEZZnJTQyi1OtgVa81sAoH/H0CbbzDiTsquKdaESf+1DSSEkUlfZmMUEw==} | 883 | resolution: {integrity: sha512-Xl/m7TaSC3T5IDBdHrZQ9fCQYyDmPELN34CL+MoyPIf7uSmuZnjE9fUOqDh2Rv26JxWssi1M6X+BBvVuKd6Cpg==} |
| 884 | cpu: [x64] | 884 | cpu: [x64] |
| 885 | os: [linux] | 885 | os: [linux] |
| 886 | 886 | ||
| 887 | '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.159': | 887 | '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.170': |
| 888 | resolution: {integrity: sha512-WN1QEZGgWXz9GMl61QU6j9E+LEF5plki87bL2xsGwuCPzK+OeVPQU55pabuP8P+vFBFHUo3Y9OlTVyZHnUzmAQ==} | 888 | resolution: {integrity: sha512-IG+8isJNNJKbnnhO7m+PGhfVCg+XoQ/MDxGde5eigFI0WsEfitjuWSWwx82bT9ghxI1aa6qNvI+UPgPcZuo5Fg==} |
| 889 | cpu: [arm64] | 889 | cpu: [arm64] |
| 890 | os: [win32] | 890 | os: [win32] |
| 891 | 891 | ||
| 892 | '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.159': | 892 | '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.170': |
| 893 | resolution: {integrity: sha512-Ty4seccD+dTDX5hhj89IUELZd/LkxO5O43Uiz5Mo8ZJktoX38SK4XMZlBS935QdqTFLRvPL0hvK4Lt4dTOqzPw==} | 893 | resolution: {integrity: sha512-7cuqSKbHVItPGVwRbd3A0BEJwcNtc7Fhoh6qHN4C6yrmjSrvdYYx3MLvq/VI768/RoG7mAMDxb+j7WfEfoP9BA==} |
| 894 | cpu: [x64] | 894 | cpu: [x64] |
| 895 | os: [win32] | 895 | os: [win32] |
| 896 | 896 | ||
| 897 | '@anthropic-ai/claude-agent-sdk@0.3.159': | 897 | '@anthropic-ai/claude-agent-sdk@0.3.170': |
| 898 | resolution: {integrity: sha512-Xh1oVMIK6N3KsiNIhqNH8ZK90zjRmAEL9d1Md8ZlGdHJE+HhdMYdBadujc3KEkV0uufsEUvYp+A3fDenfypGSA==} | 898 | resolution: {integrity: sha512-pAvhfk+iTodXZ6RF18Kz7BEUWFjL7EcR3tKuhUNdPpE1NAYCR3mSHGbafi72JsrNwKEDIs7FU31z3fqhwy8QzA==} |
| 899 | engines: {node: '>=18.0.0'} | 899 | engines: {node: '>=18.0.0'} |
| 900 | peerDependencies: | 900 | peerDependencies: |
| 901 | '@anthropic-ai/sdk': '>=0.93.0' | 901 | '@anthropic-ai/sdk': '>=0.93.0' |
| ... | @@ -2809,6 +2809,12 @@ packages: | ... | @@ -2809,6 +2809,12 @@ packages: |
| 2809 | '@emnapi/core': ^1.7.1 | 2809 | '@emnapi/core': ^1.7.1 |
| 2810 | '@emnapi/runtime': ^1.7.1 | 2810 | '@emnapi/runtime': ^1.7.1 |
| 2811 | 2811 | ||
| 2812 | '@napi-rs/wasm-runtime@1.1.5': | ||
| 2813 | resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} | ||
| 2814 | peerDependencies: | ||
| 2815 | '@emnapi/core': ^1.7.1 | ||
| 2816 | '@emnapi/runtime': ^1.7.1 | ||
| 2817 | |||
| 2812 | '@neon-rs/load@0.0.4': | 2818 | '@neon-rs/load@0.0.4': |
| 2813 | resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} | 2819 | resolution: {integrity: sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw==} |
| 2814 | 2820 | ||
| ... | @@ -6534,8 +6540,8 @@ packages: | ... | @@ -6534,8 +6540,8 @@ packages: |
| 6534 | hoist-non-react-statics@3.3.2: | 6540 | hoist-non-react-statics@3.3.2: |
| 6535 | resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} | 6541 | resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} |
| 6536 | 6542 | ||
| 6537 | hono@4.12.23: | 6543 | hono@4.12.25: |
| 6538 | resolution: {integrity: sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==} | 6544 | resolution: {integrity: sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==} |
| 6539 | engines: {node: '>=16.9.0'} | 6545 | engines: {node: '>=16.9.0'} |
| 6540 | 6546 | ||
| 6541 | hosted-git-info@4.1.0: | 6547 | hosted-git-info@4.1.0: |
| ... | @@ -7689,6 +7695,10 @@ packages: | ... | @@ -7689,6 +7695,10 @@ packages: |
| 7689 | obug@2.1.1: | 7695 | obug@2.1.1: |
| 7690 | resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} | 7696 | resolution: {integrity: sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ==} |
| 7691 | 7697 | ||
| 7698 | obug@2.1.2: | ||
| 7699 | resolution: {integrity: sha512-AWGB9WFcRXOQs48Z/udjI5ZcZMHXwX8XPByNpOydgcGsDLIzjGizhoMWJyKAWze7AVW/2W1i+/gPX4YtKe5cyg==} | ||
| 7700 | engines: {node: '>=12.20.0'} | ||
| 7701 | |||
| 7692 | ofetch@1.5.1: | 7702 | ofetch@1.5.1: |
| 7693 | resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} | 7703 | resolution: {integrity: sha512-2W4oUZlVaqAPAil6FUg/difl6YhqhUR7x2eZY4bQCko22UXg3hptq9KLQdqFClV+Wu85UX7hNtdGTngi/1BxcA==} |
| 7694 | 7704 | ||
| ... | @@ -8627,8 +8637,8 @@ packages: | ... | @@ -8627,8 +8637,8 @@ packages: |
| 8627 | resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} | 8637 | resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} |
| 8628 | engines: {node: '>= 0.4'} | 8638 | engines: {node: '>= 0.4'} |
| 8629 | 8639 | ||
| 8630 | side-channel@1.1.0: | 8640 | side-channel@1.1.1: |
| 8631 | resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} | 8641 | resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} |
| 8632 | engines: {node: '>= 0.4'} | 8642 | engines: {node: '>= 0.4'} |
| 8633 | 8643 | ||
| 8634 | siginfo@2.0.0: | 8644 | siginfo@2.0.0: |
| ... | @@ -9673,44 +9683,44 @@ snapshots: | ... | @@ -9673,44 +9683,44 @@ snapshots: |
| 9673 | 9683 | ||
| 9674 | '@alchemy.run/node-utils@0.0.4': {} | 9684 | '@alchemy.run/node-utils@0.0.4': {} |
| 9675 | 9685 | ||
| 9676 | '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.159': | 9686 | '@anthropic-ai/claude-agent-sdk-darwin-arm64@0.3.170': |
| 9677 | optional: true | 9687 | optional: true |
| 9678 | 9688 | ||
| 9679 | '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.159': | 9689 | '@anthropic-ai/claude-agent-sdk-darwin-x64@0.3.170': |
| 9680 | optional: true | 9690 | optional: true |
| 9681 | 9691 | ||
| 9682 | '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.159': | 9692 | '@anthropic-ai/claude-agent-sdk-linux-arm64-musl@0.3.170': |
| 9683 | optional: true | 9693 | optional: true |
| 9684 | 9694 | ||
| 9685 | '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.159': | 9695 | '@anthropic-ai/claude-agent-sdk-linux-arm64@0.3.170': |
| 9686 | optional: true | 9696 | optional: true |
| 9687 | 9697 | ||
| 9688 | '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.159': | 9698 | '@anthropic-ai/claude-agent-sdk-linux-x64-musl@0.3.170': |
| 9689 | optional: true | 9699 | optional: true |
| 9690 | 9700 | ||
| 9691 | '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.159': | 9701 | '@anthropic-ai/claude-agent-sdk-linux-x64@0.3.170': |
| 9692 | optional: true | 9702 | optional: true |
| 9693 | 9703 | ||
| 9694 | '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.159': | 9704 | '@anthropic-ai/claude-agent-sdk-win32-arm64@0.3.170': |
| 9695 | optional: true | 9705 | optional: true |
| 9696 | 9706 | ||
| 9697 | '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.159': | 9707 | '@anthropic-ai/claude-agent-sdk-win32-x64@0.3.170': |
| 9698 | optional: true | 9708 | optional: true |
| 9699 | 9709 | ||
| 9700 | '@anthropic-ai/claude-agent-sdk@0.3.159(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3)': | 9710 | '@anthropic-ai/claude-agent-sdk@0.3.170(@anthropic-ai/sdk@0.93.0(zod@4.4.3))(@modelcontextprotocol/sdk@1.29.0(zod@4.4.3))(zod@4.4.3)': |
| 9701 | dependencies: | 9711 | dependencies: |
| 9702 | '@anthropic-ai/sdk': 0.93.0(zod@4.4.3) | 9712 | '@anthropic-ai/sdk': 0.93.0(zod@4.4.3) |
| 9703 | '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) | 9713 | '@modelcontextprotocol/sdk': 1.29.0(zod@4.4.3) |
| 9704 | zod: 4.4.3 | 9714 | zod: 4.4.3 |
| 9705 | optionalDependencies: | 9715 | optionalDependencies: |
| 9706 | '@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.159 | 9716 | '@anthropic-ai/claude-agent-sdk-darwin-arm64': 0.3.170 |
| 9707 | '@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.159 | 9717 | '@anthropic-ai/claude-agent-sdk-darwin-x64': 0.3.170 |
| 9708 | '@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.159 | 9718 | '@anthropic-ai/claude-agent-sdk-linux-arm64': 0.3.170 |
| 9709 | '@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.159 | 9719 | '@anthropic-ai/claude-agent-sdk-linux-arm64-musl': 0.3.170 |
| 9710 | '@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.159 | 9720 | '@anthropic-ai/claude-agent-sdk-linux-x64': 0.3.170 |
| 9711 | '@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.159 | 9721 | '@anthropic-ai/claude-agent-sdk-linux-x64-musl': 0.3.170 |
| 9712 | '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.159 | 9722 | '@anthropic-ai/claude-agent-sdk-win32-arm64': 0.3.170 |
| 9713 | '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.159 | 9723 | '@anthropic-ai/claude-agent-sdk-win32-x64': 0.3.170 |
| 9714 | 9724 | ||
| 9715 | '@anthropic-ai/sdk@0.93.0(zod@4.4.3)': | 9725 | '@anthropic-ai/sdk@0.93.0(zod@4.4.3)': |
| 9716 | dependencies: | 9726 | dependencies: |
| ... | @@ -11606,9 +11616,9 @@ snapshots: | ... | @@ -11606,9 +11616,9 @@ snapshots: |
| 11606 | 11616 | ||
| 11607 | '@formkit/auto-animate@0.9.0': {} | 11617 | '@formkit/auto-animate@0.9.0': {} |
| 11608 | 11618 | ||
| 11609 | '@hono/node-server@1.19.14(hono@4.12.23)': | 11619 | '@hono/node-server@1.19.14(hono@4.12.25)': |
| 11610 | dependencies: | 11620 | dependencies: |
| 11611 | hono: 4.12.23 | 11621 | hono: 4.12.25 |
| 11612 | 11622 | ||
| 11613 | '@img/colour@1.1.0': | 11623 | '@img/colour@1.1.0': |
| 11614 | optional: true | 11624 | optional: true |
| ... | @@ -12031,7 +12041,7 @@ snapshots: | ... | @@ -12031,7 +12041,7 @@ snapshots: |
| 12031 | 12041 | ||
| 12032 | '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': | 12042 | '@modelcontextprotocol/sdk@1.29.0(zod@4.4.3)': |
| 12033 | dependencies: | 12043 | dependencies: |
| 12034 | '@hono/node-server': 1.19.14(hono@4.12.23) | 12044 | '@hono/node-server': 1.19.14(hono@4.12.25) |
| 12035 | ajv: 8.20.0 | 12045 | ajv: 8.20.0 |
| 12036 | ajv-formats: 3.0.1(ajv@8.20.0) | 12046 | ajv-formats: 3.0.1(ajv@8.20.0) |
| 12037 | content-type: 1.0.5 | 12047 | content-type: 1.0.5 |
| ... | @@ -12041,7 +12051,7 @@ snapshots: | ... | @@ -12041,7 +12051,7 @@ snapshots: |
| 12041 | eventsource-parser: 3.1.0 | 12051 | eventsource-parser: 3.1.0 |
| 12042 | express: 5.2.1 | 12052 | express: 5.2.1 |
| 12043 | express-rate-limit: 8.5.2(express@5.2.1) | 12053 | express-rate-limit: 8.5.2(express@5.2.1) |
| 12044 | hono: 4.12.23 | 12054 | hono: 4.12.25 |
| 12045 | jose: 6.2.3 | 12055 | jose: 6.2.3 |
| 12046 | json-schema-typed: 8.0.2 | 12056 | json-schema-typed: 8.0.2 |
| 12047 | pkce-challenge: 5.0.1 | 12057 | pkce-challenge: 5.0.1 |
| ... | @@ -12085,6 +12095,13 @@ snapshots: | ... | @@ -12085,6 +12095,13 @@ snapshots: |
| 12085 | '@tybys/wasm-util': 0.10.2 | 12095 | '@tybys/wasm-util': 0.10.2 |
| 12086 | optional: true | 12096 | optional: true |
| 12087 | 12097 | ||
| 12098 | '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': | ||
| 12099 | dependencies: | ||
| 12100 | '@emnapi/core': 1.10.0 | ||
| 12101 | '@emnapi/runtime': 1.10.0 | ||
| 12102 | '@tybys/wasm-util': 0.10.2 | ||
| 12103 | optional: true | ||
| 12104 | |||
| 12088 | '@neon-rs/load@0.0.4': {} | 12105 | '@neon-rs/load@0.0.4': {} |
| 12089 | 12106 | ||
| 12090 | '@noble/curves@1.9.1': | 12107 | '@noble/curves@1.9.1': |
| ... | @@ -12603,7 +12620,7 @@ snapshots: | ... | @@ -12603,7 +12620,7 @@ snapshots: |
| 12603 | '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) | 12620 | '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7) |
| 12604 | '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) | 12621 | '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7) |
| 12605 | '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7) | 12622 | '@babel/plugin-transform-react-display-name': 7.29.7(@babel/core@7.29.7) |
| 12606 | '@babel/plugin-transform-react-jsx': 7.28.6(@babel/core@7.29.7) | 12623 | '@babel/plugin-transform-react-jsx': 7.29.7(@babel/core@7.29.7) |
| 12607 | '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) | 12624 | '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) |
| 12608 | '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) | 12625 | '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) |
| 12609 | '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7) | 12626 | '@babel/plugin-transform-regenerator': 7.29.7(@babel/core@7.29.7) |
| ... | @@ -12818,7 +12835,7 @@ snapshots: | ... | @@ -12818,7 +12835,7 @@ snapshots: |
| 12818 | dependencies: | 12835 | dependencies: |
| 12819 | '@emnapi/core': 1.10.0 | 12836 | '@emnapi/core': 1.10.0 |
| 12820 | '@emnapi/runtime': 1.10.0 | 12837 | '@emnapi/runtime': 1.10.0 |
| 12821 | '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) | 12838 | '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) |
| 12822 | optional: true | 12839 | optional: true |
| 12823 | 12840 | ||
| 12824 | '@rolldown/binding-wasm32-wasi@1.0.1': | 12841 | '@rolldown/binding-wasm32-wasi@1.0.1': |
| ... | @@ -12832,7 +12849,7 @@ snapshots: | ... | @@ -12832,7 +12849,7 @@ snapshots: |
| 12832 | dependencies: | 12849 | dependencies: |
| 12833 | '@emnapi/core': 1.10.0 | 12850 | '@emnapi/core': 1.10.0 |
| 12834 | '@emnapi/runtime': 1.10.0 | 12851 | '@emnapi/runtime': 1.10.0 |
| 12835 | '@napi-rs/wasm-runtime': 1.1.4(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) | 12852 | '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) |
| 12836 | optional: true | 12853 | optional: true |
| 12837 | 12854 | ||
| 12838 | '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': | 12855 | '@rolldown/binding-win32-arm64-msvc@1.0.0-rc.17': |
| ... | @@ -15896,7 +15913,7 @@ snapshots: | ... | @@ -15896,7 +15913,7 @@ snapshots: |
| 15896 | dependencies: | 15913 | dependencies: |
| 15897 | react-is: 16.13.1 | 15914 | react-is: 16.13.1 |
| 15898 | 15915 | ||
| 15899 | hono@4.12.23: {} | 15916 | hono@4.12.25: {} |
| 15900 | 15917 | ||
| 15901 | hosted-git-info@4.1.0: | 15918 | hosted-git-info@4.1.0: |
| 15902 | dependencies: | 15919 | dependencies: |
| ... | @@ -17258,6 +17275,8 @@ snapshots: | ... | @@ -17258,6 +17275,8 @@ snapshots: |
| 17258 | 17275 | ||
| 17259 | obug@2.1.1: {} | 17276 | obug@2.1.1: {} |
| 17260 | 17277 | ||
| 17278 | obug@2.1.2: {} | ||
| 17279 | |||
| 17261 | ofetch@1.5.1: | 17280 | ofetch@1.5.1: |
| 17262 | dependencies: | 17281 | dependencies: |
| 17263 | destr: 2.0.5 | 17282 | destr: 2.0.5 |
| ... | @@ -17645,7 +17664,7 @@ snapshots: | ... | @@ -17645,7 +17664,7 @@ snapshots: |
| 17645 | 17664 | ||
| 17646 | qs@6.15.2: | 17665 | qs@6.15.2: |
| 17647 | dependencies: | 17666 | dependencies: |
| 17648 | side-channel: 1.1.0 | 17667 | side-channel: 1.1.1 |
| 17649 | 17668 | ||
| 17650 | query-string@7.1.3: | 17669 | query-string@7.1.3: |
| 17651 | dependencies: | 17670 | dependencies: |
| ... | @@ -18439,7 +18458,7 @@ snapshots: | ... | @@ -18439,7 +18458,7 @@ snapshots: |
| 18439 | object-inspect: 1.13.4 | 18458 | object-inspect: 1.13.4 |
| 18440 | side-channel-map: 1.0.1 | 18459 | side-channel-map: 1.0.1 |
| 18441 | 18460 | ||
| 18442 | side-channel@1.1.0: | 18461 | side-channel@1.1.1: |
| 18443 | dependencies: | 18462 | dependencies: |
| 18444 | es-errors: 1.3.0 | 18463 | es-errors: 1.3.0 |
| 18445 | object-inspect: 1.13.4 | 18464 | object-inspect: 1.13.4 |
| ... | @@ -19071,7 +19090,7 @@ snapshots: | ... | @@ -19071,7 +19090,7 @@ snapshots: |
| 19071 | es-module-lexer: 2.1.0 | 19090 | es-module-lexer: 2.1.0 |
| 19072 | expect-type: 1.3.0 | 19091 | expect-type: 1.3.0 |
| 19073 | magic-string: 0.30.21 | 19092 | magic-string: 0.30.21 |
| 19074 | obug: 2.1.1 | 19093 | obug: 2.1.2 |
| 19075 | pathe: 2.0.3 | 19094 | pathe: 2.0.3 |
| 19076 | picomatch: 4.0.4 | 19095 | picomatch: 4.0.4 |
| 19077 | std-env: 4.1.0 | 19096 | std-env: 4.1.0 |