文件最后提交记录最后更新时间
feat(approval-prompt): unified PauseRequest→UI data model for ACP, CLI, Desktop (#1322 Phase 3) (#1443) * fix(desktop): sync context token meter after /compact (#1305) Problem: Desktop ContextPanel showed stale token counts after /compact because it relies on per-turn API usage events (model.final) to update cacheHitTokens/cacheMissTokens. /compact is a local operation with no API call, so no usage event fires and the meter never refreshes. Fix (high-cohesion): 1. ContextManager.getLogTokens() — real-time token count of current log. 2. Loop.getCurrentLogTokens() — forwards to ContextManager. 3. Extend \$ctx_breakdown event with optional logTokens field. 4. emitCtxBreakdown() now computes + pushes logTokens alongside reservedTokens, becoming the unified context-refresh entrypoint. 5. compact_history handler calls emitCtxBreakdown(tab) on success so the frontend immediately receives the compressed token count. 6. App.tsx \$ctx_breakdown handler resets cacheHitTokens=0 and cacheMissTokens=logTokens when logTokens is present, calibrating the meter to the actual current context size. This keeps all computation in ContextManager, all emitting in emitCtxBreakdown, and all consumption in App.tsx — no new event types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(core-utils): introduce ApprovalPrompt unified data model (#1322 Phase 3 PR 1) - Add toApprovalPrompt() and resolveApprovalPrompt() in @reasonix/core-utils to serve as the single source of truth for PauseRequest → UI metadata mapping. - Define ApprovalPrompt, ApprovalAction, ApprovalTone, ApprovalPromptKind types with English fallback labels. - Move derivePrefix computation into toApprovalPrompt so all surfaces share one implementation. - Add secondaryInput to ApprovalAction to describe two-phase deny flows. - Replace ACP gates.ts inline mapping with calls to the new unified helpers, deleting duplicated permissionOptionsFor, permissionTitleFor, permissionKindFor, verdictFor, and all ID_* constants. - Update acp.test.ts to use new semantic action IDs (always_allow, etc.). - Add packages/core-utils/tests/**/*.test.ts to vitest include pattern. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(cli): migrate ShellConfirm and PathConfirm to ApprovalPrompt model (#1322 Phase 3 PR 2) - Update ShellConfirm.tsx and PathConfirm.tsx to accept prompt: ApprovalPrompt instead of individual raw fields. - Drive SingleSelect items from prompt.actions instead of hardcoded options. - Trigger deny phase via action.secondaryInput detection instead of hardcoded "deny" value check. - Remove clampCommand, tildeify, and derivePrefix from ShellConfirm/PathConfirm (computed centrally in toApprovalPrompt). - In App.tsx, call toApprovalPrompt() at render time for both shell and path confirmations, removing inline derivePrefix at the component boundary. - Update shell-confirm-render.test.tsx to use ApprovalPrompt fixtures. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(desktop): migrate ConfirmApprovalCard and PathAccessApprovalCard to ApprovalPrompt (#1322 Phase 3 PR 3) - Add @reasonix/core-utils workspace dependency to desktop/package.json. - Extend ConfirmRequiredEvent and PathAccessRequiredEvent with optional prompt: ApprovalPrompt for backward-compatible RPC. - In src/cli/commands/desktop.ts, call toApprovalPrompt() when emitting $confirm_required and $path_access_required events. - Update ConfirmApprovalCard and PathAccessApprovalCard in desktop/src/ui/thread.tsx to consume prompt instead of raw fields. - Drive primary/secondary/tertiary buttons from prompt.actions mapped by kind (allow_once, allow_always, reject). - Map ApprovalPrompt.tone to Desktop ApprovalTone (warn/danger/info/brand). - Remove inline derivePrefix from card components. - Update PendingConfirm and PendingPathAccess types in desktop/src/App.tsx to store prompt, and pass it to the card components at render time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(desktop): add ApprovalPrompt reducer and component tests - Add desktop/src/App.test.ts (5 reducer integration tests) - Add desktop/src/ui/thread.test.tsx (6 component rendering tests) - Install @testing-library/react and jsdom for Desktop component testing - Configure vitest with React aliases to prevent duplicate React copies - Fix tildeify double-slash normalization bug on Windows - Fix ACP gates comment length to pass policy check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(desktop-tests): mock Tauri and lucide-react imports for CI CI installs only root dependencies; desktop-specific deps like @tauri-apps/api and lucide-react are not available in test runners. Add vi.mock() calls to App.test.ts and thread.test.tsx so vitest can resolve these imports without the desktop node_modules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): add vitest aliases for desktop-only dependencies in CI CI installs only root dependencies; desktop-specific packages like lucide-react and @tauri-apps/api are not available. Add mock modules in tests/mocks/ and wire them via resolve.alias in vitest.config.ts so desktop tests can resolve these imports without desktop/node_modules. Also remove redundant vi.mock() calls from App.test.ts and thread.test.tsx since aliases now handle module resolution globally. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(desktop-tests): mock local desktop modules to avoid transitive dep loading App.test.ts imports reduce from App.tsx, which transitively loads CommandPalette, Markdown, and theme modules with desktop-only deps. thread.test.tsx imports from thread.tsx, which loads cards.tsx, which loads Markdown.tsx with react-markdown and other deps. Add vi.mock() for these local module boundaries so tests resolve without needing the full desktop/node_modules dependency tree. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>8 天前
feat(ui): render compacted history as a collapsible card on all three surfaces (#1649) After auto-compaction, the synthesized recap was being stored as a plain assistant message with a HISTORY_FOLD_MARKER prefix. None of the three surfaces special-cased it — TUI hydrated it as a regular streaming card on resume; Desktop and Dashboard rendered it inline through AssistantText. Users had no way to tell compaction had happened or distinguish the recap from a real model reply. - Single-source the marker + helpers in @reasonix/core-utils/compaction (COMPACTION_SUMMARY_MARKER, isCompactionSummary, stripCompactionMarker). Re-export the constant from src/context-manager.ts so existing HISTORY_FOLD_MARKER imports keep resolving. - TUI: new kind: "compaction" in state/cards.ts, renderer in cards/CompactionCard.tsx, hydrate.ts emits it instead of a streaming card when the marker is present. - Desktop / Dashboard: CompactionCard component in ui/cards.tsx, intercepted in the assistant-segment renderer in ui/thread.tsx. Default-collapsed, archive icon, header shows char count, body renders the recap markdown. - Wire vite + tsconfig aliases for the sub-import path so browser bundles don't pull in Node-only siblings (tildeify) via the barrel. Tests: marker detection edge cases in core-utils, hydrate emits compaction card for the marker, full verify (262 files / 3595 tests). Follow-up: surface the loop "warning" event ("folded N messages → M") as a visible row on Desktop / Dashboard (currently flows through protocol, no ChatMessage reducer).5 天前
feat(core-utils): introduce @reasonix/core-utils workspace package (Phase 1) (#1328) Closes #1322 (Phase 1) Co-authored-by: paradoxSCH <sch.paradox@foxmail.com>10 天前
feat(ui): render compacted history as a collapsible card on all three surfaces (#1649) After auto-compaction, the synthesized recap was being stored as a plain assistant message with a HISTORY_FOLD_MARKER prefix. None of the three surfaces special-cased it — TUI hydrated it as a regular streaming card on resume; Desktop and Dashboard rendered it inline through AssistantText. Users had no way to tell compaction had happened or distinguish the recap from a real model reply. - Single-source the marker + helpers in @reasonix/core-utils/compaction (COMPACTION_SUMMARY_MARKER, isCompactionSummary, stripCompactionMarker). Re-export the constant from src/context-manager.ts so existing HISTORY_FOLD_MARKER imports keep resolving. - TUI: new kind: "compaction" in state/cards.ts, renderer in cards/CompactionCard.tsx, hydrate.ts emits it instead of a streaming card when the marker is present. - Desktop / Dashboard: CompactionCard component in ui/cards.tsx, intercepted in the assistant-segment renderer in ui/thread.tsx. Default-collapsed, archive icon, header shows char count, body renders the recap markdown. - Wire vite + tsconfig aliases for the sub-import path so browser bundles don't pull in Node-only siblings (tildeify) via the barrel. Tests: marker detection edge cases in core-utils, hydrate emits compaction card for the marker, full verify (262 files / 3595 tests). Follow-up: surface the loop "warning" event ("folded N messages → M") as a visible row on Desktop / Dashboard (currently flows through protocol, no ChatMessage reducer).5 天前
feat(core-utils): introduce @reasonix/core-utils workspace package (Phase 1) (#1328) Closes #1322 (Phase 1) Co-authored-by: paradoxSCH <sch.paradox@foxmail.com>10 天前
feat(approval-prompt): unified PauseRequest→UI data model for ACP, CLI, Desktop (#1322 Phase 3) (#1443) * fix(desktop): sync context token meter after /compact (#1305) Problem: Desktop ContextPanel showed stale token counts after /compact because it relies on per-turn API usage events (model.final) to update cacheHitTokens/cacheMissTokens. /compact is a local operation with no API call, so no usage event fires and the meter never refreshes. Fix (high-cohesion): 1. ContextManager.getLogTokens() — real-time token count of current log. 2. Loop.getCurrentLogTokens() — forwards to ContextManager. 3. Extend \$ctx_breakdown event with optional logTokens field. 4. emitCtxBreakdown() now computes + pushes logTokens alongside reservedTokens, becoming the unified context-refresh entrypoint. 5. compact_history handler calls emitCtxBreakdown(tab) on success so the frontend immediately receives the compressed token count. 6. App.tsx \$ctx_breakdown handler resets cacheHitTokens=0 and cacheMissTokens=logTokens when logTokens is present, calibrating the meter to the actual current context size. This keeps all computation in ContextManager, all emitting in emitCtxBreakdown, and all consumption in App.tsx — no new event types. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(core-utils): introduce ApprovalPrompt unified data model (#1322 Phase 3 PR 1) - Add toApprovalPrompt() and resolveApprovalPrompt() in @reasonix/core-utils to serve as the single source of truth for PauseRequest → UI metadata mapping. - Define ApprovalPrompt, ApprovalAction, ApprovalTone, ApprovalPromptKind types with English fallback labels. - Move derivePrefix computation into toApprovalPrompt so all surfaces share one implementation. - Add secondaryInput to ApprovalAction to describe two-phase deny flows. - Replace ACP gates.ts inline mapping with calls to the new unified helpers, deleting duplicated permissionOptionsFor, permissionTitleFor, permissionKindFor, verdictFor, and all ID_* constants. - Update acp.test.ts to use new semantic action IDs (always_allow, etc.). - Add packages/core-utils/tests/**/*.test.ts to vitest include pattern. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(cli): migrate ShellConfirm and PathConfirm to ApprovalPrompt model (#1322 Phase 3 PR 2) - Update ShellConfirm.tsx and PathConfirm.tsx to accept prompt: ApprovalPrompt instead of individual raw fields. - Drive SingleSelect items from prompt.actions instead of hardcoded options. - Trigger deny phase via action.secondaryInput detection instead of hardcoded "deny" value check. - Remove clampCommand, tildeify, and derivePrefix from ShellConfirm/PathConfirm (computed centrally in toApprovalPrompt). - In App.tsx, call toApprovalPrompt() at render time for both shell and path confirmations, removing inline derivePrefix at the component boundary. - Update shell-confirm-render.test.tsx to use ApprovalPrompt fixtures. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * feat(desktop): migrate ConfirmApprovalCard and PathAccessApprovalCard to ApprovalPrompt (#1322 Phase 3 PR 3) - Add @reasonix/core-utils workspace dependency to desktop/package.json. - Extend ConfirmRequiredEvent and PathAccessRequiredEvent with optional prompt: ApprovalPrompt for backward-compatible RPC. - In src/cli/commands/desktop.ts, call toApprovalPrompt() when emitting $confirm_required and $path_access_required events. - Update ConfirmApprovalCard and PathAccessApprovalCard in desktop/src/ui/thread.tsx to consume prompt instead of raw fields. - Drive primary/secondary/tertiary buttons from prompt.actions mapped by kind (allow_once, allow_always, reject). - Map ApprovalPrompt.tone to Desktop ApprovalTone (warn/danger/info/brand). - Remove inline derivePrefix from card components. - Update PendingConfirm and PendingPathAccess types in desktop/src/App.tsx to store prompt, and pass it to the card components at render time. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(desktop): add ApprovalPrompt reducer and component tests - Add desktop/src/App.test.ts (5 reducer integration tests) - Add desktop/src/ui/thread.test.tsx (6 component rendering tests) - Install @testing-library/react and jsdom for Desktop component testing - Configure vitest with React aliases to prevent duplicate React copies - Fix tildeify double-slash normalization bug on Windows - Fix ACP gates comment length to pass policy check Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(desktop-tests): mock Tauri and lucide-react imports for CI CI installs only root dependencies; desktop-specific deps like @tauri-apps/api and lucide-react are not available in test runners. Add vi.mock() calls to App.test.ts and thread.test.tsx so vitest can resolve these imports without the desktop node_modules. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(tests): add vitest aliases for desktop-only dependencies in CI CI installs only root dependencies; desktop-specific packages like lucide-react and @tauri-apps/api are not available. Add mock modules in tests/mocks/ and wire them via resolve.alias in vitest.config.ts so desktop tests can resolve these imports without desktop/node_modules. Also remove redundant vi.mock() calls from App.test.ts and thread.test.tsx since aliases now handle module resolution globally. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(desktop-tests): mock local desktop modules to avoid transitive dep loading App.test.ts imports reduce from App.tsx, which transitively loads CommandPalette, Markdown, and theme modules with desktop-only deps. thread.test.tsx imports from thread.tsx, which loads cards.tsx, which loads Markdown.tsx with react-markdown and other deps. Add vi.mock() for these local module boundaries so tests resolve without needing the full desktop/node_modules dependency tree. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>8 天前
feat(core-utils): introduce @reasonix/core-utils workspace package (Phase 1) (#1328) Closes #1322 (Phase 1) Co-authored-by: paradoxSCH <sch.paradox@foxmail.com>10 天前