0.2.9#239
Merged
Merged
Conversation
When the user selects a sub-folder of a git repository as the workspace root, the GUI used to show "未检测到 Git" even though the folder is clearly inside a git working tree. Root cause: getGitBranches / switchGitBranch / createAndSwitchGitBranch in src/main/services/git-service.ts used `git rev-parse --show-toplevel` to resolve the cwd. That command does walk up the tree on its own, but the rest of getGitBranches also calls `git branch --format=%(refname:short)` (requires git 2.28+) and matches a very narrow set of error messages in gitFailure(). Older git binaries or unrecognised error strings therefore fall through to reason 'error', and the renderer falls back to the 'gitBranchUnavailable' label. This change adds a pure-Node walk-up in src/main/services/git-discovery.ts that mirrors the upward search git does internally. resolveGitCwd() in git-service.ts runs it first and passes the discovered repo root to all subsequent git invocations. When the walker cannot find a .git ancestor, the original trimmed workspaceRoot is used, so behavior for non-repo paths is unchanged. Closes #98 Validation: - npm run typecheck (tsconfig.web + tsconfig.node) - npm run test (105 files / 651 tests pass, including 9 new tests in git-discovery.test.ts) - manual scenarios covered by tests: subdir, deep nesting, .git-as-file (worktree), multiple nested .git, relative path, non-existent path, empty string
…space roots (issue #98) Adds 7 integration tests in src/main/services/git-service.test.ts that exercise the real `git` binary in a temp repository. The headline test asserts that `getGitBranches(<5-levels-deep>)` returns `ok: true` with `repositoryRoot === <repoRoot>` — the exact behaviour reported as broken in #98. This was requested in PR review by @XingYu-Zhong to prove the fix works at the public entry point, not just inside the findNearestGitRoot unit helper.
…sage - agent-loop: filter toolSpecs in plan mode — read-only tools + create_plan during investigation, only create_plan when plan is owed (fixes comment at L598-601 that described this behavior but wasn't implemented) - workbench-plan-controller: default new plan turns to 'draft' instead of auto-detecting 'refine' from the active plan, so each composer send starts a fresh plan - use-timeline-scroll: force stick-to-bottom when currentTurnUserId changes, so new user messages auto-scroll into view even when the user had previously scrolled up Refs #93
- Remove bash from PLAN_READ_ONLY_TOOL_NAMES — bash policy is on-request which auto-approves under approvalPolicy: auto, making it a mutation vector during plan investigation - Extract resolvePlanModeToolSpecs as an exported pure function for testability without full AgentLoop mock infrastructure - Add agent-loop.test.ts with 7 cases covering all filtering phases (step 0, step > 0, plan satisfied, not plan-active, defaults, and custom overrides) Refs #93
The chat route showed the same usage stats twice: the compact SessionHeader in the topbar and the composer footer both rendered tokens / cost / cache-rate for the active thread, each polling the usage endpoints independently. Keep the richer composer footer (it also shows turns and context savings), drop the topbar copy, and skip the usage fetch entirely in compact mode so the duplicate polling goes away too. The non-compact SessionHeader branch is untouched. Also remove the now-orphaned sessionUsageCompact locale key. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
- Add sandbox-policy module: blocks file mutation and host command tools under read-only/external-sandbox, limits writes to the workspace under workspace-write, and hides blocked tools from the advertised catalog. - Thread sandboxMode through StartTurnRequest, ToolHostContext, agent loop, CLI exec context, and tool hooks; persist per-turn approval and sandbox overrides on the thread record. - Finalize persisted open items (tool calls, approvals, user input) in messages.jsonl when a turn completes, fails, or is aborted, and heal stale open items from finished turns when serving thread detail. - Fix output accumulator snapshots to include undecoded buffered bytes in totals so truncation metadata stays accurate mid-stream. - Update approval/sandbox settings copy: changes apply on the next turn. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Chunk usage-event backfill into small transactions with event-loop yields: synchronous better-sqlite3 inserts over a large JSONL history starved the loop and kept KUN_READY from being emitted within the GUI's 15s startup timeout. - Add a usage_backfilled flag column (in-place migration via addColumnIfMissing, default 0) so each thread's events.jsonl is scanned at most once instead of on every boot. - Connect MCP servers in parallel with a 10s per-server startup timeout; a hung stdio server (e.g. npx resolving @latest) no longer blocks the runtime ready signal forever, and late connections are closed. - Cache reconstructed thread records keyed by file signatures and compact metadata.jsonl past 1MB into a single normalized snapshot (atomic tmp+fsync+rename, same line format, old and new readers stay compatible; observed 4.4MB -> 6.3KB, cold get 63ms -> 4ms). Temp file is removed when the rename loses a race on Windows. - Cache prepared statements for the per-event high-water and usage insert hot paths. - postinstall: fetch the Electron-ABI better-sqlite3 prebuild (verified published for darwin/win32/linux x64+arm64); Kun is spawned via ELECTRON_RUN_AS_NODE and could never load the node-ABI build, so it silently fell back to JSONL scanning. Failure only warns and keeps the fallback. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Main process now sends one runtime:sse-event IPC message per network
chunk instead of one structured-clone send per token delta.
- Renderer coalesces consecutive assistant text/reasoning deltas from a
batch into a single sink.onDeltas call (one store update and React
commit per chunk instead of per token) and reports onSeq once per
batch.
- Keep a fallback for the legacy single-event { data } payload so a
stale main/renderer pair during dev reload degrades gracefully.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
- Subscribe WriteWorkspaceView, WriteSidebar, and WriteAssistantPanel to the write store with useShallow field selectors so typing no longer re-renders the file tree and assistant panel. - Deduplicate selection updates (new write-selection equality helper, applied in both the editor push and store setSelection); plain typing stops broadcasting fresh empty-selection objects. - Serialize the editor document at most once per update and skip the round-trip doc comparison when the store value came from our own onChange emit. - Build inline-completion context from cursor windows instead of copying the full document prefix/suffix; request payloads keep the same windowed semantics. - Cache fenced-code/table block ranges in the live-preview state field: plain edits map cached ranges through the change set, only edits that touch block structure rescan the document, and the view plugin reuses the cache instead of scanning from line 1 per update. - Scale the preview debounce with document size (60ms under 30k chars, up to 500ms past 300k). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…fidelity gate Add a Tiptap 3 (ProseMirror) rich-text engine for the write workspace, SDD requirement drafts, and the plan panel, with the existing CodeMirror editor retained as source mode and as the automatic fallback: - Per-file fidelity gate: every externally loaded document is audited (round-trip idempotence + plain-text preservation); failing files fall back to CodeMirror with a notice so files on disk are never silently rewritten. Pure browsing never saves. - Markdown projection layer maps ProseMirror positions to markdown-shaped text offsets, letting inline AI reuse the existing completion context/policy/scoring modules and IPC contracts unchanged. - Inline AI parity: ghost-text completions (Tab/Esc, short/long modes, cooldowns), edit-action diff preview, inline edit via projected scopes, recent-edits from PM transactions. - External disk edits (agent writes) sync as minimal block-level diffs, preserving cursor and undo history without rewrite loops. - Term propagation and @Date template shortcuts ported as ProseMirror plugins; local image NodeView and clipboard image paste reuse the existing workspace IPC. - Default preview mode switches to rich; stored user preferences are respected. scripts/tiptap-roundtrip-audit.mjs gates future @tiptap upgrades; see docs/tiptap-migration.md for decisions. Verified end-to-end in the running app: WYSIWYG rendering, typing and autosave serialization, gate fallback on hard-wrapped ordered lists and raw HTML, external-edit sync with stable cursor, live ghost-text completion accepted via Tab, mode switching, undo grouping with term propagation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… blocks
Connect 新建需求, planning, build, and acceptance into one stateful
pipeline instead of three one-way prompt handoffs:
- Requirement blocks: `### R-n: title {status}` headings with
acceptance checklists, parsed by a shared trace layer
(src/shared/sdd-trace.ts). Status tokens render as colored pills
in the rich editor (raw token revealed while the cursor is on the
heading) and a progress bar sits above the SDD draft editor.
- Covers anchoring: the draft-to-plan prompt now requires every plan
step to carry `(covers: R-n)` tags; the plan panel shows a
coverage chip plus an uncovered-requirements warning.
- Status feedback: a trace loop aggregates the requirement file, the
plan's covers tags, and live thread todo statuses, then writes
forward-only status transitions (planned/building/done) back into
requirement.md - through the draft store while editing, straight
to disk otherwise, with a slow refresh pulse for agent edits.
- Acceptance turn: a 验收 button sends an agent turn that verifies
each acceptance criterion and updates checkboxes plus {verified}
tokens in place.
- Drift detection: a trace.json baseline (written when 下一步
generates the plan and re-baselined on replan) powers a banner
naming changed requirement ids with one-click incremental
replanning that feeds only the changed blocks into a refine turn.
- AI structuring action in the requirement assistant rewrites a
free-form draft into R blocks with acceptance criteria.
Verified live end-to-end against the running app with a real model:
plan generated with covers tags on every step and a coverage matrix,
statuses auto-flipped to planned, checking a plan checkbox flipped
the requirement to building, editing a requirement raised the drift
banner, and incremental replan propagated the change, kept all
covers tags, and cleared the banner.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…and write Kun runtime gains a generate_image tool behind a new capabilities.imageGen config block (baseUrl/apiKey/model, OpenAI-compatible /images/generations and /images/edits with b64/url and response_format fallbacks). Generated images are saved under .deepseekgui-images/ in the workspace and stored as thread-scoped attachments so the chat timeline renders inline previews without any marker hacks. Reference images (image-to-image) are validated as workspace-contained png/jpeg/webp. GUI side: - Settings → Agents gains an "Image generation" card; values flow settings → kun config.json capabilities.imageGen, with the capability whitelisted in the config sanitizer to avoid a kun restart loop (guarded by an idempotency test) - Tool result cards lift output.attachments into meta and render thumbnails via the existing attachment preview path - Write workspace: selecting text shows a "Generate infographic" button (only when the provider is configured); the infographic is generated by the main process reusing kun's OpenAiCompatImageClient, saved next to the document under assets/, and inserted below the selection in both plain and rich editors Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix: remove duplicate usage stats from chat topbar
fix(git): walk up directory tree to find nearest .git root (fixes #98)
…sage (#167) fix: enforce plan-mode tool isolation and auto-scroll on new user message
- fix invalid 'discovery' toolKind in agent-loop.test.ts (kun typecheck) - drop render-phase stick-to-bottom block duplicated by the existing userTurnKey effect that landed on develop before the merge - remove dead planTurnOverrides wrapper left after draft-by-default Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Disable GUI input tools for IM/headless turns so remote-channel users are not blocked on unavailable prompts. Send and persist one-time welcome messages for Feishu and WeChat channels.
Root cause chain: after a kun restart the SSE heartbeat allocated seqs from the empty in-memory bus (1, 2, 3...), the renderer's onSeq overwrote lastSeq unconditionally, and the next send subscribed with that rewound cursor — replaying the whole persisted thread history into the live bubble, since onDeltas appends without any dedup. - kun events route: per-connection high-water dedup; heartbeats reuse the connection cursor instead of allocating fresh seqs - kun recorder: persist before publish (events could fall between a subscriber's backlog read and bus subscription and be lost), cache the per-thread seq floor (no more full events.jsonl scan per delta, no more duplicate seqs under concurrent records) - renderer: monotonic lastSeq; per-subscription delta floor drops replayed/duplicated deltas in main and side sinks Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Goal continuation re-prompts the model whenever it stops without tool calls; near-identical filler answers could spin that loop forever. Detect repeats via normalized text + character-bigram similarity and end the turn instead of re-prompting. (Recovered from a concurrent working session on this branch.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Abort the event stream and flip busy off immediately on stop, then re-sync via recoverActiveTurn after the runtime acknowledges — a slow or hung interruptTurn no longer leaves the stop button unresponsive. (Recovered from a concurrent working session on this branch.) Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The bus retained every published event (including all streaming deltas) for the process lifetime; SSE replay reads the session store, so the bus only needs a recent tail. Cap retention per thread and track the seq high-water mark in a map instead of scanning the list. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
contextInstructions were sent as system messages ahead of the entire conversation history. The goal-continuation instruction embeds a tokens-used counter that changes every step, and todo/memory/skill notes change between turns — any of those invalidated the provider's prefix cache for the whole thread, which is why measured cache hit rates trailed comparable tools. Trailing the stable history keeps the prefix byte-stable; the Anthropic/messages path hoists system content regardless of position, so behavior there is unchanged. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A tool whose execute threw (e.g. an MCP server returning "MCP error -32603: Validation Failed") propagated out of the tool host and failed the whole turn with "Kun turn failed". Catch non-abort execution errors at the host and hand the model an isError tool result so it can adjust and continue. Also stop tearing down healthy MCP connections for deterministic protocol errors — only transport-looking failures earn the reconnect + retry. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When the watchdog gave up on a turn it cleared busy but left running tool/approval blocks pending, so hasPendingRuntimeWork stayed true and every later message queued forever behind a completion event that would never arrive. Settle stuck blocks in the timeout finalizer and kick the queue drain once the thread is idle again. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Pages whose declared content-length exceeded the byte budget hard failed with "content exceeds N byte limit", and models often pass tiny budgets (2000 bytes was common), which made most real pages unfetchable. Stream and truncate at the cap instead, raise tiny model-passed budgets to a 4 KiB floor, and expose the cap as web.maxFetchBytes in capabilities config. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The WeChat monitor awaited each webhook dispatch (whole agent turn, up to the 650s timeout) inside the long-poll loop, so one slow or stuck turn froze the channel for every chat — and restarting reran the same stuck flow. Dispatch per sender instead: one conversation stays ordered, other chats and polling keep moving. Scheduled-task turns now also pass disableUserInput — they are headless, and an agent asking a user_input question hung the turn until the response timeout. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Fresh installs on slow Windows machines hit the 15s KUN_READY deadline (antivirus cold scans, sqlite rebuilds, MCP connects) and the GUI SIGTERMed a healthy kun mid-boot, leaving "unable to connect to kun" permanently. Poll the unauthenticated /health endpoint in parallel with the stdout marker — the HTTP server is the ground truth and the marker can lag behind pipe buffering — and give startup 45s. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Updated the buildHeaders method to conditionally set the 'Accept' header based on the stream parameter. This change addresses issues with timeouts on Windows Node/Electron paths when routing requests with 'Accept: text/event-stream'. Additionally, added tests to verify the absence of the 'Accept' header when streaming is enabled.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.