@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,137 +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
|
-
import {
|
|
8
|
-
addRelayTenant,
|
|
9
|
-
inferBaseDomainFromHost,
|
|
10
|
-
inferRelayTenantDomain,
|
|
11
|
-
listRelayTenants,
|
|
12
|
-
normalizeHost,
|
|
13
|
-
normalizeTenantKey,
|
|
14
|
-
readRelayTenantsFile,
|
|
15
|
-
removeRelayTenant,
|
|
16
|
-
resolveTenantHost,
|
|
17
|
-
} from './relayTenants.js'
|
|
18
|
-
|
|
19
|
-
test('normalizeTenantKey keeps only safe slug characters', () => {
|
|
20
|
-
assert.equal(normalizeTenantKey(' User_One '), 'user-one')
|
|
21
|
-
assert.equal(normalizeTenantKey('a---b'), 'a-b')
|
|
22
|
-
})
|
|
23
|
-
|
|
24
|
-
test('normalizeHost strips protocol and path', () => {
|
|
25
|
-
assert.equal(normalizeHost('https://User1.PromptX.mushayu.com/path?a=1'), 'user1.promptx.mushayu.com')
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
test('resolveTenantHost combines key and domain when host is omitted', () => {
|
|
29
|
-
assert.equal(resolveTenantHost({ key: 'user1', domain: 'promptx.mushayu.com' }), 'user1.promptx.mushayu.com')
|
|
30
|
-
assert.equal(resolveTenantHost({ key: 'user1', host: 'https://custom.promptx.mushayu.com' }), 'custom.promptx.mushayu.com')
|
|
31
|
-
})
|
|
32
|
-
|
|
33
|
-
test('inferBaseDomainFromHost keeps root domain after removing first label', () => {
|
|
34
|
-
assert.equal(inferBaseDomainFromHost('user1.promptx.mushayu.com'), 'promptx.mushayu.com')
|
|
35
|
-
assert.equal(inferBaseDomainFromHost('promptx.mushayu.com'), 'mushayu.com')
|
|
36
|
-
})
|
|
37
|
-
|
|
38
|
-
test('addRelayTenant writes host and generated tokens to file', () => {
|
|
39
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-tenants-'))
|
|
40
|
-
const filePath = path.join(tempDir, 'relay-tenants.json')
|
|
41
|
-
|
|
42
|
-
const result = addRelayTenant({
|
|
43
|
-
filePath,
|
|
44
|
-
key: 'user1',
|
|
45
|
-
domain: 'promptx.mushayu.com',
|
|
46
|
-
})
|
|
47
|
-
|
|
48
|
-
assert.equal(result.tenant.host, 'user1.promptx.mushayu.com')
|
|
49
|
-
assert.equal(result.tenant.deviceId, 'user1-mac')
|
|
50
|
-
assert.match(result.tenant.deviceToken, /^dev_user1_/)
|
|
51
|
-
assert.match(result.tenant.accessToken, /^access_user1_/)
|
|
52
|
-
|
|
53
|
-
const saved = readRelayTenantsFile(filePath)
|
|
54
|
-
assert.equal(saved.tenants.length, 1)
|
|
55
|
-
assert.equal(saved.tenants[0].host, 'user1.promptx.mushayu.com')
|
|
56
|
-
})
|
|
57
|
-
|
|
58
|
-
test('inferRelayTenantDomain falls back to existing tenant host when domain is omitted', () => {
|
|
59
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-tenants-domain-'))
|
|
60
|
-
const filePath = path.join(tempDir, 'relay-tenants.json')
|
|
61
|
-
|
|
62
|
-
addRelayTenant({
|
|
63
|
-
filePath,
|
|
64
|
-
key: 'user1',
|
|
65
|
-
domain: 'promptx.mushayu.com',
|
|
66
|
-
})
|
|
67
|
-
|
|
68
|
-
assert.equal(inferRelayTenantDomain({ filePath }), 'promptx.mushayu.com')
|
|
69
|
-
|
|
70
|
-
const result = addRelayTenant({
|
|
71
|
-
filePath,
|
|
72
|
-
key: 'user2',
|
|
73
|
-
})
|
|
74
|
-
assert.equal(result.tenant.host, 'user2.promptx.mushayu.com')
|
|
75
|
-
})
|
|
76
|
-
|
|
77
|
-
test('inferRelayTenantDomain supports explicit fallback domain from relay public url', () => {
|
|
78
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-tenants-fallback-'))
|
|
79
|
-
const filePath = path.join(tempDir, 'relay-tenants.json')
|
|
80
|
-
|
|
81
|
-
const result = addRelayTenant({
|
|
82
|
-
filePath,
|
|
83
|
-
key: 'dongdong',
|
|
84
|
-
fallbackDomain: 'https://promptx.mushayu.com',
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
assert.equal(result.tenant.host, 'dongdong.promptx.mushayu.com')
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
test('addRelayTenant rejects duplicate tenant key and host', () => {
|
|
91
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-tenants-dup-'))
|
|
92
|
-
const filePath = path.join(tempDir, 'relay-tenants.json')
|
|
93
|
-
|
|
94
|
-
addRelayTenant({
|
|
95
|
-
filePath,
|
|
96
|
-
key: 'user1',
|
|
97
|
-
domain: 'promptx.mushayu.com',
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
assert.throws(() => addRelayTenant({
|
|
101
|
-
filePath,
|
|
102
|
-
key: 'user1',
|
|
103
|
-
domain: 'promptx.mushayu.com',
|
|
104
|
-
}), /租户已存在/)
|
|
105
|
-
|
|
106
|
-
assert.throws(() => addRelayTenant({
|
|
107
|
-
filePath,
|
|
108
|
-
key: 'user2',
|
|
109
|
-
host: 'user1.promptx.mushayu.com',
|
|
110
|
-
}), /域名已存在/)
|
|
111
|
-
})
|
|
112
|
-
|
|
113
|
-
test('listRelayTenants and removeRelayTenant update tenant file', () => {
|
|
114
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-tenants-remove-'))
|
|
115
|
-
const filePath = path.join(tempDir, 'relay-tenants.json')
|
|
116
|
-
|
|
117
|
-
addRelayTenant({
|
|
118
|
-
filePath,
|
|
119
|
-
key: 'user1',
|
|
120
|
-
domain: 'promptx.mushayu.com',
|
|
121
|
-
})
|
|
122
|
-
addRelayTenant({
|
|
123
|
-
filePath,
|
|
124
|
-
key: 'user2',
|
|
125
|
-
domain: 'promptx.mushayu.com',
|
|
126
|
-
})
|
|
127
|
-
|
|
128
|
-
const listed = listRelayTenants(filePath)
|
|
129
|
-
assert.equal(listed.tenants.length, 2)
|
|
130
|
-
|
|
131
|
-
const removed = removeRelayTenant({
|
|
132
|
-
filePath,
|
|
133
|
-
key: 'user1',
|
|
134
|
-
})
|
|
135
|
-
assert.equal(removed.tenants.length, 1)
|
|
136
|
-
assert.equal(removed.tenants[0].key, 'user2')
|
|
137
|
-
})
|
|
@@ -1,65 +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
|
-
import { createRelayUsageStore } from './relayUsageStore.js'
|
|
8
|
-
|
|
9
|
-
test('relay usage store aggregates connects and proxy requests by local day', () => {
|
|
10
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-relay-usage-'))
|
|
11
|
-
const filePath = path.join(tempDir, 'relay-usage.json')
|
|
12
|
-
const store = createRelayUsageStore({ filePath })
|
|
13
|
-
|
|
14
|
-
store.record({
|
|
15
|
-
tenantKey: 'user1',
|
|
16
|
-
type: 'connect',
|
|
17
|
-
host: 'user1.promptx.test',
|
|
18
|
-
deviceId: 'user1-mac',
|
|
19
|
-
at: '2026-03-24T01:00:00+08:00',
|
|
20
|
-
})
|
|
21
|
-
store.record({
|
|
22
|
-
tenantKey: 'user1',
|
|
23
|
-
type: 'proxy_request',
|
|
24
|
-
host: 'user1.promptx.test',
|
|
25
|
-
deviceId: 'user1-mac',
|
|
26
|
-
path: '/api/tasks',
|
|
27
|
-
at: '2026-03-24T01:05:00+08:00',
|
|
28
|
-
})
|
|
29
|
-
store.record({
|
|
30
|
-
tenantKey: 'user1',
|
|
31
|
-
type: 'proxy_request',
|
|
32
|
-
host: 'user1.promptx.test',
|
|
33
|
-
deviceId: 'user1-mac',
|
|
34
|
-
path: '/uploads/a.png',
|
|
35
|
-
at: '2026-03-24T01:06:00+08:00',
|
|
36
|
-
})
|
|
37
|
-
store.record({
|
|
38
|
-
tenantKey: 'user2',
|
|
39
|
-
type: 'connect',
|
|
40
|
-
host: 'user2.promptx.test',
|
|
41
|
-
deviceId: 'user2-win',
|
|
42
|
-
at: '2026-03-24T10:00:00+08:00',
|
|
43
|
-
})
|
|
44
|
-
|
|
45
|
-
store.flush()
|
|
46
|
-
|
|
47
|
-
const report = store.getReport({
|
|
48
|
-
days: 7,
|
|
49
|
-
today: new Date('2026-03-24T12:00:00+08:00'),
|
|
50
|
-
})
|
|
51
|
-
|
|
52
|
-
assert.equal(report.today.date, '2026-03-24')
|
|
53
|
-
assert.equal(report.today.tenantCount, 2)
|
|
54
|
-
assert.equal(report.today.connectCount, 2)
|
|
55
|
-
assert.equal(report.today.proxyRequestCount, 2)
|
|
56
|
-
assert.equal(report.today.apiRequestCount, 1)
|
|
57
|
-
assert.equal(report.today.uploadRequestCount, 1)
|
|
58
|
-
assert.equal(report.today.tenants[0].tenantKey, 'user2')
|
|
59
|
-
assert.equal(report.today.tenants[1].tenantKey, 'user1')
|
|
60
|
-
|
|
61
|
-
const persisted = JSON.parse(fs.readFileSync(filePath, 'utf8'))
|
|
62
|
-
assert.equal(persisted.days['2026-03-24'].user1.proxyRequestCount, 2)
|
|
63
|
-
assert.equal(persisted.days['2026-03-24'].user1.apiRequestCount, 1)
|
|
64
|
-
assert.equal(persisted.days['2026-03-24'].user1.uploadRequestCount, 1)
|
|
65
|
-
})
|
|
@@ -1,150 +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('listTasks uses stable sort order instead of updated-at order', async () => {
|
|
8
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-repository-'))
|
|
9
|
-
const originalCwd = process.cwd()
|
|
10
|
-
const originalDataDir = process.env.PROMPTX_DATA_DIR
|
|
11
|
-
const dataDir = path.join(tempDir, 'data')
|
|
12
|
-
|
|
13
|
-
fs.mkdirSync(dataDir, { recursive: true })
|
|
14
|
-
process.chdir(tempDir)
|
|
15
|
-
process.env.PROMPTX_DATA_DIR = dataDir
|
|
16
|
-
|
|
17
|
-
try {
|
|
18
|
-
const repository = await import(`./repository.js?test=${Date.now()}`)
|
|
19
|
-
const { createTask, listTasks, updateTask } = repository
|
|
20
|
-
|
|
21
|
-
const olderTask = createTask({
|
|
22
|
-
title: 'older',
|
|
23
|
-
visibility: 'private',
|
|
24
|
-
expiry: 'none',
|
|
25
|
-
})
|
|
26
|
-
|
|
27
|
-
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
28
|
-
|
|
29
|
-
const newerTask = createTask({
|
|
30
|
-
title: 'newer',
|
|
31
|
-
visibility: 'private',
|
|
32
|
-
expiry: 'none',
|
|
33
|
-
})
|
|
34
|
-
|
|
35
|
-
updateTask(olderTask.slug, {
|
|
36
|
-
title: 'older updated',
|
|
37
|
-
visibility: 'private',
|
|
38
|
-
expiry: 'none',
|
|
39
|
-
blocks: [{ type: 'text', content: 'changed' }],
|
|
40
|
-
})
|
|
41
|
-
|
|
42
|
-
const items = listTasks()
|
|
43
|
-
assert.deepEqual(
|
|
44
|
-
items.map((item) => item.slug),
|
|
45
|
-
[newerTask.slug, olderTask.slug]
|
|
46
|
-
)
|
|
47
|
-
} finally {
|
|
48
|
-
process.chdir(originalCwd)
|
|
49
|
-
if (typeof originalDataDir === 'string') {
|
|
50
|
-
process.env.PROMPTX_DATA_DIR = originalDataDir
|
|
51
|
-
} else {
|
|
52
|
-
delete process.env.PROMPTX_DATA_DIR
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
test('reorderTasks persists manual task ordering', async () => {
|
|
58
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-repository-'))
|
|
59
|
-
const originalCwd = process.cwd()
|
|
60
|
-
const originalDataDir = process.env.PROMPTX_DATA_DIR
|
|
61
|
-
const dataDir = path.join(tempDir, 'data')
|
|
62
|
-
|
|
63
|
-
fs.mkdirSync(dataDir, { recursive: true })
|
|
64
|
-
process.chdir(tempDir)
|
|
65
|
-
process.env.PROMPTX_DATA_DIR = dataDir
|
|
66
|
-
|
|
67
|
-
try {
|
|
68
|
-
const repository = await import(`./repository.js?test=${Date.now()}`)
|
|
69
|
-
const { createTask, listTasks, reorderTasks } = repository
|
|
70
|
-
|
|
71
|
-
const first = createTask({ title: 'first', visibility: 'private', expiry: 'none' })
|
|
72
|
-
const second = createTask({ title: 'second', visibility: 'private', expiry: 'none' })
|
|
73
|
-
const third = createTask({ title: 'third', visibility: 'private', expiry: 'none' })
|
|
74
|
-
|
|
75
|
-
const initialItems = listTasks()
|
|
76
|
-
assert.deepEqual(initialItems.slice(0, 3).map((item) => item.slug), [third.slug, second.slug, first.slug])
|
|
77
|
-
|
|
78
|
-
const result = reorderTasks([second.slug, third.slug, first.slug])
|
|
79
|
-
assert.equal(result.changed, true)
|
|
80
|
-
assert.deepEqual(result.items.slice(0, 3).map((item) => item.slug), [second.slug, third.slug, first.slug])
|
|
81
|
-
assert.deepEqual(listTasks().slice(0, 3).map((item) => item.slug), [second.slug, third.slug, first.slug])
|
|
82
|
-
} finally {
|
|
83
|
-
process.chdir(originalCwd)
|
|
84
|
-
if (typeof originalDataDir === 'string') {
|
|
85
|
-
process.env.PROMPTX_DATA_DIR = originalDataDir
|
|
86
|
-
} else {
|
|
87
|
-
delete process.env.PROMPTX_DATA_DIR
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
test('updateTask skips touching updatedAt when payload is unchanged', async () => {
|
|
93
|
-
const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'promptx-repository-'))
|
|
94
|
-
const originalCwd = process.cwd()
|
|
95
|
-
const originalDataDir = process.env.PROMPTX_DATA_DIR
|
|
96
|
-
const dataDir = path.join(tempDir, 'data')
|
|
97
|
-
|
|
98
|
-
fs.mkdirSync(dataDir, { recursive: true })
|
|
99
|
-
process.chdir(tempDir)
|
|
100
|
-
process.env.PROMPTX_DATA_DIR = dataDir
|
|
101
|
-
|
|
102
|
-
try {
|
|
103
|
-
const repository = await import(`./repository.js?test=${Date.now()}`)
|
|
104
|
-
const { createTask, getTaskBySlug, updateTask } = repository
|
|
105
|
-
|
|
106
|
-
const task = createTask({
|
|
107
|
-
title: 'same task',
|
|
108
|
-
autoTitle: 'same auto',
|
|
109
|
-
lastPromptPreview: 'same preview',
|
|
110
|
-
visibility: 'private',
|
|
111
|
-
expiry: 'none',
|
|
112
|
-
codexSessionId: 'session-a',
|
|
113
|
-
todoItems: [
|
|
114
|
-
{
|
|
115
|
-
id: 'todo-1',
|
|
116
|
-
createdAt: '2026-03-26T00:00:00.000Z',
|
|
117
|
-
blocks: [{ type: 'text', content: 'todo text' }],
|
|
118
|
-
},
|
|
119
|
-
],
|
|
120
|
-
blocks: [
|
|
121
|
-
{ type: 'text', content: 'hello' },
|
|
122
|
-
],
|
|
123
|
-
})
|
|
124
|
-
|
|
125
|
-
const before = getTaskBySlug(task.slug)
|
|
126
|
-
await new Promise((resolve) => setTimeout(resolve, 10))
|
|
127
|
-
|
|
128
|
-
const result = updateTask(task.slug, {
|
|
129
|
-
title: before.title,
|
|
130
|
-
autoTitle: before.autoTitle,
|
|
131
|
-
lastPromptPreview: before.lastPromptPreview,
|
|
132
|
-
visibility: before.visibility,
|
|
133
|
-
expiry: before.expiry,
|
|
134
|
-
codexSessionId: before.codexSessionId,
|
|
135
|
-
todoItems: before.todoItems,
|
|
136
|
-
blocks: before.blocks,
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
const after = getTaskBySlug(task.slug)
|
|
140
|
-
assert.equal(result.changed, false)
|
|
141
|
-
assert.equal(after.updatedAt, before.updatedAt)
|
|
142
|
-
} finally {
|
|
143
|
-
process.chdir(originalCwd)
|
|
144
|
-
if (typeof originalDataDir === 'string') {
|
|
145
|
-
process.env.PROMPTX_DATA_DIR = originalDataDir
|
|
146
|
-
} else {
|
|
147
|
-
delete process.env.PROMPTX_DATA_DIR
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
})
|