nuwaxcode 1.1.28 → 1.1.30
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/package.json +76 -7
- package/script/build.ts +1 -1
- package/src/cli/cmd/tui/component/logo.tsx +1 -1
- package/src/cli/ui.ts +4 -4
- package/test/acp/system-prompt.test.ts +262 -0
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"$schema": "https://json.schemastore.org/package.json",
|
|
3
|
-
"version": "1.1.
|
|
3
|
+
"version": "1.1.30",
|
|
4
4
|
"name": "nuwaxcode",
|
|
5
|
-
|
|
5
|
+
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"scripts": {
|
|
8
8
|
"typecheck": "tsgo --noEmit",
|
|
@@ -34,18 +34,87 @@
|
|
|
34
34
|
"@parcel/watcher-linux-x64-musl": "2.5.1",
|
|
35
35
|
"@parcel/watcher-win32-x64": "2.5.1",
|
|
36
36
|
"@standard-schema/spec": "1.0.0",
|
|
37
|
-
"@tsconfig/bun": "
|
|
37
|
+
"@tsconfig/bun": "1.0.9",
|
|
38
38
|
"@types/babel__core": "7.20.5",
|
|
39
|
-
"@types/bun": "
|
|
39
|
+
"@types/bun": "1.3.6",
|
|
40
40
|
"@types/turndown": "5.0.5",
|
|
41
41
|
"@types/yargs": "17.0.33",
|
|
42
|
-
"@typescript/native-preview": "
|
|
43
|
-
"typescript": "
|
|
42
|
+
"@typescript/native-preview": "7.0.0-dev.20251207.1",
|
|
43
|
+
"typescript": "5.8.2",
|
|
44
44
|
"vscode-languageserver-types": "3.17.5",
|
|
45
45
|
"why-is-node-running": "3.2.2",
|
|
46
46
|
"zod-to-json-schema": "3.24.5"
|
|
47
47
|
},
|
|
48
|
-
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"@actions/core": "1.11.1",
|
|
50
|
+
"@actions/github": "6.0.1",
|
|
51
|
+
"@agentclientprotocol/sdk": "0.5.1",
|
|
52
|
+
"@ai-sdk/amazon-bedrock": "3.0.73",
|
|
53
|
+
"@ai-sdk/anthropic": "2.0.57",
|
|
54
|
+
"@ai-sdk/azure": "2.0.91",
|
|
55
|
+
"@ai-sdk/cerebras": "1.0.34",
|
|
56
|
+
"@ai-sdk/cohere": "2.0.22",
|
|
57
|
+
"@ai-sdk/deepinfra": "1.0.31",
|
|
58
|
+
"@ai-sdk/gateway": "2.0.25",
|
|
59
|
+
"@ai-sdk/google": "2.0.52",
|
|
60
|
+
"@ai-sdk/google-vertex": "3.0.97",
|
|
61
|
+
"@ai-sdk/groq": "2.0.34",
|
|
62
|
+
"@ai-sdk/mistral": "2.0.27",
|
|
63
|
+
"@ai-sdk/openai": "2.0.89",
|
|
64
|
+
"@ai-sdk/openai-compatible": "1.0.30",
|
|
65
|
+
"@ai-sdk/perplexity": "2.0.23",
|
|
66
|
+
"@ai-sdk/provider": "2.0.1",
|
|
67
|
+
"@ai-sdk/provider-utils": "3.0.20",
|
|
68
|
+
"@ai-sdk/togetherai": "1.0.31",
|
|
69
|
+
"@ai-sdk/vercel": "1.0.31",
|
|
70
|
+
"@ai-sdk/xai": "2.0.51",
|
|
71
|
+
"@clack/prompts": "1.0.0-alpha.1",
|
|
72
|
+
"@gitlab/gitlab-ai-provider": "3.1.2",
|
|
73
|
+
"@hono/standard-validator": "0.1.5",
|
|
74
|
+
"@hono/zod-validator": "0.4.2",
|
|
75
|
+
"@modelcontextprotocol/sdk": "1.25.2",
|
|
76
|
+
"@octokit/graphql": "9.0.2",
|
|
77
|
+
"@octokit/rest": "22.0.0",
|
|
78
|
+
"@openauthjs/openauth": "0.0.0-20250322224806",
|
|
79
|
+
"@openrouter/ai-sdk-provider": "1.5.2",
|
|
80
|
+
"@opentui/core": "0.1.74",
|
|
81
|
+
"@opentui/solid": "0.1.74",
|
|
82
|
+
"@parcel/watcher": "2.5.1",
|
|
83
|
+
"@pierre/diffs": "1.0.2",
|
|
84
|
+
"@solid-primitives/event-bus": "1.1.2",
|
|
85
|
+
"@solid-primitives/scheduled": "1.5.2",
|
|
86
|
+
"@standard-schema/spec": "1.0.0",
|
|
87
|
+
"@zip.js/zip.js": "2.7.62",
|
|
88
|
+
"ai": "5.0.119",
|
|
89
|
+
"bonjour-service": "1.3.0",
|
|
90
|
+
"bun-pty": "0.4.4",
|
|
91
|
+
"chokidar": "4.0.3",
|
|
92
|
+
"clipboardy": "4.0.0",
|
|
93
|
+
"decimal.js": "10.5.0",
|
|
94
|
+
"diff": "8.0.2",
|
|
95
|
+
"fuzzysort": "3.1.0",
|
|
96
|
+
"gray-matter": "4.0.3",
|
|
97
|
+
"hono": "4.10.7",
|
|
98
|
+
"hono-openapi": "1.1.2",
|
|
99
|
+
"ignore": "7.0.5",
|
|
100
|
+
"jsonc-parser": "3.3.1",
|
|
101
|
+
"minimatch": "10.0.3",
|
|
102
|
+
"open": "10.1.2",
|
|
103
|
+
"opentui-spinner": "0.0.6",
|
|
104
|
+
"partial-json": "0.1.7",
|
|
105
|
+
"remeda": "2.26.0",
|
|
106
|
+
"solid-js": "1.9.10",
|
|
107
|
+
"strip-ansi": "7.1.2",
|
|
108
|
+
"tree-sitter-bash": "0.25.0",
|
|
109
|
+
"turndown": "7.2.0",
|
|
110
|
+
"ulid": "3.0.1",
|
|
111
|
+
"vscode-jsonrpc": "8.2.1",
|
|
112
|
+
"web-tree-sitter": "0.25.10",
|
|
113
|
+
"xdg-basedir": "5.1.0",
|
|
114
|
+
"yargs": "18.0.0",
|
|
115
|
+
"zod": "4.1.8",
|
|
116
|
+
"zod-to-json-schema": "3.24.5"
|
|
117
|
+
},
|
|
49
118
|
"optionalDependencies": {
|
|
50
119
|
"nuwaxcode-darwin-arm64": "1.1.25",
|
|
51
120
|
"nuwaxcode-darwin-x64": "1.1.25",
|
package/script/build.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { useTheme, tint } from "@tui/context/theme"
|
|
|
8
8
|
// ~ = shadow top only (▀ with fg=shadow)
|
|
9
9
|
const SHADOW_MARKER = /[_^~]/
|
|
10
10
|
|
|
11
|
-
const LOGO_LEFT = [`
|
|
11
|
+
const LOGO_LEFT = [` `, `█▀▀▄ █ █ █ █ █▀▀█ ▀▄ ▄▀`, `█ █ █ █ █▄█▄█ █▄▄█ _█_ `, `▀ ▀ ▀▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀`]
|
|
12
12
|
|
|
13
13
|
const LOGO_RIGHT = [` ▄ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`, `█___ █__█ █__█ █^^^`, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`]
|
|
14
14
|
|
package/src/cli/ui.ts
CHANGED
|
@@ -4,10 +4,10 @@ import { NamedError } from "@opencode-ai/util/error"
|
|
|
4
4
|
|
|
5
5
|
export namespace UI {
|
|
6
6
|
const LOGO = [
|
|
7
|
-
[`
|
|
8
|
-
[
|
|
9
|
-
[
|
|
10
|
-
[
|
|
7
|
+
[` `, ` ▄ `],
|
|
8
|
+
[`█▀▀▄ █ █ █ █ █▀▀█ ▀▄ ▄▀ `, `█▀▀▀ █▀▀█ █▀▀█ █▀▀█`],
|
|
9
|
+
[`█ █ █ █ █ █ █ █▄▄█ ░█░ `, `█░░░ █░░█ █░░█ █▀▀▀`],
|
|
10
|
+
[`▀ ▀ ▀▀▀▀ ▀ ▀ ▀ ▀ ▀ ▀ ▀ `, `▀▀▀▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀▀`],
|
|
11
11
|
]
|
|
12
12
|
|
|
13
13
|
export const CancelledError = NamedError.create("UICancelledError", z.void())
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { describe, expect, test, beforeEach, mock } from "bun:test"
|
|
2
|
+
import type { AgentSideConnection } from "@agentclientprotocol/sdk"
|
|
3
|
+
import { z } from "zod"
|
|
4
|
+
|
|
5
|
+
// Mock the Log module
|
|
6
|
+
const logEntries: any[] = []
|
|
7
|
+
mock.module("../../src/util/log", () => {
|
|
8
|
+
return {
|
|
9
|
+
Log: {
|
|
10
|
+
create: () => ({
|
|
11
|
+
info: (msg: any, extra: any) => {
|
|
12
|
+
logEntries.push({ level: "INFO", msg, ...extra })
|
|
13
|
+
},
|
|
14
|
+
error: (msg: any, extra: any) => {
|
|
15
|
+
logEntries.push({ level: "ERROR", msg, ...extra })
|
|
16
|
+
},
|
|
17
|
+
debug: () => {},
|
|
18
|
+
warn: () => {},
|
|
19
|
+
time: () => ({ stop: () => {} })
|
|
20
|
+
}),
|
|
21
|
+
Level: z.enum(["DEBUG", "INFO", "WARN", "ERROR"])
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
// Dynamically import ACP after mocking
|
|
27
|
+
const { ACP } = await import("../../src/acp/agent")
|
|
28
|
+
|
|
29
|
+
describe("ACP System Prompt via _meta", () => {
|
|
30
|
+
let acp: import("../../src/acp/agent").ACP.Agent
|
|
31
|
+
let connection: AgentSideConnection
|
|
32
|
+
|
|
33
|
+
beforeEach(async () => {
|
|
34
|
+
// Clear logs
|
|
35
|
+
logEntries.length = 0
|
|
36
|
+
|
|
37
|
+
connection = {
|
|
38
|
+
async sessionUpdate() {},
|
|
39
|
+
async requestPermission() {
|
|
40
|
+
return { outcome: { outcome: "selected", optionId: "once" } } as any
|
|
41
|
+
}
|
|
42
|
+
} as any
|
|
43
|
+
|
|
44
|
+
const config = {
|
|
45
|
+
sdk: {
|
|
46
|
+
sessions: {
|
|
47
|
+
create: async () => ({ id: "test-session" })
|
|
48
|
+
},
|
|
49
|
+
events: {
|
|
50
|
+
subscribe: () => ({ async *[Symbol.asyncIterator]() {} })
|
|
51
|
+
}
|
|
52
|
+
} as any
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
acp = new ACP.Agent(connection, config)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test("should extract systemPrompt from _meta during session creation", async () => {
|
|
59
|
+
const customSystemPrompt = "你是 Nuwaxcode,一个强大的 AI 编程助手。请在回答前仔细思考..."
|
|
60
|
+
|
|
61
|
+
// Mock the session manager to capture the system prompt
|
|
62
|
+
let capturedSystemPrompt: string | { append: string } | undefined
|
|
63
|
+
acp["sessionManager"].create = async (cwd, mcpServers, model, systemPrompt) => {
|
|
64
|
+
capturedSystemPrompt = systemPrompt
|
|
65
|
+
return {
|
|
66
|
+
id: "test-session",
|
|
67
|
+
cwd,
|
|
68
|
+
mcpServers,
|
|
69
|
+
createdAt: new Date(),
|
|
70
|
+
model,
|
|
71
|
+
systemPrompt
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Mock loadSessionMode
|
|
76
|
+
acp["loadSessionMode"] = async () => ({
|
|
77
|
+
models: [{ providerID: "test", modelID: "test" }] as any,
|
|
78
|
+
modes: { availableModes: [], currentModeId: "default" },
|
|
79
|
+
sessionId: "test-session",
|
|
80
|
+
_meta: {}
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
const mockConfig = {
|
|
84
|
+
defaultModel: { providerID: "test", modelID: "test" },
|
|
85
|
+
sdk: acp["config"].sdk
|
|
86
|
+
}
|
|
87
|
+
acp["config"] = mockConfig as any
|
|
88
|
+
|
|
89
|
+
const params = {
|
|
90
|
+
cwd: "/test/directory",
|
|
91
|
+
mcpServers: [],
|
|
92
|
+
_meta: {
|
|
93
|
+
systemPrompt: customSystemPrompt
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
await acp.newSession(params as any)
|
|
98
|
+
|
|
99
|
+
expect(capturedSystemPrompt).toBe(customSystemPrompt)
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
test("should handle append-style system prompt", async () => {
|
|
103
|
+
const appendPrompt = { append: "请始终用中文回答问题。" }
|
|
104
|
+
|
|
105
|
+
let capturedSystemPrompt: string | { append: string } | undefined
|
|
106
|
+
acp["sessionManager"].create = async (cwd, mcpServers, model, systemPrompt) => {
|
|
107
|
+
capturedSystemPrompt = systemPrompt
|
|
108
|
+
return {
|
|
109
|
+
id: "test-session",
|
|
110
|
+
cwd,
|
|
111
|
+
mcpServers,
|
|
112
|
+
createdAt: new Date(),
|
|
113
|
+
model,
|
|
114
|
+
systemPrompt
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
acp["loadSessionMode"] = async () => ({
|
|
119
|
+
models: [{ providerID: "test", modelID: "test" }] as any,
|
|
120
|
+
modes: { availableModes: [], currentModeId: "default" },
|
|
121
|
+
sessionId: "test-session",
|
|
122
|
+
_meta: {}
|
|
123
|
+
})
|
|
124
|
+
|
|
125
|
+
const mockConfig = {
|
|
126
|
+
defaultModel: { providerID: "test", modelID: "test" },
|
|
127
|
+
sdk: acp["config"].sdk
|
|
128
|
+
}
|
|
129
|
+
acp["config"] = mockConfig as any
|
|
130
|
+
|
|
131
|
+
const params = {
|
|
132
|
+
cwd: "/test/directory",
|
|
133
|
+
mcpServers: [],
|
|
134
|
+
_meta: {
|
|
135
|
+
systemPrompt: appendPrompt
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
await acp.newSession(params as any)
|
|
140
|
+
|
|
141
|
+
expect(capturedSystemPrompt).toEqual(appendPrompt)
|
|
142
|
+
})
|
|
143
|
+
|
|
144
|
+
test("should work without _meta systemPrompt", async () => {
|
|
145
|
+
let capturedSystemPrompt: string | { append: string } | undefined
|
|
146
|
+
acp["sessionManager"].create = async (cwd, mcpServers, model, systemPrompt) => {
|
|
147
|
+
capturedSystemPrompt = systemPrompt
|
|
148
|
+
return {
|
|
149
|
+
id: "test-session",
|
|
150
|
+
cwd,
|
|
151
|
+
mcpServers,
|
|
152
|
+
createdAt: new Date(),
|
|
153
|
+
model,
|
|
154
|
+
systemPrompt
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
acp["loadSessionMode"] = async () => ({
|
|
159
|
+
models: [{ providerID: "test", modelID: "test" }] as any,
|
|
160
|
+
modes: { availableModes: [], currentModeId: "default" },
|
|
161
|
+
sessionId: "test-session",
|
|
162
|
+
_meta: {}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const mockConfig = {
|
|
166
|
+
defaultModel: { providerID: "test", modelID: "test" },
|
|
167
|
+
sdk: acp["config"].sdk
|
|
168
|
+
}
|
|
169
|
+
acp["config"] = mockConfig as any
|
|
170
|
+
|
|
171
|
+
const params = {
|
|
172
|
+
cwd: "/test/directory",
|
|
173
|
+
mcpServers: []
|
|
174
|
+
// No _meta
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
await acp.newSession(params as any)
|
|
178
|
+
|
|
179
|
+
expect(capturedSystemPrompt).toBeUndefined()
|
|
180
|
+
})
|
|
181
|
+
|
|
182
|
+
test("should work with empty _meta", async () => {
|
|
183
|
+
let capturedSystemPrompt: string | { append: string } | undefined
|
|
184
|
+
acp["sessionManager"].create = async (cwd, mcpServers, model, systemPrompt) => {
|
|
185
|
+
capturedSystemPrompt = systemPrompt
|
|
186
|
+
return {
|
|
187
|
+
id: "test-session",
|
|
188
|
+
cwd,
|
|
189
|
+
mcpServers,
|
|
190
|
+
createdAt: new Date(),
|
|
191
|
+
model,
|
|
192
|
+
systemPrompt
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
acp["loadSessionMode"] = async () => ({
|
|
197
|
+
models: [{ providerID: "test", modelID: "test" }] as any,
|
|
198
|
+
modes: { availableModes: [], currentModeId: "default" },
|
|
199
|
+
sessionId: "test-session",
|
|
200
|
+
_meta: {}
|
|
201
|
+
})
|
|
202
|
+
|
|
203
|
+
const mockConfig = {
|
|
204
|
+
defaultModel: { providerID: "test", modelID: "test" },
|
|
205
|
+
sdk: acp["config"].sdk
|
|
206
|
+
}
|
|
207
|
+
acp["config"] = mockConfig as any
|
|
208
|
+
|
|
209
|
+
const params = {
|
|
210
|
+
cwd: "/test/directory",
|
|
211
|
+
mcpServers: [],
|
|
212
|
+
_meta: {}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
await acp.newSession(params as any)
|
|
216
|
+
|
|
217
|
+
expect(capturedSystemPrompt).toBeUndefined()
|
|
218
|
+
})
|
|
219
|
+
|
|
220
|
+
test("should log when systemPrompt is provided", async () => {
|
|
221
|
+
const customSystemPrompt = "Test system prompt"
|
|
222
|
+
|
|
223
|
+
acp["sessionManager"].create = async (cwd, mcpServers, model, systemPrompt) => {
|
|
224
|
+
return {
|
|
225
|
+
id: "test-session",
|
|
226
|
+
cwd,
|
|
227
|
+
mcpServers,
|
|
228
|
+
createdAt: new Date(),
|
|
229
|
+
model,
|
|
230
|
+
systemPrompt
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
acp["loadSessionMode"] = async () => ({
|
|
235
|
+
models: [{ providerID: "test", modelID: "test" }] as any,
|
|
236
|
+
modes: { availableModes: [], currentModeId: "default" },
|
|
237
|
+
sessionId: "test-session",
|
|
238
|
+
_meta: {}
|
|
239
|
+
})
|
|
240
|
+
|
|
241
|
+
const mockConfig = {
|
|
242
|
+
defaultModel: { providerID: "test", modelID: "test" },
|
|
243
|
+
sdk: acp["config"].sdk
|
|
244
|
+
}
|
|
245
|
+
acp["config"] = mockConfig as any
|
|
246
|
+
|
|
247
|
+
const params = {
|
|
248
|
+
cwd: "/test/directory",
|
|
249
|
+
mcpServers: [],
|
|
250
|
+
_meta: {
|
|
251
|
+
systemPrompt: customSystemPrompt
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
await acp.newSession(params as any)
|
|
256
|
+
|
|
257
|
+
const hasSystemPromptLog = logEntries.some(entry =>
|
|
258
|
+
entry.hasSystemPrompt === true && entry.level === "INFO"
|
|
259
|
+
)
|
|
260
|
+
expect(hasSystemPromptLog).toBe(true)
|
|
261
|
+
})
|
|
262
|
+
})
|