Files
codewhale/web/lib/deepseek.ts
T
Hunter Bown f8a3c6619e fix(npm): map openharmony platform to linux binaries (#1072)
Node's `os.platform()` returns `openharmony` on HarmonyPC and on
OpenHarmony's Linux ABI-compatible userspace. The npm wrapper's
platform-asset matrix only covered `linux` / `darwin` / `win32`,
so `npm i -g deepseek-tui` aborted on those hosts with

    Unsupported platform: openharmony. Supported platforms: …

even though the existing Linux x64 / arm64 binaries run unchanged
on that environment (OpenHarmony is Linux-ABI-compatible at the
ELF level).

Added a `PLATFORM_ALIASES = { openharmony: "linux" }` indirection
that resolves the raw platform name through the alias map before
the `ASSET_MATRIX` lookup. Genuinely unsupported platforms still
report the raw `os.platform()` value in the error so OS-mismatch
bug reports stay diagnostic.

Four pure-JS regression tests pin the behaviour:

- openharmony x64 → linux x64 binaries
- openharmony arm64 → linux arm64 binaries
- known platforms unchanged by the alias map
- freebsd still reports `Unsupported platform: freebsd`

Harvested from PR #1499 by @CrepuscularIRIS

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-12 01:39:44 -05:00

120 lines
3.9 KiB
TypeScript

import type { CuratedDispatch, FeedItem, RepoStats } from "./types";
const FALLBACK_BASE = "https://api.deepseek.com";
const FALLBACK_MODEL = "deepseek-v4-flash";
interface ChatMessage {
role: "system" | "user" | "assistant";
content: string;
}
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;
const res = await fetch(`${base}/v1/chat/completions`, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${apiKey}`,
},
body: JSON.stringify({
model,
messages,
temperature: 0.4,
max_tokens: 4096,
reasoning_effort: "high",
...(jsonMode ? { response_format: { type: "json_object" } } : {}),
}),
});
if (!res.ok) {
const text = await res.text();
throw new Error(`DeepSeek ${res.status}: ${text}`);
}
const data = (await res.json()) as ChatResponse;
return data.choices[0]?.message?.content ?? "";
}
const SYSTEM_PROMPT = `You are the editor of "今日要闻 / Today's Dispatch", a daily-ish digest for the deepseek-tui open source project.
You receive: repo stats and a list of recently updated issues, PRs, and releases.
Output a single JSON object — no prose around it — matching this exact shape:
{
"headline": "string — one short editorial headline summarising the project's pulse this period (max ~70 chars)",
"summary": "string — 2-3 sentences in a calm, factual editorial voice. No marketing fluff. No emoji.",
"highlights": [
{ "title": "string", "href": "string", "tag": "shipped|merged|opened|discussion|release", "blurb": "one sentence, max ~120 chars" }
],
"movers": [
{ "number": 123, "title": "string", "href": "string", "reason": "one short clause explaining why it matters" }
]
}
Rules:
- Pick 3-5 highlights and 3-5 movers from the actual provided items. Never invent.
- Prefer items with discussion, merged PRs, recent releases, or labelled "good first issue".
- Tone: like a small-paper editor — measured, specific, never breathless.
- Never use words like "exciting", "amazing", "powerful", "revolutionary".
- href must be the html_url provided.`;
export async function curate(
apiKey: string,
stats: RepoStats,
feed: FeedItem[]
): Promise<CuratedDispatch> {
const trimmedFeed = feed.slice(0, 25).map((f) => ({
kind: f.kind,
number: f.number,
title: f.title,
state: f.state,
href: f.url,
author: f.author,
updated: f.updatedAt,
comments: f.comments,
labels: f.labels.map((l) => l.name),
}));
const userPayload = {
repo: "Hmbown/deepseek-tui",
stats: {
stars: stats.stars,
forks: stats.forks,
open_issues: stats.openIssues,
open_pulls: stats.openPulls,
latest_release: stats.latestRelease?.tag,
},
recent: trimmedFeed,
};
const raw = await chat(
[
{ role: "system", content: SYSTEM_PROMPT },
{ role: "user", content: JSON.stringify(userPayload, null, 2) },
],
apiKey,
true
);
const parsed = JSON.parse(raw) as Omit<CuratedDispatch, "generatedAt">;
return { ...sanitizeDispatch(parsed), generatedAt: new Date().toISOString() };
}
const SAFE_HREF_RE = /^https:\/\/(?:github\.com|api\.github\.com|deepseek-tui\.com|crates\.io|www\.npmjs\.com|docs\.rs)\//;
const FALLBACK_HREF = "https://github.com/Hmbown/deepseek-tui";
function safeHref(u: unknown): string {
return typeof u === "string" && SAFE_HREF_RE.test(u) ? u : FALLBACK_HREF;
}
function sanitizeDispatch(d: Omit<CuratedDispatch, "generatedAt">): Omit<CuratedDispatch, "generatedAt"> {
return {
...d,
highlights: (d.highlights ?? []).map((h) => ({ ...h, href: safeHref(h.href) })),
movers: (d.movers ?? []).map((m) => ({ ...m, href: safeHref(m.href) })),
};
}