chatccc 0.2.241 → 0.2.242
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/bin/cccagent.mjs +1 -1
- package/deepccc-agent/LICENSE +201 -0
- package/deepccc-agent/README.md +291 -0
- package/deepccc-agent/bin/deepccc.mjs +26 -0
- package/deepccc-agent/docs/cache-hit-rate-1.jpg +0 -0
- package/deepccc-agent/docs/cache-hit-rate-2.jpg +0 -0
- package/deepccc-agent/package-lock.json +1959 -0
- package/deepccc-agent/package.json +62 -0
- package/deepccc-agent/src/__tests__/chat-session.test.ts +522 -0
- package/deepccc-agent/src/__tests__/cli-json.test.ts +49 -0
- package/deepccc-agent/src/__tests__/config.test.ts +26 -0
- package/deepccc-agent/src/__tests__/context.test.ts +319 -0
- package/deepccc-agent/src/__tests__/file-tools.test.ts +240 -0
- package/deepccc-agent/src/__tests__/permissions.test.ts +195 -0
- package/deepccc-agent/src/__tests__/privacy.test.ts +311 -0
- package/deepccc-agent/src/__tests__/progress-reducer.test.ts +121 -0
- package/deepccc-agent/src/__tests__/session-search.test.ts +262 -0
- package/deepccc-agent/src/__tests__/session-select.test.ts +116 -0
- package/deepccc-agent/src/__tests__/sigint.test.ts +56 -0
- package/deepccc-agent/src/__tests__/skills.test.ts +284 -0
- package/deepccc-agent/src/__tests__/terminal-renderer.test.ts +247 -0
- package/deepccc-agent/src/__tests__/web-tools.test.ts +220 -0
- package/deepccc-agent/tsconfig.build.json +13 -0
- package/deepccc-agent/tsconfig.json +13 -0
- package/deepccc-agent/vitest.config.ts +7 -0
- package/package.json +3 -1
- package/src/__tests__/builtin-chat-session.test.ts +17 -17
- package/src/__tests__/builtin-config.test.ts +2 -2
- package/src/__tests__/builtin-context.test.ts +1 -1
- package/src/__tests__/builtin-file-tools.test.ts +1 -1
- package/src/__tests__/builtin-permissions.test.ts +4 -4
- package/src/__tests__/builtin-session-search.test.ts +1 -1
- package/src/__tests__/builtin-session-select.test.ts +2 -2
- package/src/__tests__/builtin-sigint.test.ts +1 -1
- package/src/__tests__/builtin-skills.test.ts +1 -1
- package/src/__tests__/builtin-web-tools.test.ts +1 -1
- package/src/__tests__/progress-reducer.test.ts +1 -1
- package/src/adapters/ccc-adapter.ts +2 -2
- package/src/progress/reducer.ts +1 -1
- /package/{src/builtin → deepccc-agent/src}/cli.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/config.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/context.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/file-log.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/file-tools.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/index.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/permissions.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/privacy.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/proc-tree-kill.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/progress/cards-helpers.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/progress/reducer.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/progress/terminal-renderer.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/progress/view.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/raw-stream-log.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/session-search.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/session-select.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/sigint.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/skills.ts +0 -0
- /package/{src/builtin → deepccc-agent/src}/web-tools.ts +0 -0
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
decodeDdgHref,
|
|
5
|
+
extractHtmlTitle,
|
|
6
|
+
htmlToPlainText,
|
|
7
|
+
parseDuckDuckGoHtml,
|
|
8
|
+
webFetchForTool,
|
|
9
|
+
webSearchForTool,
|
|
10
|
+
type FetchLike,
|
|
11
|
+
} from "../web-tools.js";
|
|
12
|
+
|
|
13
|
+
const DDG_HTML = `<!DOCTYPE html>
|
|
14
|
+
<html>
|
|
15
|
+
<head><title>Search results</title></head>
|
|
16
|
+
<body>
|
|
17
|
+
<div class="result results_links results_links_deep web-result">
|
|
18
|
+
<h2 class="result__title">
|
|
19
|
+
<a rel="nofollow" class="result__a" href="//duckduckgo.com/l/?uddg=https%3A%2F%2Fnodejs.org%2Fen%2Fdocs&rut=abc">Node.js <b>Docs</b></a>
|
|
20
|
+
</h2>
|
|
21
|
+
<a rel="nofollow" class="result__snippet" href="//duckduckgo.com/l/?uddg=...">Official documentation for Node.js & npm.</a>
|
|
22
|
+
</div>
|
|
23
|
+
<div class="result">
|
|
24
|
+
<a rel="nofollow" class="result__a" href="https://example.com/page">Example "quoted" page</a>
|
|
25
|
+
<a rel="nofollow" class="result__snippet" href="https://example.com/page">A plain snippet without highlight.</a>
|
|
26
|
+
</div>
|
|
27
|
+
</body>
|
|
28
|
+
</html>`;
|
|
29
|
+
|
|
30
|
+
const WEB_FETCH_HTML = `<!DOCTYPE html>
|
|
31
|
+
<html><head><title>Fetch & Me</title></head>
|
|
32
|
+
<body>
|
|
33
|
+
<style>.x { color: red }</style>
|
|
34
|
+
<script>alert("x")</script>
|
|
35
|
+
<h1>Hello World</h1>
|
|
36
|
+
<p>First paragraph with & entity.</p>
|
|
37
|
+
<p>Second paragraph<br>with a break.</p>
|
|
38
|
+
<footer>bye</footer>
|
|
39
|
+
</body></html>`;
|
|
40
|
+
|
|
41
|
+
describe("parseDuckDuckGoHtml", () => {
|
|
42
|
+
it("extracts title, decoded url, and snippet per result", () => {
|
|
43
|
+
const results = parseDuckDuckGoHtml(DDG_HTML);
|
|
44
|
+
expect(results).toHaveLength(2);
|
|
45
|
+
expect(results[0]).toEqual({
|
|
46
|
+
title: "Node.js Docs",
|
|
47
|
+
url: "https://nodejs.org/en/docs",
|
|
48
|
+
snippet: "Official documentation for Node.js & npm.",
|
|
49
|
+
});
|
|
50
|
+
expect(results[1]).toEqual({
|
|
51
|
+
title: 'Example "quoted" page',
|
|
52
|
+
url: "https://example.com/page",
|
|
53
|
+
snippet: "A plain snippet without highlight.",
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
it("returns empty array for pages without results", () => {
|
|
58
|
+
expect(parseDuckDuckGoHtml("<html><body>no results here</body></html>")).toEqual([]);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
describe("decodeDdgHref", () => {
|
|
63
|
+
it("decodes uddg redirect params and restores protocol", () => {
|
|
64
|
+
expect(
|
|
65
|
+
decodeDdgHref("//duckduckgo.com/l/?uddg=https%3A%2F%2Fnodejs.org%2Fen%2Fdocs&rut=abc"),
|
|
66
|
+
).toBe("https://nodejs.org/en/docs");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("passes through plain urls", () => {
|
|
70
|
+
expect(decodeDdgHref("https://example.com/a?b=1")).toBe("https://example.com/a?b=1");
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it("returns input untouched when unparseable", () => {
|
|
74
|
+
expect(decodeDdgHref("not a url")).toBe("not a url");
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("htmlToPlainText", () => {
|
|
79
|
+
it("strips scripts/styles, keeps block boundaries, decodes entities, compresses whitespace", () => {
|
|
80
|
+
const text = htmlToPlainText(WEB_FETCH_HTML);
|
|
81
|
+
expect(text).not.toContain("alert");
|
|
82
|
+
expect(text).not.toContain(".x {");
|
|
83
|
+
expect(text).toContain("Hello World");
|
|
84
|
+
expect(text).toContain("First paragraph with & entity.");
|
|
85
|
+
expect(text).toContain("Second paragraph\nwith a break.");
|
|
86
|
+
expect(text).toContain("bye");
|
|
87
|
+
// 段落间允许单个空行,但不得出现连续空行
|
|
88
|
+
expect(text).not.toContain("\n\n\n");
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
describe("extractHtmlTitle", () => {
|
|
93
|
+
it("extracts and decodes the title", () => {
|
|
94
|
+
expect(extractHtmlTitle(WEB_FETCH_HTML)).toBe("Fetch & Me");
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
it("returns empty string when no title", () => {
|
|
98
|
+
expect(extractHtmlTitle("<html><body>x</body></html>")).toBe("");
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
describe("webSearchForTool", () => {
|
|
103
|
+
function mockFetch(html: string, status = 200): FetchLike {
|
|
104
|
+
return async () =>
|
|
105
|
+
new Response(html, {
|
|
106
|
+
status,
|
|
107
|
+
headers: { "content-type": "text/html; charset=utf-8" },
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
it("returns parsed results from the search page", async () => {
|
|
112
|
+
const output = await webSearchForTool(
|
|
113
|
+
{ query: "nodejs docs" },
|
|
114
|
+
{ fetchImpl: mockFetch(DDG_HTML) },
|
|
115
|
+
);
|
|
116
|
+
expect(output.query).toBe("nodejs docs");
|
|
117
|
+
expect(output.results).toHaveLength(2);
|
|
118
|
+
expect(output.results[0].url).toBe("https://nodejs.org/en/docs");
|
|
119
|
+
expect(output.results[0].snippet).toContain("Node.js");
|
|
120
|
+
expect(typeof output.durationMs).toBe("number");
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
it("respects maxResults and caps at 10", async () => {
|
|
124
|
+
const html = Array.from({ length: 12 }, (_, i) => {
|
|
125
|
+
const title = `<a rel="nofollow" class="result__a" href="https://e.com/${i}">R${i}</a>`;
|
|
126
|
+
const snippet = `<a rel="nofollow" class="result__snippet" href="https://e.com/${i}">s${i}</a>`;
|
|
127
|
+
return `<div>${title}${snippet}</div>`;
|
|
128
|
+
}).join("");
|
|
129
|
+
const output = await webSearchForTool({ query: "many" }, { fetchImpl: mockFetch(html) });
|
|
130
|
+
expect(output.results).toHaveLength(5);
|
|
131
|
+
expect(output.truncated).toBe(true);
|
|
132
|
+
|
|
133
|
+
const output2 = await webSearchForTool({ query: "many", maxResults: 20 }, { fetchImpl: mockFetch(html) });
|
|
134
|
+
expect(output2.results).toHaveLength(10);
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
it("returns empty results (not an error) when the page has no matches", async () => {
|
|
138
|
+
const output = await webSearchForTool(
|
|
139
|
+
{ query: "zzz-nothing" },
|
|
140
|
+
{ fetchImpl: mockFetch("<html><body>no results</body></html>") },
|
|
141
|
+
);
|
|
142
|
+
expect(output.results).toEqual([]);
|
|
143
|
+
expect(output.truncated).toBe(false);
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
it("throws on empty query", async () => {
|
|
147
|
+
await expect(webSearchForTool({ query: " " }, { fetchImpl: mockFetch("") })).rejects.toThrow(
|
|
148
|
+
"query is required",
|
|
149
|
+
);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
it("throws on non-2xx response", async () => {
|
|
153
|
+
await expect(
|
|
154
|
+
webSearchForTool({ query: "x" }, { fetchImpl: mockFetch("blocked", 429) }),
|
|
155
|
+
).rejects.toThrow("HTTP 429");
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
describe("webFetchForTool", () => {
|
|
160
|
+
function mockFetch(html: string, status = 200, contentType = "text/html; charset=utf-8"): FetchLike {
|
|
161
|
+
return async () =>
|
|
162
|
+
new Response(html, {
|
|
163
|
+
status,
|
|
164
|
+
headers: { "content-type": contentType },
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
it("fetches and converts html to plain text with title", async () => {
|
|
169
|
+
const output = await webFetchForTool(
|
|
170
|
+
{ url: "https://example.com/page" },
|
|
171
|
+
{ fetchImpl: mockFetch(WEB_FETCH_HTML) },
|
|
172
|
+
);
|
|
173
|
+
expect(output.title).toBe("Fetch & Me");
|
|
174
|
+
expect(output.text).toContain("Hello World");
|
|
175
|
+
expect(output.text).toContain("Second paragraph\nwith a break.");
|
|
176
|
+
expect(output.text).not.toContain("alert");
|
|
177
|
+
expect(output.contentType).toContain("text/html");
|
|
178
|
+
expect(output.chars).toBe(output.text.length);
|
|
179
|
+
expect(output.truncated).toBe(false);
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("truncates text beyond maxChars", async () => {
|
|
183
|
+
const output = await webFetchForTool(
|
|
184
|
+
{ url: "https://example.com/long", maxChars: 10 },
|
|
185
|
+
{ fetchImpl: mockFetch("<p>hello world and more</p>") },
|
|
186
|
+
);
|
|
187
|
+
expect(output.text).toBe("hello worl");
|
|
188
|
+
expect(output.truncated).toBe(true);
|
|
189
|
+
expect(output.chars).toBe(10);
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
it("truncates oversized response bodies", async () => {
|
|
193
|
+
const big = `<!DOCTYPE html><html><body><p>${"a".repeat(600 * 1024)}</p></body></html>`;
|
|
194
|
+
const output = await webFetchForTool(
|
|
195
|
+
{ url: "https://example.com/big" },
|
|
196
|
+
{ fetchImpl: mockFetch(big) },
|
|
197
|
+
);
|
|
198
|
+
expect(output.truncated).toBe(true);
|
|
199
|
+
expect(output.text.length).toBeLessThan(600 * 1024);
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it("rejects non-http(s) protocols", async () => {
|
|
203
|
+
await expect(
|
|
204
|
+
webFetchForTool({ url: "file:///etc/passwd" }, { fetchImpl: mockFetch("") }),
|
|
205
|
+
).rejects.toThrow("unsupported protocol");
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
it("rejects invalid urls", async () => {
|
|
209
|
+
await expect(
|
|
210
|
+
webFetchForTool({ url: "not a url" }, { fetchImpl: mockFetch("") }),
|
|
211
|
+
).rejects.toThrow("invalid URL");
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it("throws on missing url and non-2xx", async () => {
|
|
215
|
+
await expect(webFetchForTool({ url: " " })).rejects.toThrow("url is required");
|
|
216
|
+
await expect(
|
|
217
|
+
webFetchForTool({ url: "https://example.com/404" }, { fetchImpl: mockFetch("nf", 404) }),
|
|
218
|
+
).rejects.toThrow("HTTP 404");
|
|
219
|
+
});
|
|
220
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"noEmit": false,
|
|
5
|
+
"outDir": "./dist",
|
|
6
|
+
"rootDir": "./src",
|
|
7
|
+
"declaration": true,
|
|
8
|
+
"declarationMap": false,
|
|
9
|
+
"sourceMap": false
|
|
10
|
+
},
|
|
11
|
+
"include": ["src/*.ts"],
|
|
12
|
+
"exclude": ["src/__tests__/**"]
|
|
13
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "NodeNext",
|
|
5
|
+
"moduleResolution": "NodeNext",
|
|
6
|
+
"strict": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"skipLibCheck": true,
|
|
9
|
+
"forceConsistentCasingInFileNames": true,
|
|
10
|
+
"noEmit": true
|
|
11
|
+
},
|
|
12
|
+
"include": ["src/**/*.ts", "vitest.config.ts"]
|
|
13
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "chatccc",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.242",
|
|
4
4
|
"description": "Feishu bot bridge for Claude Code",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
},
|
|
12
12
|
"files": [
|
|
13
13
|
"src/",
|
|
14
|
+
"deepccc-agent/",
|
|
14
15
|
"bin/",
|
|
15
16
|
"scripts/postinstall-sharp-check.mjs",
|
|
16
17
|
"demo/ilink_echo_probe.ts",
|
|
@@ -43,6 +44,7 @@
|
|
|
43
44
|
"demo:ilink-echo": "tsx demo/ilink_echo_probe.ts",
|
|
44
45
|
"claude-proxy": "tsx src/litellm-proxy.ts",
|
|
45
46
|
"test": "vitest run",
|
|
47
|
+
"test:deepccc": "vitest run --root deepccc-agent",
|
|
46
48
|
"test:watch": "vitest",
|
|
47
49
|
"postinstall": "node scripts/postinstall-sharp-check.mjs"
|
|
48
50
|
},
|
|
@@ -4,8 +4,8 @@ import { join } from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
6
6
|
|
|
7
|
-
import { config } from "
|
|
8
|
-
import { estimateBuiltinContextTokens } from "
|
|
7
|
+
import { config } from "../../deepccc-agent/src/config.ts";
|
|
8
|
+
import { estimateBuiltinContextTokens } from "../../deepccc-agent/src/context.ts";
|
|
9
9
|
|
|
10
10
|
const streamTextMock = vi.fn();
|
|
11
11
|
const generateTextMock = vi.fn();
|
|
@@ -27,7 +27,7 @@ vi.mock("ai", () => ({
|
|
|
27
27
|
tool: vi.fn((definition: unknown) => definition),
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
|
-
vi.mock("
|
|
30
|
+
vi.mock("../../deepccc-agent/src/raw-stream-log.js", () => ({
|
|
31
31
|
createRawStreamLog: createRawStreamLogMock,
|
|
32
32
|
}));
|
|
33
33
|
|
|
@@ -57,7 +57,7 @@ afterEach(() => {
|
|
|
57
57
|
|
|
58
58
|
describe("ChatSession context management", () => {
|
|
59
59
|
it("keeps the generalized evidence gate in the stable system prompt prefix", async () => {
|
|
60
|
-
const { ChatSession } = await import("
|
|
60
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
61
61
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-evidence-gate-"));
|
|
62
62
|
await writeFile(join(dir, "AGENTS.md"), "PROJECT GUIDANCE MARKER", "utf-8");
|
|
63
63
|
streamTextMock.mockReturnValueOnce({ textStream: textStream("done") });
|
|
@@ -93,7 +93,7 @@ describe("ChatSession context management", () => {
|
|
|
93
93
|
});
|
|
94
94
|
|
|
95
95
|
it("keeps execution discipline sections in the stable system prompt prefix", async () => {
|
|
96
|
-
const { ChatSession } = await import("
|
|
96
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
97
97
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-discipline-"));
|
|
98
98
|
await writeFile(join(dir, "AGENTS.md"), "PROJECT GUIDANCE MARKER", "utf-8");
|
|
99
99
|
streamTextMock.mockReturnValueOnce({ textStream: textStream("done") });
|
|
@@ -130,7 +130,7 @@ describe("ChatSession context management", () => {
|
|
|
130
130
|
});
|
|
131
131
|
|
|
132
132
|
it("injects cwd project instruction files before runtime workspace details", async () => {
|
|
133
|
-
const { ChatSession } = await import("
|
|
133
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
134
134
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-instructions-"));
|
|
135
135
|
await writeFile(join(dir, "AGENTS.md"), "agents root guidance", "utf-8");
|
|
136
136
|
await writeFile(join(dir, "AGENTS.local.md"), "agents local guidance", "utf-8");
|
|
@@ -165,7 +165,7 @@ describe("ChatSession context management", () => {
|
|
|
165
165
|
});
|
|
166
166
|
|
|
167
167
|
it("places the volatile skills index at the very end of system prompt", async () => {
|
|
168
|
-
const { ChatSession } = await import("
|
|
168
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
169
169
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-skill-order-"));
|
|
170
170
|
const skillsDir = join(dir, "skills");
|
|
171
171
|
await mkdir(join(skillsDir, "demo-skill"), { recursive: true });
|
|
@@ -199,7 +199,7 @@ describe("ChatSession context management", () => {
|
|
|
199
199
|
});
|
|
200
200
|
|
|
201
201
|
it("does not read project instruction files from parent directories", async () => {
|
|
202
|
-
const { ChatSession } = await import("
|
|
202
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
203
203
|
const parent = await mkdtemp(join(tmpdir(), "deepccc-session-parent-instructions-"));
|
|
204
204
|
const child = join(parent, "child");
|
|
205
205
|
await mkdir(child);
|
|
@@ -220,7 +220,7 @@ describe("ChatSession context management", () => {
|
|
|
220
220
|
});
|
|
221
221
|
|
|
222
222
|
it("uses loop-finished stopping by default", async () => {
|
|
223
|
-
const { ChatSession } = await import("
|
|
223
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
224
224
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-unlimited-"));
|
|
225
225
|
streamTextMock.mockReturnValueOnce({ textStream: textStream("done") });
|
|
226
226
|
|
|
@@ -239,7 +239,7 @@ describe("ChatSession context management", () => {
|
|
|
239
239
|
});
|
|
240
240
|
|
|
241
241
|
it("uses a configured tool step limit when provided", async () => {
|
|
242
|
-
const { ChatSession } = await import("
|
|
242
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
243
243
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-step-budget-"));
|
|
244
244
|
streamTextMock.mockReturnValueOnce({ textStream: textStream("done") });
|
|
245
245
|
|
|
@@ -259,7 +259,7 @@ describe("ChatSession context management", () => {
|
|
|
259
259
|
});
|
|
260
260
|
|
|
261
261
|
it("loads persisted context, compacts older messages, and persists the new assistant reply", async () => {
|
|
262
|
-
const { ChatSession } = await import("
|
|
262
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
263
263
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-context-"));
|
|
264
264
|
|
|
265
265
|
const seed = new ChatSession(
|
|
@@ -307,7 +307,7 @@ describe("ChatSession context management", () => {
|
|
|
307
307
|
|
|
308
308
|
it("times out context compaction independently before reply generation", async () => {
|
|
309
309
|
vi.useFakeTimers();
|
|
310
|
-
const { ChatSession } = await import("
|
|
310
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
311
311
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-compaction-timeout-"));
|
|
312
312
|
const seed = new ChatSession(
|
|
313
313
|
{ apiKey: "sk-test" },
|
|
@@ -341,7 +341,7 @@ describe("ChatSession context management", () => {
|
|
|
341
341
|
});
|
|
342
342
|
|
|
343
343
|
it("streams tool calls and tool results from fullStream", async () => {
|
|
344
|
-
const { ChatSession } = await import("
|
|
344
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
345
345
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-tools-"));
|
|
346
346
|
const session = new ChatSession(
|
|
347
347
|
{ apiKey: "sk-test" },
|
|
@@ -379,7 +379,7 @@ describe("ChatSession context management", () => {
|
|
|
379
379
|
});
|
|
380
380
|
|
|
381
381
|
it("caps the total persisted tool transcript for a turn", async () => {
|
|
382
|
-
const { ChatSession } = await import("
|
|
382
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
383
383
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-tool-cap-"));
|
|
384
384
|
const session = new ChatSession(
|
|
385
385
|
{ apiKey: "sk-test" },
|
|
@@ -403,7 +403,7 @@ describe("ChatSession context management", () => {
|
|
|
403
403
|
});
|
|
404
404
|
|
|
405
405
|
it("persists structured tool calls alongside the text transcript", async () => {
|
|
406
|
-
const { ChatSession } = await import("
|
|
406
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
407
407
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-structured-tools-"));
|
|
408
408
|
const session = new ChatSession(
|
|
409
409
|
{ apiKey: "sk-test" },
|
|
@@ -430,7 +430,7 @@ describe("ChatSession context management", () => {
|
|
|
430
430
|
});
|
|
431
431
|
|
|
432
432
|
it("records tool errors and preserves tool call order in structured tool calls", async () => {
|
|
433
|
-
const { ChatSession } = await import("
|
|
433
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
434
434
|
const dir = await mkdtemp(join(tmpdir(), "deepccc-session-structured-tools-order-"));
|
|
435
435
|
const session = new ChatSession(
|
|
436
436
|
{ apiKey: "sk-test" },
|
|
@@ -459,7 +459,7 @@ describe("ChatSession context management", () => {
|
|
|
459
459
|
});
|
|
460
460
|
|
|
461
461
|
it("writes raw DeepCCC fullStream parts when raw stream logs are enabled", async () => {
|
|
462
|
-
const { ChatSession } = await import("
|
|
462
|
+
const { ChatSession } = await import("../../deepccc-agent/src/index.ts");
|
|
463
463
|
config.rawStreamLogs = {
|
|
464
464
|
enabled: true,
|
|
465
465
|
maxBytesPerTurn: 4096,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
|
-
import { ChatSession } from "
|
|
4
|
-
import { config } from "
|
|
3
|
+
import { ChatSession } from "../../deepccc-agent/src/index.ts";
|
|
4
|
+
import { config } from "../../deepccc-agent/src/config.ts";
|
|
5
5
|
|
|
6
6
|
const originalDeepSeekApiKey = process.env.DEEPSEEK_API_KEY;
|
|
7
7
|
const originalDeepCccApiKey = config.apiKey;
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
listBuiltinContextSessions,
|
|
13
13
|
newBuiltinSessionId,
|
|
14
14
|
serializeMessagesForSummary,
|
|
15
|
-
} from "
|
|
15
|
+
} from "../../deepccc-agent/src/context.ts";
|
|
16
16
|
|
|
17
17
|
describe("BuiltinContextManager", () => {
|
|
18
18
|
it("keeps recent messages within the token budget instead of a fixed count", () => {
|
|
@@ -31,7 +31,7 @@ vi.mock("ai", () => ({
|
|
|
31
31
|
tool: vi.fn((definition: unknown) => definition),
|
|
32
32
|
}));
|
|
33
33
|
|
|
34
|
-
vi.mock("
|
|
34
|
+
vi.mock("../../deepccc-agent/src/raw-stream-log.ts", () => ({
|
|
35
35
|
createRawStreamLog: vi.fn().mockResolvedValue(null),
|
|
36
36
|
}));
|
|
37
37
|
|
|
@@ -41,9 +41,9 @@ import {
|
|
|
41
41
|
isDangerousCommand,
|
|
42
42
|
matchRule,
|
|
43
43
|
reloadAllowRules,
|
|
44
|
-
} from "
|
|
45
|
-
import { createBuiltinFileTools } from "
|
|
46
|
-
import { ChatSession } from "
|
|
44
|
+
} from "../../deepccc-agent/src/permissions.ts";
|
|
45
|
+
import { createBuiltinFileTools } from "../../deepccc-agent/src/file-tools.ts";
|
|
46
|
+
import { ChatSession } from "../../deepccc-agent/src/index.ts";
|
|
47
47
|
|
|
48
48
|
const streamTextMock = aiMocks.streamText;
|
|
49
49
|
const generateTextMock = aiMocks.generateText;
|
|
@@ -5,7 +5,7 @@ import { gzipSync } from "node:zlib";
|
|
|
5
5
|
|
|
6
6
|
import { describe, expect, it } from "vitest";
|
|
7
7
|
|
|
8
|
-
import { searchBuiltinSessions } from "
|
|
8
|
+
import { searchBuiltinSessions } from "../../deepccc-agent/src/session-search.ts";
|
|
9
9
|
|
|
10
10
|
interface TestMessage {
|
|
11
11
|
role: "user" | "assistant";
|
|
@@ -4,8 +4,8 @@ import { join } from "node:path";
|
|
|
4
4
|
|
|
5
5
|
import { describe, expect, it } from "vitest";
|
|
6
6
|
|
|
7
|
-
import { defaultBuiltinSessionId } from "
|
|
8
|
-
import { resolveBuiltinSession } from "
|
|
7
|
+
import { defaultBuiltinSessionId } from "../../deepccc-agent/src/context.ts";
|
|
8
|
+
import { resolveBuiltinSession } from "../../deepccc-agent/src/session-select.ts";
|
|
9
9
|
|
|
10
10
|
async function writeSession(
|
|
11
11
|
contextDir: string,
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
|
-
import { createCtrlCState } from "
|
|
3
|
+
import { createCtrlCState } from "../../deepccc-agent/src/sigint.ts";
|
|
4
4
|
|
|
5
5
|
describe("builtin CLI Ctrl+C state", () => {
|
|
6
6
|
it("requires two presses to interrupt an active generation", () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "vitest";
|
|
2
2
|
|
|
3
|
-
import type { ChatEvent } from "
|
|
3
|
+
import type { ChatEvent } from "../../deepccc-agent/src/index.ts";
|
|
4
4
|
import { reduceProgress, summarizeToolInput, summarizeToolResult } from "../progress/reducer.ts";
|
|
5
5
|
import { progressView } from "../progress/view.ts";
|
|
6
6
|
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { ChatSession, type ChatSessionConfig, type ChatSessionOptions } from "
|
|
1
|
+
import { ChatSession, type ChatSessionConfig, type ChatSessionOptions } from "../../deepccc-agent/src/index.ts";
|
|
2
2
|
import {
|
|
3
3
|
getBuiltinContextSession,
|
|
4
4
|
newBuiltinSessionId,
|
|
5
5
|
normalizeBuiltinSessionId,
|
|
6
|
-
} from "
|
|
6
|
+
} from "../../deepccc-agent/src/context.ts";
|
|
7
7
|
import { config, CCC_SESSION_PREFIX } from "../config.ts";
|
|
8
8
|
import type {
|
|
9
9
|
CreateSessionResult,
|
package/src/progress/reducer.ts
CHANGED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|