@muyichengshayu/promptx 0.2.13 → 0.2.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/CHANGELOG.md +11 -0
- package/apps/server/src/agentSessionDiscovery.js +180 -7
- package/apps/web/dist/assets/{CodexSessionManagerDialog-Dic9kMHK.js → CodexSessionManagerDialog-y7O-JTxP.js} +1 -1
- package/apps/web/dist/assets/{TaskDiffReviewDialog-CKiZdXqi.js → TaskDiffReviewDialog-CTr_zoAn.js} +1 -1
- package/apps/web/dist/assets/{WorkbenchSettingsDialog-CP0z90bm.js → WorkbenchSettingsDialog-Bf2DCuN_.js} +1 -1
- package/apps/web/dist/assets/{WorkbenchView-D1oxqNr4.css → WorkbenchView-CK1snPBz.css} +1 -1
- package/apps/web/dist/assets/WorkbenchView-Gq3mmtsK.js +60 -0
- package/apps/web/dist/assets/index-Co1Ssha9.js +2 -0
- package/apps/web/dist/index.html +1 -1
- package/package.json +21 -14
- package/apps/runner/src/engines/claudeCodeRunner.test.js +0 -467
- package/apps/runner/src/engines/kimiCodeRunner.test.js +0 -127
- package/apps/runner/src/engines/openCodeRunner.test.js +0 -236
- package/apps/runner/src/engines/runnerContract.test.js +0 -449
- package/apps/runner/src/engines/shellRunner.test.js +0 -46
- package/apps/runner/src/runManager.test.js +0 -913
- package/apps/runner/src/serverClient.test.js +0 -93
- package/apps/server/src/agentSessionDiscovery.test.js +0 -186
- package/apps/server/src/appPaths.test.js +0 -52
- package/apps/server/src/assetRoutes.test.js +0 -168
- package/apps/server/src/codex.test.js +0 -518
- package/apps/server/src/codexRoutes.test.js +0 -376
- package/apps/server/src/codexRuns.test.js +0 -160
- package/apps/server/src/codexSessions.test.js +0 -369
- package/apps/server/src/db.test.js +0 -182
- package/apps/server/src/gitDiff.test.js +0 -542
- package/apps/server/src/gitDiffClient.test.js +0 -140
- package/apps/server/src/internalRoutes.test.js +0 -134
- package/apps/server/src/maintenance.test.js +0 -154
- package/apps/server/src/processControl.test.js +0 -147
- package/apps/server/src/relayClient.test.js +0 -478
- package/apps/server/src/relayConfig.test.js +0 -73
- package/apps/server/src/relayProtocol.test.js +0 -49
- package/apps/server/src/relayServer.test.js +0 -798
- package/apps/server/src/relayTenants.test.js +0 -137
- package/apps/server/src/relayUsageStore.test.js +0 -65
- package/apps/server/src/repository.test.js +0 -150
- package/apps/server/src/runDispatchService.test.js +0 -563
- package/apps/server/src/runEventIngest.test.js +0 -225
- package/apps/server/src/runRecovery.test.js +0 -73
- package/apps/server/src/runnerClient.test.js +0 -80
- package/apps/server/src/runnerDispatch.test.js +0 -136
- package/apps/server/src/systemConfig.test.js +0 -112
- package/apps/server/src/systemRoutes.test.js +0 -319
- package/apps/server/src/taskRoutes.test.js +0 -775
- package/apps/server/src/upload.test.js +0 -30
- package/apps/server/src/webAppRoutes.test.js +0 -67
- package/apps/server/src/workspaceFiles.test.js +0 -279
- package/apps/web/dist/assets/WorkbenchView-noayQwj4.js +0 -60
- package/apps/web/dist/assets/index-HLkdzIYF.js +0 -2
- package/packages/shared/src/dailyLogStream.test.js +0 -29
- package/packages/shared/src/shellCommands.test.js +0 -45
|
@@ -1,319 +0,0 @@
|
|
|
1
|
-
import assert from 'node:assert/strict'
|
|
2
|
-
import fs from 'node:fs'
|
|
3
|
-
import os from 'node:os'
|
|
4
|
-
import path from 'node:path'
|
|
5
|
-
import test from 'node:test'
|
|
6
|
-
import Fastify from 'fastify'
|
|
7
|
-
|
|
8
|
-
import { buildInternalAuthHeaders } from './internalAuth.js'
|
|
9
|
-
import { registerSystemRoutes } from './systemRoutes.js'
|
|
10
|
-
|
|
11
|
-
function createTestServices(overrides = {}) {
|
|
12
|
-
const runnerUpdates = []
|
|
13
|
-
const relayUpdates = []
|
|
14
|
-
|
|
15
|
-
const services = {
|
|
16
|
-
getGitDiffWorkerDiagnostics: () => ({ healthy: true }),
|
|
17
|
-
localBaseUrl: 'http://127.0.0.1:3001',
|
|
18
|
-
maintenanceService: {
|
|
19
|
-
getDiagnostics: () => ({ lastCleanupAt: null }),
|
|
20
|
-
runCleanup: () => ({ removedFiles: 0 }),
|
|
21
|
-
},
|
|
22
|
-
promptxVersion: '1.2.3',
|
|
23
|
-
relayClient: {
|
|
24
|
-
getStatus: () => ({ enabled: false }),
|
|
25
|
-
reconnect: () => true,
|
|
26
|
-
updateConfig: (payload) => {
|
|
27
|
-
relayUpdates.push(payload)
|
|
28
|
-
},
|
|
29
|
-
},
|
|
30
|
-
runRecoveryService: {
|
|
31
|
-
getDiagnostics: () => ({ recoveredRuns: 0 }),
|
|
32
|
-
},
|
|
33
|
-
runnerClient: {
|
|
34
|
-
baseUrl: 'http://127.0.0.1:3002',
|
|
35
|
-
getDiagnostics: async () => ({
|
|
36
|
-
runner: {
|
|
37
|
-
activeRuns: 1,
|
|
38
|
-
queuedRuns: 0,
|
|
39
|
-
},
|
|
40
|
-
}),
|
|
41
|
-
updateConfig: async (payload) => {
|
|
42
|
-
runnerUpdates.push(payload)
|
|
43
|
-
},
|
|
44
|
-
},
|
|
45
|
-
...overrides,
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return {
|
|
49
|
-
...services,
|
|
50
|
-
relayUpdates,
|
|
51
|
-
runnerUpdates,
|
|
52
|
-
}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
async function withTestApp(t, overrides, run) {
|
|
56
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-system-routes-'))
|
|
57
|
-
const originalEnv = {
|
|
58
|
-
PROMPTX_DATA_DIR: process.env.PROMPTX_DATA_DIR,
|
|
59
|
-
PROMPTX_RUNNER_MAX_CONCURRENT_RUNS: process.env.PROMPTX_RUNNER_MAX_CONCURRENT_RUNS,
|
|
60
|
-
PROMPTX_RELAY_URL: process.env.PROMPTX_RELAY_URL,
|
|
61
|
-
PROMPTX_RELAY_DEVICE_ID: process.env.PROMPTX_RELAY_DEVICE_ID,
|
|
62
|
-
PROMPTX_RELAY_DEVICE_TOKEN: process.env.PROMPTX_RELAY_DEVICE_TOKEN,
|
|
63
|
-
PROMPTX_RELAY_ALLOW_REMOTE_SHELL: process.env.PROMPTX_RELAY_ALLOW_REMOTE_SHELL,
|
|
64
|
-
PROMPTX_RELAY_ENABLED: process.env.PROMPTX_RELAY_ENABLED,
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
delete process.env.PROMPTX_RUNNER_MAX_CONCURRENT_RUNS
|
|
68
|
-
delete process.env.PROMPTX_RELAY_URL
|
|
69
|
-
delete process.env.PROMPTX_RELAY_DEVICE_ID
|
|
70
|
-
delete process.env.PROMPTX_RELAY_DEVICE_TOKEN
|
|
71
|
-
delete process.env.PROMPTX_RELAY_ALLOW_REMOTE_SHELL
|
|
72
|
-
delete process.env.PROMPTX_RELAY_ENABLED
|
|
73
|
-
process.env.PROMPTX_DATA_DIR = tempDir
|
|
74
|
-
|
|
75
|
-
const services = createTestServices(overrides)
|
|
76
|
-
const app = Fastify()
|
|
77
|
-
registerSystemRoutes(app, services)
|
|
78
|
-
await app.ready()
|
|
79
|
-
|
|
80
|
-
try {
|
|
81
|
-
await run({ app, services, tempDir })
|
|
82
|
-
} finally {
|
|
83
|
-
await app.close()
|
|
84
|
-
Object.entries(originalEnv).forEach(([key, value]) => {
|
|
85
|
-
if (typeof value === 'string') {
|
|
86
|
-
process.env[key] = value
|
|
87
|
-
} else {
|
|
88
|
-
delete process.env[key]
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
fs.rmSync(tempDir, { recursive: true, force: true })
|
|
92
|
-
}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
test('system routes persist config and hot update runner when env does not override', async (t) => {
|
|
96
|
-
await withTestApp(t, {}, async ({ app, services }) => {
|
|
97
|
-
const response = await app.inject({
|
|
98
|
-
method: 'PUT',
|
|
99
|
-
url: '/api/system/config',
|
|
100
|
-
payload: {
|
|
101
|
-
runner: {
|
|
102
|
-
maxConcurrentRuns: 4,
|
|
103
|
-
},
|
|
104
|
-
},
|
|
105
|
-
})
|
|
106
|
-
|
|
107
|
-
assert.equal(response.statusCode, 200)
|
|
108
|
-
assert.deepEqual(response.json(), {
|
|
109
|
-
config: {
|
|
110
|
-
remoteCommandSecurity: {
|
|
111
|
-
mode: 'disabled',
|
|
112
|
-
trustedProxyTokenConfigured: false,
|
|
113
|
-
},
|
|
114
|
-
runner: {
|
|
115
|
-
maxConcurrentRuns: 4,
|
|
116
|
-
},
|
|
117
|
-
},
|
|
118
|
-
managedByEnv: {
|
|
119
|
-
runner: {
|
|
120
|
-
maxConcurrentRuns: false,
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
})
|
|
124
|
-
assert.deepEqual(services.runnerUpdates, [{ maxConcurrentRuns: 4 }])
|
|
125
|
-
})
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
test('system routes redact trusted proxy token in public and internal config responses', async (t) => {
|
|
129
|
-
await withTestApp(t, {}, async ({ app }) => {
|
|
130
|
-
const saveResponse = await app.inject({
|
|
131
|
-
method: 'PUT',
|
|
132
|
-
url: '/api/system/config',
|
|
133
|
-
payload: {
|
|
134
|
-
remoteCommandSecurity: {
|
|
135
|
-
mode: 'trusted-proxy',
|
|
136
|
-
trustedProxyToken: 'trusted-token',
|
|
137
|
-
},
|
|
138
|
-
},
|
|
139
|
-
})
|
|
140
|
-
|
|
141
|
-
assert.equal(saveResponse.statusCode, 200)
|
|
142
|
-
assert.deepEqual(saveResponse.json().config.remoteCommandSecurity, {
|
|
143
|
-
mode: 'trusted-proxy',
|
|
144
|
-
trustedProxyTokenConfigured: true,
|
|
145
|
-
})
|
|
146
|
-
|
|
147
|
-
const publicResponse = await app.inject({
|
|
148
|
-
method: 'GET',
|
|
149
|
-
url: '/api/system/config',
|
|
150
|
-
})
|
|
151
|
-
assert.equal(publicResponse.statusCode, 200)
|
|
152
|
-
assert.deepEqual(publicResponse.json().config.remoteCommandSecurity, {
|
|
153
|
-
mode: 'trusted-proxy',
|
|
154
|
-
trustedProxyTokenConfigured: true,
|
|
155
|
-
})
|
|
156
|
-
|
|
157
|
-
const internalResponse = await app.inject({
|
|
158
|
-
method: 'GET',
|
|
159
|
-
url: '/internal/system-config',
|
|
160
|
-
headers: buildInternalAuthHeaders(),
|
|
161
|
-
})
|
|
162
|
-
assert.equal(internalResponse.statusCode, 200)
|
|
163
|
-
assert.deepEqual(internalResponse.json().config.remoteCommandSecurity, {
|
|
164
|
-
mode: 'trusted-proxy',
|
|
165
|
-
trustedProxyTokenConfigured: true,
|
|
166
|
-
})
|
|
167
|
-
})
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
test('system routes keep saved config when runner hot update fails', async (t) => {
|
|
171
|
-
await withTestApp(t, {
|
|
172
|
-
runnerClient: {
|
|
173
|
-
baseUrl: 'http://127.0.0.1:3002',
|
|
174
|
-
getDiagnostics: async () => ({ runner: null }),
|
|
175
|
-
updateConfig: async () => {
|
|
176
|
-
const error = new Error('runner offline')
|
|
177
|
-
error.statusCode = 503
|
|
178
|
-
throw error
|
|
179
|
-
},
|
|
180
|
-
},
|
|
181
|
-
}, async ({ app }) => {
|
|
182
|
-
const response = await app.inject({
|
|
183
|
-
method: 'PUT',
|
|
184
|
-
url: '/api/system/config',
|
|
185
|
-
payload: {
|
|
186
|
-
runner: {
|
|
187
|
-
maxConcurrentRuns: 6,
|
|
188
|
-
},
|
|
189
|
-
},
|
|
190
|
-
})
|
|
191
|
-
|
|
192
|
-
assert.equal(response.statusCode, 503)
|
|
193
|
-
const payload = response.json()
|
|
194
|
-
assert.equal(payload.config.runner.maxConcurrentRuns, 6)
|
|
195
|
-
assert.equal(payload.managedByEnv.runner.maxConcurrentRuns, false)
|
|
196
|
-
assert.match(payload.message, /runner 热更新失败/)
|
|
197
|
-
})
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
test('system routes respect env managed runner config and expose internal endpoint', async (t) => {
|
|
201
|
-
await withTestApp(t, {}, async ({ app, services }) => {
|
|
202
|
-
process.env.PROMPTX_RUNNER_MAX_CONCURRENT_RUNS = '7'
|
|
203
|
-
|
|
204
|
-
const response = await app.inject({
|
|
205
|
-
method: 'PUT',
|
|
206
|
-
url: '/api/system/config',
|
|
207
|
-
payload: {
|
|
208
|
-
runner: {
|
|
209
|
-
maxConcurrentRuns: 3,
|
|
210
|
-
},
|
|
211
|
-
},
|
|
212
|
-
})
|
|
213
|
-
|
|
214
|
-
assert.equal(response.statusCode, 200)
|
|
215
|
-
assert.equal(response.json().config.runner.maxConcurrentRuns, 7)
|
|
216
|
-
assert.deepEqual(services.runnerUpdates, [])
|
|
217
|
-
|
|
218
|
-
const unauthorized = await app.inject({
|
|
219
|
-
method: 'GET',
|
|
220
|
-
url: '/internal/system-config',
|
|
221
|
-
})
|
|
222
|
-
assert.equal(unauthorized.statusCode, 401)
|
|
223
|
-
|
|
224
|
-
const internalResponse = await app.inject({
|
|
225
|
-
method: 'GET',
|
|
226
|
-
url: '/internal/system-config',
|
|
227
|
-
headers: buildInternalAuthHeaders(),
|
|
228
|
-
})
|
|
229
|
-
assert.equal(internalResponse.statusCode, 200)
|
|
230
|
-
assert.equal(internalResponse.json().config.runner.maxConcurrentRuns, 7)
|
|
231
|
-
})
|
|
232
|
-
})
|
|
233
|
-
|
|
234
|
-
test('runtime diagnostics degrade gracefully when runner diagnostics fail', async (t) => {
|
|
235
|
-
await withTestApp(t, {
|
|
236
|
-
runnerClient: {
|
|
237
|
-
baseUrl: 'http://127.0.0.1:3002',
|
|
238
|
-
getDiagnostics: async () => {
|
|
239
|
-
throw new Error('timeout')
|
|
240
|
-
},
|
|
241
|
-
updateConfig: async () => {},
|
|
242
|
-
},
|
|
243
|
-
}, async ({ app }) => {
|
|
244
|
-
const response = await app.inject({
|
|
245
|
-
method: 'GET',
|
|
246
|
-
url: '/api/diagnostics/runtime',
|
|
247
|
-
})
|
|
248
|
-
|
|
249
|
-
assert.equal(response.statusCode, 200)
|
|
250
|
-
const payload = response.json()
|
|
251
|
-
assert.equal(payload.runner.ok, false)
|
|
252
|
-
assert.equal(payload.runner.baseUrl, 'http://127.0.0.1:3002')
|
|
253
|
-
assert.match(payload.runner.message, /timeout/)
|
|
254
|
-
assert.deepEqual(payload.gitDiffWorker, { healthy: true })
|
|
255
|
-
assert.deepEqual(payload.recovery, { recoveredRuns: 0 })
|
|
256
|
-
assert.deepEqual(payload.maintenance, { lastCleanupAt: null })
|
|
257
|
-
})
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
test('relay reconnect endpoint triggers client reconnect when enabled', async (t) => {
|
|
261
|
-
let reconnectCalled = 0
|
|
262
|
-
await withTestApp(t, {
|
|
263
|
-
relayClient: {
|
|
264
|
-
getStatus: () => ({ enabled: true, connected: false }),
|
|
265
|
-
reconnect: () => {
|
|
266
|
-
reconnectCalled += 1
|
|
267
|
-
return true
|
|
268
|
-
},
|
|
269
|
-
updateConfig: () => {},
|
|
270
|
-
},
|
|
271
|
-
}, async ({ app }) => {
|
|
272
|
-
const response = await app.inject({
|
|
273
|
-
method: 'POST',
|
|
274
|
-
url: '/api/relay/reconnect',
|
|
275
|
-
})
|
|
276
|
-
|
|
277
|
-
assert.equal(response.statusCode, 200)
|
|
278
|
-
assert.equal(response.json().ok, true)
|
|
279
|
-
assert.equal(reconnectCalled, 1)
|
|
280
|
-
})
|
|
281
|
-
})
|
|
282
|
-
|
|
283
|
-
test('relay reconnect endpoint rejects when relay is disabled', async (t) => {
|
|
284
|
-
await withTestApp(t, {
|
|
285
|
-
relayClient: {
|
|
286
|
-
getStatus: () => ({ enabled: false, connected: false }),
|
|
287
|
-
reconnect: () => true,
|
|
288
|
-
updateConfig: () => {},
|
|
289
|
-
},
|
|
290
|
-
}, async ({ app }) => {
|
|
291
|
-
const response = await app.inject({
|
|
292
|
-
method: 'POST',
|
|
293
|
-
url: '/api/relay/reconnect',
|
|
294
|
-
})
|
|
295
|
-
|
|
296
|
-
assert.equal(response.statusCode, 400)
|
|
297
|
-
assert.match(response.json().message, /尚未启用/)
|
|
298
|
-
})
|
|
299
|
-
})
|
|
300
|
-
|
|
301
|
-
test('relay config persists allowRemoteShell and hot updates relay client config', async (t) => {
|
|
302
|
-
await withTestApp(t, {}, async ({ app, services }) => {
|
|
303
|
-
const response = await app.inject({
|
|
304
|
-
method: 'PUT',
|
|
305
|
-
url: '/api/relay/config',
|
|
306
|
-
payload: {
|
|
307
|
-
enabled: true,
|
|
308
|
-
relayUrl: 'https://relay.example.com',
|
|
309
|
-
deviceId: 'my-device',
|
|
310
|
-
deviceToken: 'secret-token',
|
|
311
|
-
allowRemoteShell: true,
|
|
312
|
-
},
|
|
313
|
-
})
|
|
314
|
-
|
|
315
|
-
assert.equal(response.statusCode, 200)
|
|
316
|
-
assert.equal(response.json().config.allowRemoteShell, true)
|
|
317
|
-
assert.equal(services.relayUpdates[0]?.allowRemoteShell, true)
|
|
318
|
-
})
|
|
319
|
-
})
|