@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,376 +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 Fastify from 'fastify'
6
- import test from 'node:test'
7
-
8
- import {
9
- createWorkspaceSuggestionService,
10
- registerCodexRoutes,
11
- } from './codexRoutes.js'
12
-
13
- test('workspace suggestion service merges and deduplicates sources', () => {
14
- const tempRoot = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-workspaces-'))
15
- const workspaceRootDir = path.join(tempRoot, 'promptx')
16
- const siblingA = path.join(tempRoot, 'repo-a')
17
- const siblingB = path.join(tempRoot, 'repo-b')
18
- const knownOnly = path.join(tempRoot, 'known-only')
19
-
20
- fs.mkdirSync(workspaceRootDir, { recursive: true })
21
- fs.mkdirSync(siblingA, { recursive: true })
22
- fs.mkdirSync(siblingB, { recursive: true })
23
- fs.mkdirSync(knownOnly, { recursive: true })
24
-
25
- try {
26
- const service = createWorkspaceSuggestionService({
27
- listKnownWorkspacesByEngine: () => [siblingA, knownOnly],
28
- listPromptxCodexSessions: () => [
29
- { cwd: siblingB },
30
- { cwd: workspaceRootDir },
31
- ],
32
- workspaceParentDir: tempRoot,
33
- workspaceRootDir,
34
- })
35
-
36
- const items = service.listWorkspaceSuggestions(10, 'codex')
37
- assert.deepEqual(items, [
38
- workspaceRootDir,
39
- knownOnly,
40
- siblingA,
41
- siblingB,
42
- ])
43
- } finally {
44
- fs.rmSync(tempRoot, { recursive: true, force: true })
45
- }
46
- })
47
-
48
- test('codex routes return stop acceptance and event history', async () => {
49
- const app = Fastify()
50
- registerCodexRoutes(app, {
51
- broadcastServerEvent: () => {},
52
- clearTaskCodexSessionReferences: () => [],
53
- createPromptxCodexSession: () => ({ id: 'session-1' }),
54
- decorateCodexSession: (session) => session,
55
- decorateCodexSessionList: (items) => items,
56
- deletePromptxCodexSession: () => null,
57
- getCodexRunById(runId) {
58
- if (runId !== 'run-1') {
59
- return null
60
- }
61
- return {
62
- id: 'run-1',
63
- status: 'running',
64
- }
65
- },
66
- getPromptxCodexSessionById: () => null,
67
- getRunningCodexRunBySessionId: () => null,
68
- isActiveRunStatus: (status) => ['queued', 'starting', 'running', 'stopping'].includes(status),
69
- listCodexRunEvents: () => [{ seq: 1, type: 'stdout', text: 'hello' }],
70
- listDirectoryPickerTree: () => ({}),
71
- listPromptxCodexSessions: () => [],
72
- listWorkspaceSuggestions: () => [],
73
- listWorkspaceTree: () => ({}),
74
- runDispatchService: {
75
- async requestRunStop() {
76
- return {
77
- accepted: true,
78
- run: {
79
- id: 'run-1',
80
- status: 'stopping',
81
- },
82
- }
83
- },
84
- },
85
- searchDirectoryPickerEntries: () => ({}),
86
- searchWorkspaceFileContent: () => ({}),
87
- searchWorkspaceEntries: () => ({}),
88
- updatePromptxCodexSession: () => null,
89
- })
90
- await app.ready()
91
-
92
- try {
93
- const stopResponse = await app.inject({
94
- method: 'POST',
95
- url: '/api/codex/runs/run-1/stop',
96
- payload: {
97
- reason: 'user_requested',
98
- },
99
- })
100
- assert.equal(stopResponse.statusCode, 202)
101
- assert.equal(stopResponse.json().run.status, 'stopping')
102
-
103
- const eventsResponse = await app.inject({
104
- method: 'GET',
105
- url: '/api/codex/runs/run-1/events',
106
- })
107
- assert.equal(eventsResponse.statusCode, 200)
108
- assert.deepEqual(eventsResponse.json(), {
109
- items: [{ seq: 1, type: 'stdout', text: 'hello' }],
110
- })
111
- } finally {
112
- await app.close()
113
- }
114
- })
115
-
116
- test('codex routes expose local session candidates by engine', async () => {
117
- const app = Fastify()
118
- registerCodexRoutes(app, {
119
- broadcastServerEvent: () => {},
120
- clearTaskCodexSessionReferences: () => [],
121
- createPromptxCodexSession: () => ({ id: 'session-1' }),
122
- decorateCodexSession: (session) => session,
123
- decorateCodexSessionList: (items) => items,
124
- deletePromptxCodexSession: () => null,
125
- getCodexRunById: () => null,
126
- getPromptxCodexSessionById: () => null,
127
- getRunningCodexRunBySessionId: () => null,
128
- isActiveRunStatus: () => false,
129
- listCodexRunEvents: () => [],
130
- listDirectoryPickerTree: () => ({}),
131
- listKnownSessionsByEngine(engine, options) {
132
- return [{
133
- id: `${engine}-session-1`,
134
- engine,
135
- cwd: options.cwd,
136
- updatedAt: '2026-04-13T08:00:00.000Z',
137
- }]
138
- },
139
- listPromptxCodexSessions: () => [],
140
- listWorkspaceSuggestions: () => [],
141
- listWorkspaceTree: () => ({}),
142
- runDispatchService: {
143
- async requestRunStop() {
144
- return null
145
- },
146
- },
147
- searchDirectoryPickerEntries: () => ({}),
148
- searchWorkspaceFileContent: () => ({}),
149
- searchWorkspaceEntries: () => ({}),
150
- updatePromptxCodexSession: () => null,
151
- })
152
- await app.ready()
153
-
154
- try {
155
- const response = await app.inject({
156
- method: 'GET',
157
- url: '/api/codex/session-candidates?engine=claude-code&cwd=%2Ftmp%2Fproject&limit=20',
158
- })
159
-
160
- assert.equal(response.statusCode, 200)
161
- assert.deepEqual(response.json(), {
162
- items: [{
163
- id: 'claude-code-session-1',
164
- engine: 'claude-code',
165
- cwd: '/tmp/project',
166
- updatedAt: '2026-04-13T08:00:00.000Z',
167
- }],
168
- })
169
- } finally {
170
- await app.close()
171
- }
172
- })
173
-
174
- test('codex routes broadcast task updates when deleting a session with references', async () => {
175
- const broadcasts = []
176
- const app = Fastify()
177
- registerCodexRoutes(app, {
178
- broadcastServerEvent(type, payload) {
179
- broadcasts.push({ type, payload })
180
- },
181
- clearTaskCodexSessionReferences: () => ['task-a', 'task-b'],
182
- createPromptxCodexSession: () => ({ id: 'session-1' }),
183
- decorateCodexSession: (session) => session,
184
- decorateCodexSessionList: (items) => items,
185
- deletePromptxCodexSession: () => ({ id: 'session-1' }),
186
- getCodexRunById: () => null,
187
- getPromptxCodexSessionById: () => ({ id: 'session-1', agentBindings: [] }),
188
- getRunningCodexRunBySessionId: () => null,
189
- isActiveRunStatus: () => false,
190
- listCodexRunEvents: () => [],
191
- listDirectoryPickerTree: () => ({}),
192
- listPromptxCodexSessions: () => [],
193
- listWorkspaceSuggestions: () => [],
194
- listWorkspaceTree: () => ({}),
195
- runDispatchService: {
196
- async requestRunStop() {
197
- return null
198
- },
199
- },
200
- searchDirectoryPickerEntries: () => ({}),
201
- searchWorkspaceFileContent: () => ({}),
202
- searchWorkspaceEntries: () => ({}),
203
- updatePromptxCodexSession: () => null,
204
- })
205
- await app.ready()
206
-
207
- try {
208
- const response = await app.inject({
209
- method: 'DELETE',
210
- url: '/api/codex/sessions/session-1',
211
- })
212
-
213
- assert.equal(response.statusCode, 204)
214
- assert.deepEqual(broadcasts, [
215
- {
216
- type: 'sessions.changed',
217
- payload: { sessionId: 'session-1' },
218
- },
219
- {
220
- type: 'tasks.changed',
221
- payload: { taskSlug: 'task-a', reason: 'session-cleared' },
222
- },
223
- {
224
- type: 'tasks.changed',
225
- payload: { taskSlug: 'task-b', reason: 'session-cleared' },
226
- },
227
- ])
228
- } finally {
229
- await app.close()
230
- }
231
- })
232
-
233
- test('codex routes reset session and clear related run history', async () => {
234
- const broadcasts = []
235
- const deletedTaskRuns = []
236
- const app = Fastify()
237
- registerCodexRoutes(app, {
238
- broadcastServerEvent(type, payload) {
239
- broadcasts.push({ type, payload })
240
- },
241
- clearTaskCodexSessionReferences: () => [],
242
- createPromptxCodexSession: () => ({ id: 'session-1' }),
243
- decorateCodexSession: (session) => ({ ...session, decorated: true }),
244
- decorateCodexSessionList: (items) => items,
245
- deletePromptxCodexSession: () => null,
246
- deleteTaskCodexRuns(taskSlug) {
247
- deletedTaskRuns.push(taskSlug)
248
- },
249
- getCodexRunById: () => null,
250
- getPromptxCodexSessionById: () => ({ id: 'session-1' }),
251
- getRunningCodexRunBySessionId: () => null,
252
- getRunningCodexRunByTaskSlug: () => null,
253
- isActiveRunStatus: () => false,
254
- listCodexRunEvents: () => [],
255
- listDirectoryPickerTree: () => ({}),
256
- listPromptxCodexSessions: () => [],
257
- listTaskSlugsByCodexSessionId: () => ['task-a', 'task-b'],
258
- listWorkspaceSuggestions: () => [],
259
- listWorkspaceTree: () => ({}),
260
- resetPromptxCodexSession: () => ({ id: 'session-1', title: '项目 A' }),
261
- runDispatchService: {
262
- async requestRunStop() {
263
- return null
264
- },
265
- },
266
- searchDirectoryPickerEntries: () => ({}),
267
- searchWorkspaceFileContent: () => ({}),
268
- searchWorkspaceEntries: () => ({}),
269
- updatePromptxCodexSession: () => null,
270
- })
271
- await app.ready()
272
-
273
- try {
274
- const response = await app.inject({
275
- method: 'POST',
276
- url: '/api/codex/sessions/session-1/reset',
277
- })
278
-
279
- assert.equal(response.statusCode, 200)
280
- assert.deepEqual(response.json(), {
281
- session: {
282
- id: 'session-1',
283
- title: '项目 A',
284
- decorated: true,
285
- },
286
- affectedTaskSlugs: ['task-a', 'task-b'],
287
- })
288
- assert.deepEqual(deletedTaskRuns, ['task-a', 'task-b'])
289
- assert.deepEqual(broadcasts, [
290
- {
291
- type: 'sessions.changed',
292
- payload: { sessionId: 'session-1' },
293
- },
294
- {
295
- type: 'runs.changed',
296
- payload: { taskSlug: 'task-a' },
297
- },
298
- {
299
- type: 'runs.changed',
300
- payload: { taskSlug: 'task-b' },
301
- },
302
- ])
303
- } finally {
304
- await app.close()
305
- }
306
- })
307
-
308
- test('codex routes expose workspace content search for source browser', async () => {
309
- const app = Fastify()
310
- registerCodexRoutes(app, {
311
- broadcastServerEvent: () => {},
312
- clearTaskCodexSessionReferences: () => [],
313
- createPromptxCodexSession: () => ({ id: 'session-1' }),
314
- decorateCodexSession: (session) => session,
315
- decorateCodexSessionList: (items) => items,
316
- deletePromptxCodexSession: () => null,
317
- getCodexRunById: () => null,
318
- getPromptxCodexSessionById: (sessionId) => (sessionId === 'session-1' ? { id: 'session-1', cwd: '/tmp/project' } : null),
319
- getRunningCodexRunBySessionId: () => null,
320
- isActiveRunStatus: () => false,
321
- listCodexRunEvents: () => [],
322
- listDirectoryPickerTree: () => ({}),
323
- listPromptxCodexSessions: () => [],
324
- listWorkspaceSuggestions: () => [],
325
- listWorkspaceTree: () => ({}),
326
- readWorkspaceFileContent: () => ({}),
327
- runDispatchService: {
328
- async requestRunStop() {
329
- return null
330
- },
331
- },
332
- searchDirectoryPickerEntries: () => ({}),
333
- searchWorkspaceEntries: () => ({}),
334
- searchWorkspaceFileContent(cwd, options) {
335
- return {
336
- cwd,
337
- query: options.query,
338
- items: [
339
- {
340
- path: 'src/main.ts',
341
- line: 3,
342
- column: 5,
343
- preview: 'const needle = true',
344
- },
345
- ],
346
- truncated: false,
347
- }
348
- },
349
- updatePromptxCodexSession: () => null,
350
- })
351
- await app.ready()
352
-
353
- try {
354
- const response = await app.inject({
355
- method: 'GET',
356
- url: '/api/codex/sessions/session-1/files/content-search?q=needle',
357
- })
358
-
359
- assert.equal(response.statusCode, 200)
360
- assert.deepEqual(response.json(), {
361
- cwd: '/tmp/project',
362
- query: 'needle',
363
- items: [
364
- {
365
- path: 'src/main.ts',
366
- line: 3,
367
- column: 5,
368
- preview: 'const needle = true',
369
- },
370
- ],
371
- truncated: false,
372
- })
373
- } finally {
374
- await app.close()
375
- }
376
- })
@@ -1,160 +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
-
7
- test('listTaskCodexRunsWithOptions 支持 events=none|latest|all,并兼容旧参数', async () => {
8
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-codex-runs-'))
9
- const originalCwd = process.cwd()
10
- const originalDataDir = process.env.PROMPTX_DATA_DIR
11
- const dataDir = path.join(tempDir, 'data')
12
- fs.mkdirSync(dataDir, { recursive: true })
13
- process.chdir(tempDir)
14
- process.env.PROMPTX_DATA_DIR = dataDir
15
-
16
- try {
17
- const { run } = await import('./db.js')
18
- const {
19
- appendCodexRunEvent,
20
- listTaskCodexRunsWithOptions,
21
- } = await import(`./codexRuns.js?test=${Date.now()}`)
22
-
23
- const now = new Date().toISOString()
24
- const earlier = new Date(Date.now() - 60_000).toISOString()
25
-
26
- run(
27
- `INSERT INTO tasks (slug, edit_token, title, auto_title, last_prompt_preview, codex_session_id, visibility, expires_at, created_at, updated_at)
28
- VALUES (?, ?, '', '', '', ?, 'private', NULL, ?, ?)`,
29
- ['task-1', 'token-1', 'session-1', now, now]
30
- )
31
- run(
32
- `INSERT INTO codex_sessions (id, title, cwd, codex_thread_id, created_at, updated_at)
33
- VALUES (?, ?, ?, '', ?, ?)`,
34
- ['session-1', 'Repo Session', tempDir, now, now]
35
- )
36
- run(
37
- `INSERT INTO codex_runs (id, task_slug, session_id, prompt, prompt_blocks_json, status, response_message, error_message, created_at, updated_at, started_at, finished_at)
38
- VALUES (?, ?, ?, ?, ?, 'completed', '', '', ?, ?, ?, ?)`,
39
- ['run-1', 'task-1', 'session-1', 'hello', JSON.stringify([
40
- { type: 'text', content: '请看这张图', meta: {} },
41
- { type: 'image', content: '/uploads/demo.png', meta: {} },
42
- ]), now, now, now, now]
43
- )
44
- run(
45
- `INSERT INTO codex_runs (id, task_slug, session_id, prompt, prompt_blocks_json, status, response_message, error_message, created_at, updated_at, started_at, finished_at)
46
- VALUES (?, ?, ?, ?, ?, 'completed', '', '', ?, ?, ?, ?)`,
47
- ['run-2', 'task-1', 'session-1', 'older', '[]', earlier, earlier, earlier, earlier]
48
- )
49
-
50
- appendCodexRunEvent('run-1', 1, { type: 'turn.started' })
51
- appendCodexRunEvent('run-1', 2, { type: 'turn.completed' })
52
- appendCodexRunEvent('run-2', 1, { type: 'thread.started', thread_id: 'thread-older' })
53
-
54
- const summaryRuns = listTaskCodexRunsWithOptions('task-1', { limit: 20, events: 'none' })
55
- assert.equal(summaryRuns?.length, 2)
56
- assert.equal(summaryRuns[0].id, 'run-1')
57
- assert.equal(summaryRuns[0].eventCount, 2)
58
- assert.equal(summaryRuns[0].lastEventSeq, 2)
59
- assert.equal(summaryRuns[0].eventsIncluded, false)
60
- assert.deepEqual(summaryRuns[0].events, [])
61
- assert.deepEqual(summaryRuns[0].promptBlocks, [
62
- { type: 'text', content: '请看这张图', meta: {} },
63
- { type: 'image', content: '/uploads/demo.png', meta: {} },
64
- ])
65
- assert.equal(summaryRuns[1].id, 'run-2')
66
- assert.equal(summaryRuns[1].eventsIncluded, false)
67
- assert.deepEqual(summaryRuns[1].events, [])
68
-
69
- const latestRuns = listTaskCodexRunsWithOptions('task-1', { limit: 20, events: 'latest' })
70
- assert.equal(latestRuns?.length, 2)
71
- assert.equal(latestRuns[0].eventsIncluded, true)
72
- assert.deepEqual(latestRuns[0].events.map((item) => item.seq), [1, 2])
73
- assert.equal(latestRuns[1].eventsIncluded, false)
74
- assert.deepEqual(latestRuns[1].events, [])
75
-
76
- const detailedRuns = listTaskCodexRunsWithOptions('task-1', { limit: 20, events: 'all' })
77
- assert.equal(detailedRuns?.length, 2)
78
- assert.equal(detailedRuns[0].eventsIncluded, true)
79
- assert.deepEqual(detailedRuns[0].events.map((item) => item.seq), [1, 2])
80
- assert.equal(detailedRuns[1].eventsIncluded, true)
81
- assert.deepEqual(detailedRuns[1].events.map((item) => item.seq), [1])
82
-
83
- const legacyAllRuns = listTaskCodexRunsWithOptions('task-1', { limit: 20, includeEvents: true })
84
- assert.equal(legacyAllRuns?.[0]?.eventsIncluded, true)
85
- assert.equal(legacyAllRuns?.[1]?.eventsIncluded, true)
86
-
87
- const legacyLatestRuns = listTaskCodexRunsWithOptions('task-1', { limit: 20, includeLatestEvents: true })
88
- assert.equal(legacyLatestRuns?.[0]?.eventsIncluded, true)
89
- assert.equal(legacyLatestRuns?.[1]?.eventsIncluded, false)
90
- } finally {
91
- process.chdir(originalCwd)
92
- if (typeof originalDataDir === 'string') {
93
- process.env.PROMPTX_DATA_DIR = originalDataDir
94
- } else {
95
- delete process.env.PROMPTX_DATA_DIR
96
- }
97
- }
98
- })
99
-
100
- test('listStaleActiveCodexRuns 会把最近事件视为运行活跃信号', async () => {
101
- const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-codex-stale-'))
102
- const originalCwd = process.cwd()
103
- const originalDataDir = process.env.PROMPTX_DATA_DIR
104
- const dataDir = path.join(tempDir, 'data')
105
- fs.mkdirSync(dataDir, { recursive: true })
106
- process.chdir(tempDir)
107
- process.env.PROMPTX_DATA_DIR = dataDir
108
-
109
- try {
110
- const { run } = await import('./db.js')
111
- const {
112
- appendCodexRunEvent,
113
- listStaleActiveCodexRuns,
114
- } = await import(`./codexRuns.js?test=${Date.now() + 1}`)
115
-
116
- const suffix = Date.now().toString(36)
117
- const staleAt = new Date(Date.now() - 60_000).toISOString()
118
- const now = new Date().toISOString()
119
- const taskSlug = `task-${suffix}`
120
- const sessionId = `session-${suffix}`
121
- const activeRunId = `run-active-${suffix}`
122
- const staleRunId = `run-stale-${suffix}`
123
-
124
- run(
125
- `INSERT INTO tasks (slug, edit_token, title, auto_title, last_prompt_preview, codex_session_id, visibility, expires_at, created_at, updated_at)
126
- VALUES (?, ?, '', '', '', ?, 'private', NULL, ?, ?)`,
127
- [taskSlug, `token-${suffix}`, sessionId, now, now]
128
- )
129
- run(
130
- `INSERT INTO codex_sessions (id, title, cwd, codex_thread_id, created_at, updated_at)
131
- VALUES (?, ?, ?, '', ?, ?)`,
132
- [sessionId, 'Session 1', tempDir, now, now]
133
- )
134
- run(
135
- `INSERT INTO codex_runs (id, task_slug, session_id, prompt, prompt_blocks_json, status, response_message, error_message, created_at, updated_at, started_at, finished_at)
136
- VALUES (?, ?, ?, ?, '[]', 'running', '', '', ?, ?, ?, NULL)`,
137
- [activeRunId, taskSlug, sessionId, 'hello', staleAt, staleAt, staleAt]
138
- )
139
- run(
140
- `INSERT INTO codex_runs (id, task_slug, session_id, prompt, prompt_blocks_json, status, response_message, error_message, created_at, updated_at, started_at, finished_at)
141
- VALUES (?, ?, ?, ?, '[]', 'running', '', '', ?, ?, ?, NULL)`,
142
- [staleRunId, taskSlug, sessionId, 'hello again', staleAt, staleAt, staleAt]
143
- )
144
-
145
- appendCodexRunEvent(activeRunId, {
146
- type: 'stdout',
147
- text: 'heartbeat',
148
- }, 1)
149
-
150
- const staleRuns = listStaleActiveCodexRuns(1000)
151
- assert.deepEqual(staleRuns.map((item) => item.id), [staleRunId])
152
- } finally {
153
- process.chdir(originalCwd)
154
- if (typeof originalDataDir === 'string') {
155
- process.env.PROMPTX_DATA_DIR = originalDataDir
156
- } else {
157
- delete process.env.PROMPTX_DATA_DIR
158
- }
159
- }
160
- })