deepccc 0.1.13 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -8
- package/dist/cli.js +3 -2
- package/dist/config.d.ts +2 -0
- package/dist/config.js +2 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +81 -19
- package/os-prompts/darwin.md +8 -0
- package/os-prompts/linux.md +8 -0
- package/os-prompts/win32.md +9 -0
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -45,16 +45,18 @@ deepccc 的本地缓存优化实测命中率 **96.7%**,有效降低重复请
|
|
|
45
45
|
|
|
46
46
|
```bash
|
|
47
47
|
export DEEPCCC_API_KEY="sk-..."
|
|
48
|
-
export DEEPCCC_BASE_URL="https://api.deepseek.com/v1"
|
|
49
|
-
export DEEPCCC_MODEL="deepseek-v4-pro"
|
|
48
|
+
export DEEPCCC_BASE_URL="https://api.deepseek.com/v1"
|
|
49
|
+
export DEEPCCC_MODEL="deepseek-v4-pro"
|
|
50
|
+
export DEEPCCC_STREAMING="true"
|
|
50
51
|
```
|
|
51
52
|
|
|
52
53
|
Windows PowerShell:
|
|
53
54
|
|
|
54
55
|
```powershell
|
|
55
56
|
$env:DEEPCCC_API_KEY="sk-..."
|
|
56
|
-
$env:DEEPCCC_BASE_URL="https://api.deepseek.com/v1"
|
|
57
|
-
$env:DEEPCCC_MODEL="deepseek-v4-pro"
|
|
57
|
+
$env:DEEPCCC_BASE_URL="https://api.deepseek.com/v1"
|
|
58
|
+
$env:DEEPCCC_MODEL="deepseek-v4-pro"
|
|
59
|
+
$env:DEEPCCC_STREAMING="true"
|
|
58
60
|
```
|
|
59
61
|
|
|
60
62
|
也兼容这些 DeepSeek 别名:
|
|
@@ -70,16 +72,20 @@ $env:DEEPCCC_MODEL="deepseek-v4-pro"
|
|
|
70
72
|
{
|
|
71
73
|
"apiKey": "sk-...",
|
|
72
74
|
"baseURL": "https://api.deepseek.com/v1",
|
|
73
|
-
"model": "deepseek-v4-pro",
|
|
74
|
-
"effort": "",
|
|
75
|
+
"model": "deepseek-v4-pro",
|
|
76
|
+
"effort": "",
|
|
77
|
+
"streaming": true,
|
|
75
78
|
"rawStreamLogs": {
|
|
76
79
|
"enabled": false,
|
|
77
80
|
"maxBytesPerTurn": 1048576,
|
|
78
81
|
"retentionDays": 7,
|
|
79
82
|
"keepCompleted": false
|
|
80
83
|
}
|
|
81
|
-
}
|
|
82
|
-
```
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`streaming` 控制主对话是否使用流式请求,默认 `true`;也可以通过
|
|
88
|
+
`DEEPCCC_STREAMING=true|false` 覆盖。关闭后,终端会在整条模型响应完成后一次性显示结果。
|
|
83
89
|
|
|
84
90
|
## 命令行交互
|
|
85
91
|
|
package/dist/cli.js
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
* 非 TTY(管道/CI)或 --plain 回退为纯文本流式输出;--stream-json 机器接口不变。
|
|
12
12
|
*/
|
|
13
13
|
import * as readline from "node:readline";
|
|
14
|
-
import
|
|
14
|
+
import process from "node:process";
|
|
15
15
|
import { appendFileSync, existsSync, mkdirSync, writeFileSync } from "node:fs";
|
|
16
16
|
import { homedir } from "node:os";
|
|
17
17
|
import { join, resolve as resolvePath } from "node:path";
|
|
@@ -595,7 +595,8 @@ async function main() {
|
|
|
595
595
|
const args = parseArgs();
|
|
596
596
|
if (args.streamJson) {
|
|
597
597
|
const code = await runStreamJson(args);
|
|
598
|
-
process.
|
|
598
|
+
process.exitCode = code;
|
|
599
|
+
return;
|
|
599
600
|
}
|
|
600
601
|
if (args.help) {
|
|
601
602
|
const { appConfig } = await loadRuntime();
|
package/dist/config.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ export interface DeepCccConfig {
|
|
|
4
4
|
model: string;
|
|
5
5
|
/** Reasoning effort(none/minimal/low/medium/high/xhigh/max),留空不传 reasoning_effort */
|
|
6
6
|
effort: string;
|
|
7
|
+
/** 主对话是否使用流式请求;默认开启 */
|
|
8
|
+
streaming: boolean;
|
|
7
9
|
rawStreamLogs: {
|
|
8
10
|
enabled: boolean;
|
|
9
11
|
maxBytesPerTurn: number;
|
package/dist/config.js
CHANGED
|
@@ -9,6 +9,7 @@ const DEFAULT_CONFIG = {
|
|
|
9
9
|
baseURL: "https://api.deepseek.com/v1",
|
|
10
10
|
model: "deepseek-v4-pro",
|
|
11
11
|
effort: "",
|
|
12
|
+
streaming: true,
|
|
12
13
|
rawStreamLogs: {
|
|
13
14
|
enabled: false,
|
|
14
15
|
maxBytesPerTurn: 1024 * 1024,
|
|
@@ -50,6 +51,7 @@ function loadConfig() {
|
|
|
50
51
|
baseURL: env("DEEPCCC_BASE_URL") ?? env("DEEPSEEK_BASE_URL") ?? file.baseURL ?? DEFAULT_CONFIG.baseURL,
|
|
51
52
|
model: env("DEEPCCC_MODEL") ?? env("DEEPSEEK_MODEL") ?? file.model ?? DEFAULT_CONFIG.model,
|
|
52
53
|
effort: env("DEEPCCC_EFFORT") ?? env("DEEPSEEK_EFFORT") ?? file.effort ?? DEFAULT_CONFIG.effort,
|
|
54
|
+
streaming: boolEnv("DEEPCCC_STREAMING") ?? file.streaming ?? DEFAULT_CONFIG.streaming,
|
|
53
55
|
rawStreamLogs: {
|
|
54
56
|
enabled: boolEnv("DEEPCCC_RAW_STREAM_LOGS") ?? rawLogs.enabled ?? DEFAULT_CONFIG.rawStreamLogs.enabled,
|
|
55
57
|
maxBytesPerTurn: numberEnv("DEEPCCC_RAW_STREAM_MAX_BYTES") ?? rawLogs.maxBytesPerTurn ?? DEFAULT_CONFIG.rawStreamLogs.maxBytesPerTurn,
|
package/dist/index.d.ts
CHANGED
|
@@ -5,6 +5,19 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { type PermissionMode, type PermissionResolver } from "./permissions.js";
|
|
7
7
|
export declare const DEFAULT_COMPACTION_TIMEOUT_MS: number;
|
|
8
|
+
/**
|
|
9
|
+
* 各操作系统特有的命令行指引(文本资产,维护在 os-prompts/ 目录,而非硬编码):
|
|
10
|
+
*
|
|
11
|
+
* - 内置文件:包内 os-prompts/<platform>.md(win32/darwin/linux),随 npm 包分发;
|
|
12
|
+
* - 用户覆盖:~/.deepccc/prompts/<platform>.md 存在时完全替代内置内容(可自定义)。
|
|
13
|
+
*
|
|
14
|
+
* 文件内容自带标题(如 "## Windows Command-Line Notes"),读取后 trim 直接作为
|
|
15
|
+
* 一个段落注入固定规则区(项目指令之前)。未知平台或文件缺失时返回空字符串。
|
|
16
|
+
*/
|
|
17
|
+
export declare function loadPlatformCommandPrompt(platform?: string, dirs?: {
|
|
18
|
+
builtinDir?: string;
|
|
19
|
+
userDir?: string;
|
|
20
|
+
}): string;
|
|
8
21
|
export interface ChatSessionConfig {
|
|
9
22
|
/** OpenAI-compatible service base URL. Defaults to DEEPCCC_BASE_URL/config. */
|
|
10
23
|
baseURL?: string;
|
package/dist/index.js
CHANGED
|
@@ -5,8 +5,10 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { createOpenAICompatible } from "@ai-sdk/openai-compatible";
|
|
7
7
|
import { generateText, isLoopFinished, stepCountIs, streamText } from "ai";
|
|
8
|
-
import { readFileSync } from "node:fs";
|
|
8
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
9
|
+
import { homedir } from "node:os";
|
|
9
10
|
import { join } from "node:path";
|
|
11
|
+
import { fileURLToPath } from "node:url";
|
|
10
12
|
import { config as appConfig, RAW_STREAM_LOGS_DIR } from "./config.js";
|
|
11
13
|
import { createRawStreamLog, } from "./raw-stream-log.js";
|
|
12
14
|
import { buildPersistedAssistantMessage, buildSummaryPrompt, BuiltinContextManager, defaultBuiltinSessionId, } from "./context.js";
|
|
@@ -97,22 +99,45 @@ function buildRuntimeWorkspacePrompt(cwd) {
|
|
|
97
99
|
].join("\n");
|
|
98
100
|
}
|
|
99
101
|
/**
|
|
100
|
-
*
|
|
101
|
-
*
|
|
102
|
-
*
|
|
102
|
+
* 各操作系统特有的命令行指引(文本资产,维护在 os-prompts/ 目录,而非硬编码):
|
|
103
|
+
*
|
|
104
|
+
* - 内置文件:包内 os-prompts/<platform>.md(win32/darwin/linux),随 npm 包分发;
|
|
105
|
+
* - 用户覆盖:~/.deepccc/prompts/<platform>.md 存在时完全替代内置内容(可自定义)。
|
|
106
|
+
*
|
|
107
|
+
* 文件内容自带标题(如 "## Windows Command-Line Notes"),读取后 trim 直接作为
|
|
108
|
+
* 一个段落注入固定规则区(项目指令之前)。未知平台或文件缺失时返回空字符串。
|
|
103
109
|
*/
|
|
104
|
-
function
|
|
105
|
-
|
|
110
|
+
export function loadPlatformCommandPrompt(platform = process.platform, dirs = {}) {
|
|
111
|
+
const filename = platform === "win32" ? "win32.md" :
|
|
112
|
+
platform === "darwin" ? "darwin.md" :
|
|
113
|
+
platform === "linux" ? "linux.md" :
|
|
114
|
+
null;
|
|
115
|
+
if (!filename)
|
|
106
116
|
return "";
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
117
|
+
// import.meta.url 定位包根:chatccc 源码运行时指向 deepccc-agent/os-prompts/,
|
|
118
|
+
// deepccc dist 运行时指向包根 os-prompts/(dist/index.js 的 ../os-prompts/)。
|
|
119
|
+
const builtinDir = dirs.builtinDir ?? fileURLToPath(new URL("../os-prompts/", import.meta.url));
|
|
120
|
+
const userDir = dirs.userDir ?? join(homedir(), ".deepccc", "prompts");
|
|
121
|
+
// 用户覆盖优先;读取失败时静默回退内置,内置也失败则返回空。
|
|
122
|
+
const userFile = join(userDir, filename);
|
|
123
|
+
if (existsSync(userFile)) {
|
|
124
|
+
try {
|
|
125
|
+
return readFileSync(userFile, "utf-8").trim();
|
|
126
|
+
}
|
|
127
|
+
catch {
|
|
128
|
+
// fall through to builtin
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
const builtinFile = join(builtinDir, filename);
|
|
132
|
+
if (existsSync(builtinFile)) {
|
|
133
|
+
try {
|
|
134
|
+
return readFileSync(builtinFile, "utf-8").trim();
|
|
135
|
+
}
|
|
136
|
+
catch {
|
|
137
|
+
return "";
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
return "";
|
|
116
141
|
}
|
|
117
142
|
function normalizeMaxSteps(value) {
|
|
118
143
|
if (value === undefined)
|
|
@@ -146,6 +171,7 @@ export class ChatSession {
|
|
|
146
171
|
name: "deepccc",
|
|
147
172
|
baseURL,
|
|
148
173
|
apiKey,
|
|
174
|
+
includeUsage: true,
|
|
149
175
|
});
|
|
150
176
|
this.model = provider(modelId);
|
|
151
177
|
this.cwd = options.cwd ?? process.cwd();
|
|
@@ -175,7 +201,7 @@ export class ChatSession {
|
|
|
175
201
|
*/
|
|
176
202
|
buildSystemPrompt(skills) {
|
|
177
203
|
const systemContent = [SYSTEM_PROMPT];
|
|
178
|
-
const platformPrompt =
|
|
204
|
+
const platformPrompt = loadPlatformCommandPrompt();
|
|
179
205
|
if (platformPrompt) {
|
|
180
206
|
systemContent.push("", platformPrompt);
|
|
181
207
|
}
|
|
@@ -234,7 +260,7 @@ export class ChatSession {
|
|
|
234
260
|
const skills = await scanSkillsDirs(this.skillDirs);
|
|
235
261
|
const system = this.buildSystemPrompt(skills);
|
|
236
262
|
this.systemPrompt = system;
|
|
237
|
-
const
|
|
263
|
+
const generationOptions = {
|
|
238
264
|
model: this.model,
|
|
239
265
|
system,
|
|
240
266
|
messages: this.context.buildModelMessages(),
|
|
@@ -244,8 +270,16 @@ export class ChatSession {
|
|
|
244
270
|
// DeepSeek OpenAI 兼容接口:providerOptions.deepseek.reasoningEffort
|
|
245
271
|
// 由 @ai-sdk/openai-compatible 自动映射为请求体 reasoning_effort 字段
|
|
246
272
|
...(this.effort ? { providerOptions: { deepseek: { reasoningEffort: this.effort } } } : {}),
|
|
247
|
-
}
|
|
248
|
-
|
|
273
|
+
};
|
|
274
|
+
let stream;
|
|
275
|
+
if (appConfig.streaming) {
|
|
276
|
+
const result = streamText(generationOptions);
|
|
277
|
+
stream = result.fullStream ?? textStreamToFullStream(result.textStream);
|
|
278
|
+
}
|
|
279
|
+
else {
|
|
280
|
+
const result = await generateText(generationOptions);
|
|
281
|
+
stream = generateResultToFullStream(result);
|
|
282
|
+
}
|
|
249
283
|
for await (const part of stream) {
|
|
250
284
|
rawLog?.writeLine(safeRawStreamJson(part));
|
|
251
285
|
if (part.type === "text-delta") {
|
|
@@ -407,6 +441,34 @@ async function* textStreamToFullStream(stream) {
|
|
|
407
441
|
yield { type: "text-delta", text };
|
|
408
442
|
}
|
|
409
443
|
}
|
|
444
|
+
async function* generateResultToFullStream(result) {
|
|
445
|
+
let emittedText = false;
|
|
446
|
+
for (const step of result.steps ?? []) {
|
|
447
|
+
for (const call of step.toolCalls ?? []) {
|
|
448
|
+
yield {
|
|
449
|
+
type: "tool-call",
|
|
450
|
+
toolCallId: call.toolCallId,
|
|
451
|
+
toolName: call.toolName,
|
|
452
|
+
input: call.input,
|
|
453
|
+
};
|
|
454
|
+
}
|
|
455
|
+
for (const toolResult of step.toolResults ?? []) {
|
|
456
|
+
yield {
|
|
457
|
+
type: "tool-result",
|
|
458
|
+
toolCallId: toolResult.toolCallId,
|
|
459
|
+
toolName: toolResult.toolName,
|
|
460
|
+
output: toolResult.output,
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
if (step.text) {
|
|
464
|
+
emittedText = true;
|
|
465
|
+
yield { type: "text-delta", text: step.text };
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
if (!emittedText && result.text) {
|
|
469
|
+
yield { type: "text-delta", text: result.text };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
410
472
|
function safeJson(value) {
|
|
411
473
|
try {
|
|
412
474
|
return JSON.stringify(value);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
## macOS Command-Line Notes
|
|
2
|
+
|
|
3
|
+
You are running on macOS. run_command executes through zsh, a POSIX shell. Quoting follows standard POSIX conventions (the same habits you already know from bash):
|
|
4
|
+
|
|
5
|
+
- Double quotes are stripped and group an argument containing spaces: `echo "hello world"` prints `hello world`.
|
|
6
|
+
- Single quotes are literal quoting characters: `'a b'` is a single argument `a b`.
|
|
7
|
+
- Backticks and `$(...)` perform command substitution; quote them if you need literal text.
|
|
8
|
+
- Paths use `/` separators and `~` expands to the home directory.
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
## Linux Command-Line Notes
|
|
2
|
+
|
|
3
|
+
You are running on Linux. run_command executes through a POSIX shell (bash/sh). Quoting follows standard POSIX conventions (the same habits you already know from bash):
|
|
4
|
+
|
|
5
|
+
- Double quotes are stripped and group an argument containing spaces: `echo "hello world"` prints `hello world`.
|
|
6
|
+
- Single quotes are literal quoting characters: `'a b'` is a single argument `a b`.
|
|
7
|
+
- Backticks and `$(...)` perform command substitution; quote them if you need literal text.
|
|
8
|
+
- Paths use `/` separators and `~` expands to the home directory.
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
## Windows Command-Line Notes
|
|
2
|
+
|
|
3
|
+
You are running on Windows. run_command executes through cmd.exe, not bash. cmd quoting differs from bash and breaks common habits:
|
|
4
|
+
|
|
5
|
+
- Double quotes are NOT stripped: `echo "hello world"` prints `"hello world"` (quotes included), and `"a b" "c"` passes the literal arguments `"a b"` and `"c"` (quotes included) to the program.
|
|
6
|
+
- Single quotes are NOT quoting characters in cmd.exe: `'a b'` is parsed as two arguments (`'a` and `b'`).
|
|
7
|
+
- Multi-line or quote-heavy inline scripts (python -c "...\n...", ssh host "bash -c '...'") frequently break under cmd quoting; write the script to a temporary file and execute that file instead.
|
|
8
|
+
- PowerShell-only syntax (Get-Item, 2>$null, Select-Object) is unavailable; the shell is cmd.exe unless you explicitly invoke powershell.
|
|
9
|
+
- To pass an argument containing spaces, use double quotes and expect the quotes to reach the program literally; when the target accepts file input, prefer writing the value to a file.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "deepccc",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"description": "A lightweight DeepSeek-optimized coding agent with OpenAI-compatible model support.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"keywords": [
|
|
@@ -34,6 +34,7 @@
|
|
|
34
34
|
"dist/",
|
|
35
35
|
"bin/",
|
|
36
36
|
"docs/",
|
|
37
|
+
"os-prompts/",
|
|
37
38
|
"package.json",
|
|
38
39
|
"README.md",
|
|
39
40
|
"LICENSE"
|