docs(web): refresh v0.8.32 site state

This commit is contained in:
Hunter Bown
2026-05-12 14:04:17 -05:00
parent b25450728e
commit 190eb6b162
10 changed files with 155 additions and 264 deletions
+76 -97
View File
@@ -225,106 +225,85 @@ deepseek --provider ollama --model deepseek-coder:1.3b
---
## What's New In v0.8.29
## What's New In v0.8.32
A maintenance release anchored by a v0.8.27 / v0.8.28 regression fix
plus 25 community PRs. [Full changelog](CHANGELOG.md).
A "more useful tools" release expanding the tool surface for real-world
workflows. Five new tools, ten community PRs targeting model-protocol bugs
and UX papercuts, and a snapshot cap that stops giant workspaces from
hanging the TUI on first turn. [Full changelog](CHANGELOG.md).
- **Scroll demon, gone for good** (#1085 regression). Parallel sub-
agents running `exec_shell` would scroll the alt-screen out from
under ratatui's diff renderer, leaving a blank band growing above
the header. Three layers of defence now: a `tracing-subscriber`
writing to `~/.deepseek/logs/tui-YYYY-MM-DD.log`, an fd-level
`dup2` stderr redirect for the alt-screen lifetime (Unix), and
module-level `#![deny(clippy::print_stdout, clippy::print_stderr)]`
on the TUI runtime modules. New `eprintln!`s inside `tools/`,
`core/`, `tui/`, `network_policy.rs`, or `runtime_threads.rs` now
fail CI.
- **Ctrl+R session restore is workspace-scoped** (#1395, PR #1397 from
**@linzhiqin2003**) — previously listed every saved session on disk,
which meant Project A's history could leak into Project B.
- **Runtime version visible in the header.** A discreet `v0.8.29`
chip sits in the header's right cluster alongside the provider /
effort / Live / context chips. Drops first under tight terminal
width.
- **MCP HTTP transport honors HTTP(S)_PROXY** (#1408 from
**@hlx98007**) — corporate / Clash / Shadowsocks proxies now apply
to MCP HTTP connections, matching every other tool on the box.
`NO_PROXY` honored.
- **MCP discovery survives malformed items** (#1410 from
**@Liu-Vince**) — one bad tool / resource / prompt entry no
longer drops the whole page; the malformed entry is skipped and
the rest of the catalogue surfaces normally.
- **MCP SSE accepts CRLF-framed endpoint events** (#1309, PR #1358
from **@reidliu41**) — FastMCP / uvicorn streams no longer time
out waiting for LF-only event separators.
- **Composer ignores leaked mouse-report bytes** (#1418, PR #1421
from **@reidliu41**) — terminal chains that leak `[<35;44;18M`
style mouse reports into stdin no longer fill the input area.
- **Footer chips respect the available width** (#1357, PR #1417 from
**@Wenjunyun123**) — long cache / aux chips drop before crowding
the left status line or composer area on narrow terminals.
- **Note management commands** (PR #1407 from **@reidliu41**) —
`/note add`, `/note list`, and friends for persistent maintainer
notes inside the TUI.
- **`/init`-style global AGENTS.md merges with project AGENTS.md**
(#1157, PR #1399 from **@linzhiqin2003**) — your `~/.deepseek/
AGENTS.md` baseline now layers under the workspace's own
AGENTS.md instead of being shadowed.
- **Language directive: thinking matches the user's message language**
(#1118, PR #1398 from **@linzhiqin2003**) — `reasoning_content`
follows the latest user message language, not the project context's
inferred `lang`.
- **Web search filters spam-stuffed SERPs** (#964, PR #1396 from
**@linzhiqin2003**) — Bing / DDG fallback paths drop the
generated-content / SEO-farm domains that were poisoning quick
lookups.
- **Auto routing recognises CJK debug / search keywords** (PRs #1401
and #1402 from **@linzhiqin2003**) — `--model auto` and the
reasoning-effort picker correctly route Chinese / Japanese
technical queries instead of falling through to the generic
baseline.
- **Deferred tools hydrate schemas before first execution** (#1419,
PR #1429 from **@SamhandsomeLee**) — `edit_file` and other
deferred tools now load, show their expected fields, and ask the
model to retry instead of executing guessed argument names.
- **DeepSeek aliases replay thinking-mode tool turns** (PR #1428
from **@Beltran12138**) — `deepseek-chat` and
`deepseek-reasoner` now get the same `reasoning_content` replay
treatment as explicit V4 model IDs, avoiding second-turn 400s
after tool calls.
- **Skill completions stay under `/skill`** (#1437, PR #1442 from
**@reidliu41**) — large local skill collections no longer crowd
the root slash-command menu.
- **`edit_file` rejects no-op replacements** (PR #1460 from
**@xiluoduyu**) — identical `search` / `replace` values now fail
validation instead of returning an empty diff.
- **Windows terminal layout gets width-stable glyphs** (#1314,
PR #1465 from **@CrepuscularIRIS**) — header and file-tree icons
no longer rely on SMP emoji that cmd / PowerShell can mismeasure.
- **Ghostty uses low-motion rendering by default** (#1445, PR #1468
from **@CrepuscularIRIS**) — affected terminals avoid animation
flicker without manual config.
- **Docker buildx provenance EPERM failures get a hint** (#1449,
PR #1469 from **@CrepuscularIRIS**) — macOS shell output points at
the provenance flag when that restricted metadata write fails.
- **Windows CMD mouse-wheel fallback scrolls the transcript**
(#1443, PR #1471 from **@CrepuscularIRIS**) — wheel events mapped
to Up / Down no longer cycle composer history when mouse capture
is off.
- **Sync-to-CNB workflow hardened** — explicit `permissions:
contents: read`, narrowed trigger to `main` + `v*` tags (no longer
mirrors feature branches), `actions/checkout` bumped v3 → v4.
- **+438 LOC of new test coverage** for `error_taxonomy`,
`parse_pages_arg`, web-search precedence, and
`sanitize_stream_chunk` control-byte filtering (PRs #1403-#1406
from **@linzhiqin2003**).
- **Five new tools.** `read_file` now extracts PDFs in pure Rust — no
Poppler install required. `pandoc_convert` moves documents between 11
formats (Markdown, HTML, DOCX, EPUB, LaTeX…). `image_ocr` runs local
tesseract on screenshots and scanned documents. `image_analyze` sends
images to a vision model for natural-language description (opt-in only).
`js_execution` mirrors `code_execution` for Node.js snippets.
- **Two more providers.** AtlasCloud joins as a first-class provider
(`provider = "atlascloud"`) with the same config-surface shape as the
existing NVIDIA NIM / Fireworks rows. `web_search` supports Tavily and
Bocha as configurable backends for regions where DuckDuckGo is
unreliable.
- **Prompt-cache survives mid-session edits** (PR #1345 from
**@Duducoco**). Moving `instructions`, user memory, and session goal
below the volatile-content boundary means the KV prefix cache no longer
breaks every time you edit your memory file — skills and context
management instructions stay hot regardless of how often you run
`/memory`.
- **vLLM thinking toggle actually works now** (PR #1480 from
**@h3c-hexin**). `reasoning_effort = "off"` on vLLM providers now emits
the OpenAI `chat_template_kwargs.enable_thinking` extension instead of
the silently-ignored Anthropic-native field. Measured improvement on
Qwen3: TTFT from ~13s → ~270ms.
- **Kitty keyboard protocol on Windows** (PR #1483 from
**@CrepuscularIRIS / autoghclaw**). `Shift+Enter` now inserts a
newline instead of submitting in VSCode and Windows Terminal —
previously indistinguishable from plain Enter on Windows.
- **Tool-result retrieval namespace unified** (#1541). Wire-dedup refs
and disk-spillover refs now share a lookup path — `retrieve_tool_result`
accepts SHA refs, bare hex hashes, `art_<id>` aliases, and absolute
paths, with error messages that list every accepted form.
- **Snapshots skip giant workspaces** (#1552). A 2 GB ceiling on
non-excluded workspace content prevents first-turn `git add -A` from
hanging the TUI on multi-hundred-GB project directories. Configurable
via `[snapshots] max_workspace_gb`; set to `0` to restore unbounded
behaviour.
- **`deepseek update` refreshes both binaries** (PR #1492 from
**@NorethSea**). The updater now enumerates colocated binaries (both
the dispatcher and the TUI runtime), downloads and verifies every
release asset, and writes the sibling first so a partial failure can't
leave the launcher updated while the TUI stays stale.
- **Approval modal collapses to a one-line banner** (PR #1455 from
**@tiger-dog**). Tab toggles between the full takeover card and a
bottom-line summary — the transcript stays visible while you decide.
- **`@`-mention truncation no longer splits CJK codepoints** (PR #1495
from **@CrepuscularIRIS / autoghclaw**). Files larger than 128 KB
used to truncate mid-codepoint; the truncator now rounds down to the
last valid UTF-8 boundary.
- **Startup empty-state shows the build version**, active model with a
`/model` hint, and current working directory (PR #1444 from
**@reidliu41**).
- **`/change` slash command** displays the latest CHANGELOG section
inside the TUI (PR #1416 from **@zhuangbiaowei**).
- **Toast overlay no longer renders on top of the composer** (PR #1485
from **@MeAiRobot**). Approval toasts now clamp to the gap between
the composer and footer.
- **TUI no longer freezes during long-running shell jobs** (PR #1494
from **@CrepuscularIRIS / autoghclaw**). The job panel's refresh path
now reads only the tail bytes under the mutex lock instead of cloning
the entire stdout buffer every 2.5 seconds.
- **Markdown renderer no longer eats underscores in identifiers** (PR
#1455 from **@tiger-dog**). `deepseek_tui` and `foo_bar_baz` no longer
render half-italic.
- **`/sessions` picker highlights the selected row** more strongly in
dark terminals (PR #1493 from **@reidliu41**), and no longer shows
`<turn_meta>` as the session title (PR #1498 from **@wdw8276**).
Thanks to **@linzhiqin2003** (10 landings this cycle),
**@reidliu41** (5 landings), **@CrepuscularIRIS** (4 landings),
**@SamhandsomeLee**, **@Beltran12138**, **@Wenjunyun123**,
**@hlx98007**, **@Liu-Vince**, **@xiluoduyu**, and
**@shenxiaodaosanhua** for the bug report.
Thanks to **@CrepuscularIRIS** (4 landings), **@reidliu41** (2 landings),
**@tiger-dog** (2 landings), **@Duducoco**, **@h3c-hexin**,
**@NorethSea**, **@MeAiRobot**, **@zhuangbiaowei**, **@wdw8276**,
**@MMMarcinho**, **@SamhandsomeLee**, **@sandofree**,
**@lucaszhu-hue**, **@muyuliyan**, **@Oliver-ZPLiu**, **@czf0718**,
**@jieshu666**, and **@YaYII**.
---
-141
View File
@@ -1,141 +0,0 @@
# v0.8.6 Backlog — Work Brief for an AI Agent
This is a structured brief for another AI (Claude Opus, DeepSeek V4, or similar) to
understand the full v0.8.6 scope and begin implementation. The repo is
`github.com/Hmbown/DeepSeek-TUI` — Rust workspace, TUI coding agent for DeepSeek V4.
**Branch**: create `feat/v0.8.6` from `main` (current HEAD at v0.8.5 tag).
**All 23 issues are tagged `v0.8.6`** and live in the repo's GitHub Issues.
**Zero open issues outside this list** — the board is clean.
## Project Context
DeepSeek TUI is a terminal-native coding agent. Key architectural points:
- **Dispatcher binary** (`deepseek`) delegates to the TUI binary (`deepseek-tui`)
- **Crate map**: `crates/tui` is the main crate; `crates/cli` handles CLI entry;
`crates/config`, `crates/core`, `crates/tools` etc. are sub-crates
- **Engine pattern**: `core/engine.rs` runs the agent loop, processes tool calls
- **TUI**: ratatui-based, alt-screen, composer at bottom, sidebar at right
- **Config**: `~/.deepseek/config.toml`, profiles, providers, settings
- **Key files to read first**: `docs/ARCHITECTURE.md`, `crates/tui/src/main.rs`,
`crates/tui/src/tui/app.rs`, `crates/tui/src/core/engine.rs`
Read `AGENTS.md` and `CLAUDE.md` in the repo root for build/test commands.
---
## v0.8.6 Issues — Grouped by Theme
### Group A: UX Polish — Transcript & Clipboard (5 issues)
| # | Title | TL;DR |
|---|-------|-------|
| 380 | Inline diff highlighting | Color +/- in apply_patch/edit_file results |
| 379 | Smart clipboard Ctrl+Y | Copy focused cell to system clipboard |
| 375 | Right-click context menu | Per-cell menu: Copy, Open in editor, Re-run, Hide |
| 374 | Clickable file:line | OSC-8 hyperlinks on path:line in tool output |
| 376 | Native-copy escape | Hold Shift to bypass alt-screen for terminal selection |
### Group B: Workspace UX — Navigation & Visibility (4 issues)
| # | Title | TL;DR |
|---|-------|-------|
| 394 | File-tree pane | Ctrl+E toggles left-side workspace navigator |
| 395 | Cycle-boundary visualization | Inline dividers between coherence cycles |
| 396 | Per-turn cache hit chip | Footer shows cache hit % after each turn |
| 388 | Crash-recovery prompt | On restart, offer to restore interrupted turn |
### Group C: Session & History (3 issues)
| # | Title | TL;DR |
|---|-------|-------|
| 383 | /edit — revise and resubmit | Pull last message into composer, re-run turn |
| 384 | /undo — revert last patch | Surgical undo of apply_patch/edit_file/write_file |
| 385 | /diff — session changes | Show git diff since session start |
### Group D: Tools & Intelligence (4 issues)
| # | Title | TL;DR |
|---|-------|-------|
| 389 | Inline LSP diagnostics | Show rust-analyzer errors after each patch |
| 386 | /init — bootstrap AGENTS.md | Auto-detect project type, write starter AGENTS.md |
| 391 | User-defined slash commands | ~/.deepseek/commands/<name>.md templates |
| 392 | /model auto | Heuristic Pro-vs-Flash routing per turn |
### Group E: Infrastructure & Sharing (4 issues)
| # | Title | TL;DR |
|---|-------|-------|
| 390 | /profile — hot-switch config | Switch config profiles in-session without restart |
| 393 | /share — session URL | Export session as static HTML, upload to gist/S3 |
| 387 | In-app self-update | deepseek update fetches + replaces binary |
| 397 | Goal mode | Stated objective, token budget, self-verification tools |
### Group F: Quality & Fixes (3 issues)
| # | Title | TL;DR |
|---|-------|-------|
| 382 | Collapse Steer/Queue/Immediate | One mental model — everything queues, Ctrl+Enter steers |
| 373 | Sidebar Tasks panel ignores shell jobs | Wire shell jobs into Tasks panel |
| 377 | Shrink App state | Group ~200 fields into typed sub-states |
| 378 | Docs: tighten README + ARCHITECTURE | External-reader polish pass |
---
## Suggested Implementation Order
### Wave 1: Foundation (start here)
1. **#377 (refactor App state)** — do this FIRST. Group fields into sub-state structs
before adding more fields. Every subsequent feature touches App.
2. **#382 (collapse Steer/Queue)** — UX clarity fix, low implementation risk.
3. **#373 (Tasks panel shell jobs)** — bugfix, low risk.
### Wave 2: Transcript UX
4. **#380 (inline diff highlighting)** — parser pass on tool output, visible value.
5. **#374 (clickable file:line)** — OSC-8 hyperlinks, high discoverability.
6. **#379 (smart clipboard Ctrl+Y)** — small feature, big ergonomic win.
7. **#375 (right-click context menu)** — depends on mouse event plumbing.
8. **#376 (native-copy escape)** — terminal selection fix.
### Wave 3: Session tools
9. **#383 (/edit)** — requires engine truncation path.
10. **#384 (/undo)** — depends on snapshot infra.
11. **#385 (/diff)** — uses snapshot repo, depends on #380 for rendering.
12. **#388 (crash-recovery prompt)** — uses existing checkpoint infra.
### Wave 4: Intelligence
13. **#386 (/init)** — project detection + AGENTS.md generation.
14. **#389 (LSP diagnostics)** — polls existing LSP client, low-maintenance.
15. **#391 (user-defined commands)** — skills loader reuse.
16. **#392 (/model auto)** — heuristic router, DeepSeek-specific.
### Wave 5: Visibility & sharing
17. **#394 (file-tree pane)** — workspace navigator.
18. **#395 (cycle-boundary visualization)** — coherence cycle dividers.
19. **#396 (cache hit chip)** — footer chip, simple addition.
20. **#393 (/share)** — HTML export, gist/S3 backend.
21. **#387 (self-update)** — binary fetch + verify + replace.
### Wave 6: Docs & goal mode
22. **#378 (docs polish)** — README + ARCHITECTURE refresh.
23. **#397 (Goal mode)** — largest feature, last (benefits from all previous work).
---
## Working Patterns
- **PR-per-issue** (or small clusters). Each merged PR closes one issue.
- **Decomposition first**: read the issue body, identify the files that need to change,
create a `checklist_write`, then implement.
- **Test gates**: `cargo test --workspace --all-features` must pass before each PR.
- **Lint gates**: `cargo clippy --workspace --all-targets --all-features -- -D warnings` clean.
- **Format**: `cargo fmt --all` before commit.
- **GitHub**: push to `feat/v0.8.6`, create PRs to `main`. Use `gh` CLI.
- **No open issues** except the v0.8.6 list — if new issues emerge, create them but don't block.
## Key Resources
- Repo: `https://github.com/Hmbown/DeepSeek-TUI`
- Architecture: `docs/ARCHITECTURE.md`
- Config reference: `docs/CONFIGURATION.md`
- CLI: `gh issue list --label v0.8.6 --json number,title,body` for full issue text
+2
View File
@@ -57,6 +57,8 @@ export async function GET(req: Request) {
const agentEnv: AgentEnv = {
CURATED_KV: env.CURATED_KV,
DEEPSEEK_API_KEY: env.DEEPSEEK_API_KEY,
DEEPSEEK_BASE_URL: env.DEEPSEEK_BASE_URL ?? process.env.DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL: env.DEEPSEEK_MODEL ?? process.env.DEEPSEEK_MODEL,
GITHUB_TOKEN: env.GITHUB_TOKEN,
CRON_SECRET: env.CRON_SECRET,
GITHUB_REPO: env.GITHUB_REPO,
+21 -6
View File
@@ -12,6 +12,7 @@ import {
hasFreshDraft,
logUsage,
type AgentDraft,
type DeepSeekEnv,
} from "@/lib/community-agent";
export interface AgentEnv {
@@ -22,6 +23,8 @@ export interface AgentEnv {
delete(key: string): Promise<void>;
};
DEEPSEEK_API_KEY?: string;
DEEPSEEK_BASE_URL?: string;
DEEPSEEK_MODEL?: string;
GITHUB_TOKEN?: string;
CRON_SECRET?: string;
GITHUB_REPO?: string;
@@ -29,6 +32,13 @@ export interface AgentEnv {
MAINTAINER_GITHUB_PAT?: string;
}
function dsEnv(env: AgentEnv): DeepSeekEnv {
return {
baseUrl: env.DEEPSEEK_BASE_URL ?? process.env.DEEPSEEK_BASE_URL,
model: env.DEEPSEEK_MODEL ?? process.env.DEEPSEEK_MODEL,
};
}
export async function runCurate(env: AgentEnv): Promise<Record<string, unknown>> {
if (!env.DEEPSEEK_API_KEY) {
return { skipped: true, reason: "DEEPSEEK_API_KEY not set" };
@@ -38,7 +48,7 @@ export async function runCurate(env: AgentEnv): Promise<Record<string, unknown>>
fetchRepoStats(env.GITHUB_TOKEN),
fetchFeed(env.GITHUB_TOKEN, 30),
]);
const dispatch = await curate(env.DEEPSEEK_API_KEY, stats, feed);
const dispatch = await curate(env.DEEPSEEK_API_KEY, stats, feed, dsEnv(env));
await putDispatch(dispatch);
return { ok: true, headline: dispatch.headline };
} catch (e) {
@@ -84,7 +94,8 @@ export async function runTriage(env: AgentEnv): Promise<Record<string, unknown>>
const { content, usage } = await agentChat(
[{ role: "system", content: TRIAGE_PROMPT }, { role: "user", content: JSON.stringify(payload) }],
env.DEEPSEEK_API_KEY!,
true
true,
dsEnv(env)
);
const parsed = JSON.parse(content) as { bodyEn: string; bodyZh: string };
const draft: AgentDraft = {
@@ -166,7 +177,8 @@ export async function runPrReview(env: AgentEnv): Promise<Record<string, unknown
const { content, usage } = await agentChat(
[{ role: "system", content: PR_REVIEW_PROMPT }, { role: "user", content: JSON.stringify(payload) }],
env.DEEPSEEK_API_KEY!,
true
true,
dsEnv(env)
);
const parsed = JSON.parse(content) as { bodyEn: string; bodyZh: string };
const draft: AgentDraft = {
@@ -232,7 +244,8 @@ export async function runStale(env: AgentEnv): Promise<Record<string, unknown>>
const { content, usage } = await agentChat(
[{ role: "system", content: STALE_PROMPT }, { role: "user", content: JSON.stringify(payload) }],
env.DEEPSEEK_API_KEY!,
true
true,
dsEnv(env)
);
const parsed = JSON.parse(content) as { bodyEn: string; bodyZh: string };
const draft: AgentDraft = {
@@ -290,7 +303,8 @@ export async function runDupes(env: AgentEnv): Promise<Record<string, unknown>>
const { content, usage } = await agentChat(
[{ role: "system", content: DUPES_PROMPT }, { role: "user", content: JSON.stringify({ issues: openIssues }) }],
env.DEEPSEEK_API_KEY!,
true
true,
dsEnv(env)
);
const parsed = JSON.parse(content) as { suggestions?: { targetNumber: number; duplicateNumber: number; reason: string; bodyEn: string; bodyZh: string }[] };
@@ -373,7 +387,8 @@ export async function runDigest(env: AgentEnv): Promise<Record<string, unknown>>
const { content, usage } = await agentChat(
[{ role: "system", content: DIGEST_PROMPT }, { role: "user", content: JSON.stringify(payload) }],
env.DEEPSEEK_API_KEY!,
true
true,
dsEnv(env)
);
const parsed = JSON.parse(content) as { titleEn: string; titleZh: string; summaryEn: string; summaryZh: string; sections: { heading: string; items: string[] }[] };
+13 -3
View File
@@ -41,13 +41,19 @@ export interface UsageLog {
outputTokens: number;
}
export interface DeepSeekEnv {
baseUrl?: string;
model?: string;
}
export async function agentChat(
messages: ChatMessage[],
apiKey: string,
jsonMode = false
jsonMode = false,
dsEnv?: DeepSeekEnv
): Promise<{ content: string; usage: { input: number; output: number } }> {
const base = process.env.DEEPSEEK_BASE_URL ?? FALLBACK_BASE;
const model = process.env.DEEPSEEK_MODEL ?? FALLBACK_MODEL;
const base = dsEnv?.baseUrl ?? process.env.DEEPSEEK_BASE_URL ?? FALLBACK_BASE;
const model = dsEnv?.model ?? process.env.DEEPSEEK_MODEL ?? FALLBACK_MODEL;
const res = await fetch(`${base}/v1/chat/completions`, {
method: "POST",
headers: {
@@ -185,6 +191,8 @@ interface KVNamespace {
export interface CommunityAgentEnv {
CURATED_KV?: KVNamespace;
DEEPSEEK_API_KEY?: string;
DEEPSEEK_BASE_URL?: string;
DEEPSEEK_MODEL?: string;
GITHUB_TOKEN?: string;
CRON_SECRET?: string;
GITHUB_REPO?: string;
@@ -200,6 +208,8 @@ export async function getAgentEnv(): Promise<CommunityAgentEnv> {
} catch {
return {
DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY,
DEEPSEEK_BASE_URL: process.env.DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL: process.env.DEEPSEEK_MODEL,
GITHUB_TOKEN: process.env.GITHUB_TOKEN,
CRON_SECRET: process.env.CRON_SECRET,
GITHUB_REPO: process.env.GITHUB_REPO,
+11 -1
View File
@@ -13,7 +13,7 @@
* Both surface as drafts in CURATED_KV under `draft:linkcheck:<...>` and
* `draft:semantic-drift:<...>`, picked up by the existing /admin listing.
*/
import { agentChat, saveDraft, type AgentDraft, VOICE_CONSTRAINTS } from "./community-agent";
import { agentChat, saveDraft, type AgentDraft, type DeepSeekEnv, VOICE_CONSTRAINTS } from "./community-agent";
interface KVNamespace {
get(k: string): Promise<string | null>;
@@ -25,9 +25,18 @@ interface KVNamespace {
interface WatchEnv {
CURATED_KV?: KVNamespace;
DEEPSEEK_API_KEY?: string;
DEEPSEEK_BASE_URL?: string;
DEEPSEEK_MODEL?: string;
GITHUB_TOKEN?: string;
}
function dsEnv(env: WatchEnv): DeepSeekEnv {
return {
baseUrl: env.DEEPSEEK_BASE_URL ?? process.env.DEEPSEEK_BASE_URL,
model: env.DEEPSEEK_MODEL ?? process.env.DEEPSEEK_MODEL,
};
}
// --- Link checker ---
// Targets to probe daily. For registries that block bot HEAD/GET (npm, crates.io)
@@ -255,6 +264,7 @@ ${docsText}`;
],
env.DEEPSEEK_API_KEY,
true,
dsEnv(env),
);
} catch (e) {
return { ok: false, drafted: 0, reason: `LLM call failed: ${e}` };
+17 -5
View File
@@ -12,9 +12,19 @@ interface ChatResponse {
choices: { message: { content: string } }[];
}
export async function chat(messages: ChatMessage[], apiKey: string, jsonMode = false): Promise<string> {
const base = process.env.DEEPSEEK_BASE_URL ?? FALLBACK_BASE;
const model = process.env.DEEPSEEK_MODEL ?? FALLBACK_MODEL;
export interface DeepSeekEnv {
baseUrl?: string;
model?: string;
}
export async function chat(
messages: ChatMessage[],
apiKey: string,
jsonMode = false,
dsEnv?: DeepSeekEnv
): Promise<string> {
const base = dsEnv?.baseUrl ?? process.env.DEEPSEEK_BASE_URL ?? FALLBACK_BASE;
const model = dsEnv?.model ?? process.env.DEEPSEEK_MODEL ?? FALLBACK_MODEL;
const res = await fetch(`${base}/v1/chat/completions`, {
method: "POST",
headers: {
@@ -64,7 +74,8 @@ Rules:
export async function curate(
apiKey: string,
stats: RepoStats,
feed: FeedItem[]
feed: FeedItem[],
dsEnv?: DeepSeekEnv
): Promise<CuratedDispatch> {
const trimmedFeed = feed.slice(0, 25).map((f) => ({
kind: f.kind,
@@ -96,7 +107,8 @@ export async function curate(
{ role: "user", content: JSON.stringify(userPayload, null, 2) },
],
apiKey,
true
true,
dsEnv
);
const parsed = JSON.parse(raw) as Omit<CuratedDispatch, "generatedAt">;
+3 -8
View File
@@ -18,13 +18,8 @@ export interface RepoFacts {
}
export const FACTS: RepoFacts = {
<<<<<<< Updated upstream
"generatedAt": "2026-05-12T03:14:50.815Z",
"version": "0.8.30",
=======
"generatedAt": "2026-05-10T15:06:44.698Z",
"version": "0.8.27",
>>>>>>> Stashed changes
"generatedAt": "2026-05-12T19:02:49.213Z",
"version": "0.8.32",
"crates": [
"agent",
"app-server",
@@ -95,7 +90,7 @@ export const FACTS: RepoFacts = {
],
"defaultModel": "deepseek-v4-pro",
"nodeEngines": ">=18",
"toolCount": 62,
"toolCount": 64,
"license": "MIT",
"latestRelease": null
};
+4
View File
@@ -16,6 +16,8 @@ interface KVNamespace {
interface CloudflareEnv {
CURATED_KV?: KVNamespace;
DEEPSEEK_API_KEY?: string;
DEEPSEEK_BASE_URL?: string;
DEEPSEEK_MODEL?: string;
GITHUB_TOKEN?: string;
CRON_SECRET?: string;
GITHUB_REPO?: string;
@@ -29,6 +31,8 @@ export async function getEnv(): Promise<CloudflareEnv> {
} catch {
return {
DEEPSEEK_API_KEY: process.env.DEEPSEEK_API_KEY,
DEEPSEEK_BASE_URL: process.env.DEEPSEEK_BASE_URL,
DEEPSEEK_MODEL: process.env.DEEPSEEK_MODEL,
GITHUB_TOKEN: process.env.GITHUB_TOKEN,
CRON_SECRET: process.env.CRON_SECRET,
GITHUB_REPO: process.env.GITHUB_REPO,
+8 -3
View File
@@ -14,10 +14,15 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
const cfgPath = join(__dirname, "..", "wrangler.jsonc");
const raw = readFileSync(cfgPath, "utf-8");
// Parse JSONC (strip comments, trailing commas)
// Parse JSONC (strip comments, trailing commas).
// Use a two-pass approach to avoid mangling URLs: first strip
// line comments that look like comments (preceded by whitespace
// or comma, not part of ://), then strip block comments.
const stripped = raw
.replace(/\/\/.*$/gm, "") // line comments
.replace(/\/\*[\s\S]*?\*\//g, ""); // block comments
.replace(/(^|[,\s])\/\/[^\n]*/gm, "$1") // line comments (skips :// in URLs)
.replace(/\/\*[\s\S]*?\*\//g, "") // block comments
.replace(/,\s*}/g, "}") // trailing commas
.replace(/,\s*]/g, "]");
const cfg = JSON.parse(stripped);
const nss = cfg.kv_namespaces;