Compare commits

...

4 Commits

Author SHA1 Message Date
Shantur Rathore
0ef57df3bc fix(ui): show token stats and simplify context window calculation
- Track messageInfoVersion in cache signature to rebuild when tokens arrive via SSE
- Read tokens from step-finish part directly (embedded in SSE events)
- Simplify available tokens to show full context window when no explicit input limit
2026-04-08 22:19:10 +01:00
Shantur Rathore
0739ec857c Reapply "fix(ui): support unified diff patch format in session changes viewer"
This reverts commit af6429162f.
2026-04-08 20:57:23 +01:00
Shantur Rathore
b060ab45ff Revert "feat(tauri): add zip bundle target for macOS and Windows"
This reverts commit 197898c01c.
2026-04-08 20:57:23 +01:00
Shantur Rathore
af6429162f Revert "fix(ui): support unified diff patch format in session changes viewer"
This reverts commit 2e9ee2cde6.
2026-04-08 20:57:12 +01:00
5 changed files with 30 additions and 50 deletions

View File

@@ -378,7 +378,7 @@ jobs:
- name: Build macOS bundle (Tauri)
working-directory: packages/tauri-app
run: npm exec -- tauri build --bundles app,zip
run: npm exec -- tauri build
- name: Package Tauri artifacts (macOS)
if: ${{ inputs.upload || inputs.upload_actions_artifacts }}
@@ -388,9 +388,7 @@ jobs:
ARTIFACT_DIR="packages/tauri-app/release-tauri"
rm -rf "$ARTIFACT_DIR"
mkdir -p "$ARTIFACT_DIR"
if [ -f "$BUNDLE_ROOT/macos/CodeNomad.app.zip" ]; then
mv "$BUNDLE_ROOT/macos/CodeNomad.app.zip" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-macos-x64.zip"
elif [ -d "$BUNDLE_ROOT/macos/CodeNomad.app" ]; then
if [ -d "$BUNDLE_ROOT/macos/CodeNomad.app" ]; then
ditto -ck --sequesterRsrc --keepParent "$BUNDLE_ROOT/macos/CodeNomad.app" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-macos-x64.zip"
fi
@@ -464,7 +462,7 @@ jobs:
- name: Build macOS bundle (Tauri, arm64)
working-directory: packages/tauri-app
run: npm exec -- tauri build --bundles app,zip
run: npm exec -- tauri build
- name: Package Tauri artifacts (macOS arm64)
if: ${{ inputs.upload || inputs.upload_actions_artifacts }}
@@ -474,9 +472,7 @@ jobs:
ARTIFACT_DIR="packages/tauri-app/release-tauri"
rm -rf "$ARTIFACT_DIR"
mkdir -p "$ARTIFACT_DIR"
if [ -f "$BUNDLE_ROOT/macos/CodeNomad.app.zip" ]; then
mv "$BUNDLE_ROOT/macos/CodeNomad.app.zip" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-macos-arm64.zip"
elif [ -d "$BUNDLE_ROOT/macos/CodeNomad.app" ]; then
if [ -d "$BUNDLE_ROOT/macos/CodeNomad.app" ]; then
ditto -ck --sequesterRsrc --keepParent "$BUNDLE_ROOT/macos/CodeNomad.app" "$ARTIFACT_DIR/CodeNomad-Tauri-${VERSION}-macos-arm64.zip"
fi
@@ -553,7 +549,7 @@ jobs:
- name: Build Windows bundle (Tauri)
shell: bash
working-directory: packages/tauri-app
run: npm exec -- tauri build --bundles nsis,zip
run: npm exec -- tauri build
- name: Package Tauri artifacts (Windows)
if: ${{ inputs.upload || inputs.upload_actions_artifacts }}
@@ -563,19 +559,10 @@ jobs:
$artifactDir = "packages/tauri-app/release-tauri"
if (Test-Path $artifactDir) { Remove-Item $artifactDir -Recurse -Force }
New-Item -ItemType Directory -Path $artifactDir | Out-Null
# Use Tauri-generated zip if available
$tauriZip = Get-ChildItem -Path "$bundleRoot/nsis" -Filter "*.zip" -File | Select-Object -First 1
if ($null -ne $tauriZip) {
$exe = Get-ChildItem -Path $bundleRoot -Recurse -File -Filter *.exe | Select-Object -First 1
if ($null -ne $exe) {
$dest = Join-Path $artifactDir ("CodeNomad-Tauri-$env:VERSION-windows-x64.zip")
Move-Item $tauriZip.FullName $dest -Force
} else {
# Fallback: manually zip the exe
$exe = Get-ChildItem -Path $bundleRoot -Recurse -File -Filter *.exe | Select-Object -First 1
if ($null -ne $exe) {
$dest = Join-Path $artifactDir ("CodeNomad-Tauri-$env:VERSION-windows-x64.zip")
Compress-Archive -Path $exe.Directory.FullName -DestinationPath $dest -Force
}
Compress-Archive -Path $exe.Directory.FullName -DestinationPath $dest -Force
}
- name: Upload Actions artifacts (Tauri Windows)
@@ -661,7 +648,7 @@ jobs:
- name: Build Linux bundle (Tauri)
working-directory: packages/tauri-app
run: npm exec -- tauri build --bundles appimage,deb,rpm
run: npm exec -- tauri build
- name: Package Tauri artifacts (Linux)
if: ${{ inputs.upload || inputs.upload_actions_artifacts }}

View File

@@ -11,14 +11,7 @@
"sync:version": "node ./scripts/sync-tauri-version.js",
"prebuild": "node ./scripts/prebuild.js",
"bundle:server": "npm run prebuild",
"build": "tauri build",
"build:mac": "tauri build --target universal-apple-darwin --bundles app,zip",
"build:mac-arm": "tauri build --target aarch64-apple-darwin --bundles app,zip",
"build:mac-intel": "tauri build --target x86_64-apple-darwin --bundles app,zip",
"build:mac-zip": "tauri build --target universal-apple-darwin --bundles zip",
"build:win": "tauri build --bundles nsis,zip",
"build:win-zip": "tauri build --bundles zip",
"build:linux": "tauri build --bundles appimage,deb,rpm"
"build": "tauri build"
},
"devDependencies": {
"@tauri-apps/cli": "^2.9.4"

View File

@@ -53,11 +53,10 @@
],
"targets": [
"app",
"zip",
"appimage",
"deb",
"rpm",
"nsis"
]
}
}
}

View File

@@ -629,13 +629,12 @@ export default function MessageBlock(props: MessageBlockProps) {
const lastAssistantIdx = props.lastAssistantIndex()
const isQueued = current.role === "user" && (lastAssistantIdx === -1 || index > lastAssistantIdx)
// Intentionally untracked: messageInfoVersion updates should not trigger
// a full message block rebuild; record revision is the invalidation key.
const info = untrack(messageInfo)
const messageInfoVersion = props.store().state.messageInfoVersion[current.id] ?? 0
const cacheSignature = [
current.id,
current.revision,
messageInfoVersion,
isQueued ? 1 : 0,
props.showThinking() ? 1 : 0,
props.thinkingDefaultExpanded() ? 1 : 0,
@@ -647,6 +646,9 @@ export default function MessageBlock(props: MessageBlockProps) {
return cachedBlock.block
}
// Only capture info after cache check fails - ensures fresh data on version bump
const info = untrack(messageInfo)
const { orderedParts } = buildRecordDisplayData(props.instanceId, current)
const items: MessageBlockItem[] = []
const blockContentKeys: string[] = []
@@ -1108,17 +1110,23 @@ function StepCard(props: StepCardProps) {
return null
}
const info = props.messageInfo
if (!info || info.role !== "assistant" || !info.tokens) {
const part = props.part as any
// step-finish parts have tokens embedded; also check messageInfo
const partTokens = part?.tokens
const infoTokens = info && info.role === "assistant" ? info.tokens : undefined
const tokens = partTokens ?? infoTokens
if (!tokens) {
return null
}
const tokens = info.tokens
return {
input: tokens.input ?? 0,
output: tokens.output ?? 0,
reasoning: tokens.reasoning ?? 0,
cacheRead: tokens.cache?.read ?? 0,
cacheWrite: tokens.cache?.write ?? 0,
cost: info.cost ?? 0,
cost: (part?.cost ?? (info && info.role === "assistant" ? info.cost : 0)) ?? 0,
}
}

View File

@@ -116,18 +116,11 @@ export function updateSessionInfo(instanceId: string, sessionId: string): void {
// Prefer explicit input limits when provided by the API.
// This is used by the UI "Avail" chip.
contextAvailableTokens = modelInputLimit
}
if (!contextAvailableFromPrevious && contextAvailableTokens === null) {
if (contextWindow > 0) {
if (latestHasContextUsage && actualUsageTokens > 0) {
contextAvailableTokens = Math.max(contextWindow - (actualUsageTokens + outputBudget), 0)
} else {
contextAvailableTokens = contextWindow
}
} else {
contextAvailableTokens = null
}
} else if (contextWindow > 0) {
// When no explicit input limit, show full context window capacity.
contextAvailableTokens = contextWindow
} else {
contextAvailableTokens = null
}
setSessionInfoByInstance((prev) => {