@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.
Files changed (52) hide show
  1. package/CHANGELOG.md +11 -0
  2. package/apps/server/src/agentSessionDiscovery.js +180 -7
  3. package/apps/web/dist/assets/{CodexSessionManagerDialog-Dic9kMHK.js → CodexSessionManagerDialog-y7O-JTxP.js} +1 -1
  4. package/apps/web/dist/assets/{TaskDiffReviewDialog-CKiZdXqi.js → TaskDiffReviewDialog-CTr_zoAn.js} +1 -1
  5. package/apps/web/dist/assets/{WorkbenchSettingsDialog-CP0z90bm.js → WorkbenchSettingsDialog-Bf2DCuN_.js} +1 -1
  6. package/apps/web/dist/assets/{WorkbenchView-D1oxqNr4.css → WorkbenchView-CK1snPBz.css} +1 -1
  7. package/apps/web/dist/assets/WorkbenchView-Gq3mmtsK.js +60 -0
  8. package/apps/web/dist/assets/index-Co1Ssha9.js +2 -0
  9. package/apps/web/dist/index.html +1 -1
  10. package/package.json +21 -14
  11. package/apps/runner/src/engines/claudeCodeRunner.test.js +0 -467
  12. package/apps/runner/src/engines/kimiCodeRunner.test.js +0 -127
  13. package/apps/runner/src/engines/openCodeRunner.test.js +0 -236
  14. package/apps/runner/src/engines/runnerContract.test.js +0 -449
  15. package/apps/runner/src/engines/shellRunner.test.js +0 -46
  16. package/apps/runner/src/runManager.test.js +0 -913
  17. package/apps/runner/src/serverClient.test.js +0 -93
  18. package/apps/server/src/agentSessionDiscovery.test.js +0 -186
  19. package/apps/server/src/appPaths.test.js +0 -52
  20. package/apps/server/src/assetRoutes.test.js +0 -168
  21. package/apps/server/src/codex.test.js +0 -518
  22. package/apps/server/src/codexRoutes.test.js +0 -376
  23. package/apps/server/src/codexRuns.test.js +0 -160
  24. package/apps/server/src/codexSessions.test.js +0 -369
  25. package/apps/server/src/db.test.js +0 -182
  26. package/apps/server/src/gitDiff.test.js +0 -542
  27. package/apps/server/src/gitDiffClient.test.js +0 -140
  28. package/apps/server/src/internalRoutes.test.js +0 -134
  29. package/apps/server/src/maintenance.test.js +0 -154
  30. package/apps/server/src/processControl.test.js +0 -147
  31. package/apps/server/src/relayClient.test.js +0 -478
  32. package/apps/server/src/relayConfig.test.js +0 -73
  33. package/apps/server/src/relayProtocol.test.js +0 -49
  34. package/apps/server/src/relayServer.test.js +0 -798
  35. package/apps/server/src/relayTenants.test.js +0 -137
  36. package/apps/server/src/relayUsageStore.test.js +0 -65
  37. package/apps/server/src/repository.test.js +0 -150
  38. package/apps/server/src/runDispatchService.test.js +0 -563
  39. package/apps/server/src/runEventIngest.test.js +0 -225
  40. package/apps/server/src/runRecovery.test.js +0 -73
  41. package/apps/server/src/runnerClient.test.js +0 -80
  42. package/apps/server/src/runnerDispatch.test.js +0 -136
  43. package/apps/server/src/systemConfig.test.js +0 -112
  44. package/apps/server/src/systemRoutes.test.js +0 -319
  45. package/apps/server/src/taskRoutes.test.js +0 -775
  46. package/apps/server/src/upload.test.js +0 -30
  47. package/apps/server/src/webAppRoutes.test.js +0 -67
  48. package/apps/server/src/workspaceFiles.test.js +0 -279
  49. package/apps/web/dist/assets/WorkbenchView-noayQwj4.js +0 -60
  50. package/apps/web/dist/assets/index-HLkdzIYF.js +0 -2
  51. package/packages/shared/src/dailyLogStream.test.js +0 -29
  52. 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
- })