@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,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
- })