@walkhi/code-relax 0.1.0-beta.68 → 0.1.0-beta.69

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 (120) hide show
  1. package/dist/bin/manage-relay-admin.mjs +20 -20
  2. package/dist/bin/migrate-relay-db.mjs +109 -109
  3. package/dist/bin/publish-harmony-release.mjs +46 -46
  4. package/dist/bin/self-relay-admin.mjs +8 -8
  5. package/dist/bin/self-relay-demo.mjs +33 -33
  6. package/dist/bin/self-relay-server.mjs +66 -66
  7. package/dist/bin/set-relay-admin-password.mjs +11 -11
  8. package/dist/build-platform.json +1 -1
  9. package/dist/get-lan-networks.ps1 +40 -40
  10. package/dist/shared/app-server-events.cjs +511 -511
  11. package/dist/shared/p2p-data-channel.cjs +72 -72
  12. package/dist/shared/p2p-diagnostics.cjs +28 -28
  13. package/dist/shared/p2p-ice-policy.cjs +22 -22
  14. package/dist/shared/plan-pricing.cjs +32 -32
  15. package/dist/shared/question-attention.cjs +69 -69
  16. package/dist/shared/release-version.cjs +31 -31
  17. package/dist/src/archived-threads.mjs +22 -22
  18. package/dist/src/background-process.mjs +18 -18
  19. package/dist/src/code-browser.mjs +100 -100
  20. package/dist/src/desktop-launcher.mjs +62 -62
  21. package/dist/src/dots-task-files.mjs +52 -52
  22. package/dist/src/execution-health.mjs +26 -26
  23. package/dist/src/lan-socket-server.mjs +1 -1
  24. package/dist/src/message-images.mjs +9 -9
  25. package/dist/src/plan-pricing.mjs +47 -47
  26. package/dist/src/platform/codex-runtime.mjs +3 -3
  27. package/dist/src/platform/credential-store.mjs +19 -19
  28. package/dist/src/platform/desktop-host.mjs +3 -3
  29. package/dist/src/platform/desktop-permission-mode.mjs +17 -17
  30. package/dist/src/platform/desktop-project-registration.mjs +3 -3
  31. package/dist/src/platform/file-opener.mjs +9 -9
  32. package/dist/src/platform/linux/README.md +3 -3
  33. package/dist/src/platform/linux/codex-runtime.mjs +56 -56
  34. package/dist/src/platform/linux/desktop-installation.mjs +36 -36
  35. package/dist/src/platform/linux/desktop-project-registration.mjs +11 -11
  36. package/dist/src/platform/linux/network-info.mjs +11 -11
  37. package/dist/src/platform/linux/project-locations.mjs +17 -17
  38. package/dist/src/platform/linux/resident-startup.mjs +52 -52
  39. package/dist/src/platform/linux/retained-runtime.mjs +76 -76
  40. package/dist/src/platform/linux/service-host.mjs +18 -18
  41. package/dist/src/platform/macos/README.md +3 -3
  42. package/dist/src/platform/macos/desktop-project-registration.mjs +11 -11
  43. package/dist/src/platform/macos/network-info.mjs +8 -8
  44. package/dist/src/platform/macos/project-locations.mjs +8 -8
  45. package/dist/src/platform/macos/resident-startup.mjs +84 -84
  46. package/dist/src/platform/macos/retained-runtime.mjs +127 -127
  47. package/dist/src/platform/macos/service-host.mjs +18 -18
  48. package/dist/src/platform/macos/system.mjs +29 -29
  49. package/dist/src/platform/network-info.mjs +3 -3
  50. package/dist/src/platform/path-identity.mjs +5 -5
  51. package/dist/src/platform/posix/network-candidates.mjs +23 -23
  52. package/dist/src/platform/posix/runtime-paths.mjs +25 -25
  53. package/dist/src/platform/power-inhibitor.mjs +22 -22
  54. package/dist/src/platform/project-locations.mjs +3 -3
  55. package/dist/src/platform/runtime-paths.mjs +8 -8
  56. package/dist/src/platform/select.mjs +5 -5
  57. package/dist/src/platform/service-host.mjs +3 -3
  58. package/dist/src/platform/user-environment.mjs +3 -3
  59. package/dist/src/platform/windows/IsolatedProcess.cs +79 -79
  60. package/dist/src/platform/windows/background-process.mjs +30 -30
  61. package/dist/src/platform/windows/desktop-helper.mjs +179 -179
  62. package/dist/src/platform/windows/desktop-runtime.ps1 +10 -10
  63. package/dist/src/platform/windows/desktop-shortcuts.ps1 +7 -7
  64. package/dist/src/platform/windows/keep-awake.ps1 +20 -20
  65. package/dist/src/platform/windows/network-info.mjs +34 -34
  66. package/dist/src/platform/windows/resident-start.js +20 -20
  67. package/dist/src/platform/windows/resident-start.ps1 +7 -7
  68. package/dist/src/platform/windows/resident-startup.ps1 +83 -83
  69. package/dist/src/platform/windows/resolve-state-root.ps1 +14 -14
  70. package/dist/src/platform/windows/runtime-paths.mjs +20 -20
  71. package/dist/src/platform/windows/rustdesk-video-probe.mjs +167 -167
  72. package/dist/src/platform/windows/start-hidden-console.ps1 +58 -58
  73. package/dist/src/platform/windows/stop-desktop.ps1 +22 -22
  74. package/dist/src/platform/windows/user-environment.ps1 +41 -41
  75. package/dist/src/project-create.mjs +121 -121
  76. package/dist/src/project-management.mjs +1 -1
  77. package/dist/src/project-remove.mjs +55 -55
  78. package/dist/src/project-update.mjs +59 -59
  79. package/dist/src/relay-config-import.mjs +45 -45
  80. package/dist/src/self-relay/account-connections.mjs +52 -52
  81. package/dist/src/self-relay/admin-auth.mjs +59 -59
  82. package/dist/src/self-relay/admin-cloud.mjs +101 -101
  83. package/dist/src/self-relay/admin-login-page.mjs +7 -7
  84. package/dist/src/self-relay/admin-server.mjs +105 -105
  85. package/dist/src/self-relay/admin-state.mjs +127 -127
  86. package/dist/src/self-relay/admin-workstations-page.mjs +95 -95
  87. package/dist/src/self-relay/admin-workstations.mjs +143 -143
  88. package/dist/src/self-relay/android-releases.mjs +61 -61
  89. package/dist/src/self-relay/client.mjs +61 -61
  90. package/dist/src/self-relay/connection-reporting.mjs +38 -38
  91. package/dist/src/self-relay/connector.mjs +13 -2
  92. package/dist/src/self-relay/debug-allowlist.mjs +33 -33
  93. package/dist/src/self-relay/demo.mjs +6 -6
  94. package/dist/src/self-relay/device-info.mjs +27 -27
  95. package/dist/src/self-relay/device-store.mjs +92 -92
  96. package/dist/src/self-relay/lan-authorizations.mjs +71 -71
  97. package/dist/src/self-relay/lifecycle.mjs +278 -278
  98. package/dist/src/self-relay/long-pairing.mjs +40 -40
  99. package/dist/src/self-relay/mysql-state.mjs +118 -118
  100. package/dist/src/self-relay/phone-connections.mjs +55 -55
  101. package/dist/src/self-relay/server.mjs +14 -3
  102. package/dist/src/self-relay/usage-daily.mjs +55 -55
  103. package/dist/src/self-relay/windows-route-helper.mjs +75 -75
  104. package/dist/src/self-relay/wire.mjs +36 -36
  105. package/dist/src/server.mjs +40 -18
  106. package/dist/src/service-control.mjs +82 -82
  107. package/dist/src/service-health.mjs +33 -33
  108. package/dist/src/service-power.mjs +58 -58
  109. package/dist/src/service-restart.mjs +81 -81
  110. package/dist/src/service-update-worker.mjs +42 -42
  111. package/dist/src/service-update.mjs +80 -80
  112. package/dist/src/shared-recovery.mjs +152 -152
  113. package/dist/src/skill-install.mjs +51 -51
  114. package/dist/src/thread-title-generation.mjs +150 -150
  115. package/dist/src/turn-model-history.mjs +47 -47
  116. package/dist/tools/rtc-route-helper.ps1 +99 -99
  117. package/dist/tools/start-rtc-route-helper.ps1 +15 -15
  118. package/dist/web/vendor/markdown-it.LICENSE.txt +22 -22
  119. package/dist/web/vendor/markdown-it.umd.min.js +13 -13
  120. package/package.json +4 -4
@@ -1,72 +1,72 @@
1
- (function (root, factory) {
2
- if (typeof module === 'object' && module.exports) module.exports = factory();
3
- else root.CodeRelaxP2pDataFramer = factory();
4
- })(globalThis, () => {
5
- const CHUNK_CHARS = 12000;
6
- const MAX_MESSAGE_BYTES = 8 * 1024 * 1024;
7
- const MAX_PARTS = 1024;
8
- const byteLength = value => new TextEncoder().encode(value).length;
9
-
10
- return class {
11
- static IdleWatch = class {
12
- constructor(send, failed) { this.send = send; this.failed = failed; this.serial = 0; this.closed = false; }
13
- received() {
14
- if (this.closed) return;
15
- clearTimeout(this.timer); this.pending = undefined;
16
- this.timer = setTimeout(() => {
17
- this.pending = String(++this.serial);
18
- this.timer = setTimeout(() => { this.close(); this.failed(); }, 15000);
19
- try { this.send({ type: 'idle-ping', nonce: this.pending }); } catch { this.close(); this.failed(); }
20
- }, 15000);
21
- this.timer.unref?.();
22
- }
23
- accept(message) {
24
- if (!['idle-ping', 'idle-pong'].includes(message.type)) return false;
25
- if (typeof message.nonce !== 'string' || !/^[0-9]{1,12}$/.test(message.nonce)) throw new Error('Invalid idle probe');
26
- if (message.type === 'idle-pong' && message.nonce !== this.pending) return true;
27
- this.received();
28
- if (message.type === 'idle-ping') this.send({ type: 'idle-pong', nonce: message.nonce });
29
- return true;
30
- }
31
- close() { this.closed = true; clearTimeout(this.timer); this.pending = undefined; }
32
- };
33
- constructor() { this.inbound = undefined; }
34
- create(payload, id) {
35
- if (typeof payload !== 'string' || !/^[a-f0-9]{32}-[0-9]{1,10}$/.test(id)) throw new Error('Invalid P2P payload');
36
- const bytes = byteLength(payload);
37
- if (bytes > MAX_MESSAGE_BYTES) throw new Error('Code Relax 直连消息超过 8 MiB');
38
- const total = Math.max(1, Math.ceil(payload.length / CHUNK_CHARS));
39
- if (total > MAX_PARTS) throw new Error('Code Relax 直连消息分片过多');
40
- return { id, payload, bytes, index: 0, total };
41
- }
42
- frame(item) {
43
- if (!item || item.index >= item.total) return undefined;
44
- const start = item.index * CHUNK_CHARS;
45
- return JSON.stringify({ type: 'data', id: item.id, index: item.index, total: item.total,
46
- payload: item.payload.slice(start, start + CHUNK_CHARS) });
47
- }
48
- commit(item) { item.index++; return item.index >= item.total; }
49
- accept(message) {
50
- if (!message || message.type !== 'data') return { handled: false };
51
- if (!/^[a-f0-9]{32}-[0-9]{1,10}$/.test(message.id || '') || !Number.isSafeInteger(message.index) ||
52
- !Number.isSafeInteger(message.total) || message.total < 1 || message.total > MAX_PARTS ||
53
- message.index < 0 || message.index >= message.total || typeof message.payload !== 'string' ||
54
- message.payload.length > CHUNK_CHARS) throw new Error('Invalid P2P data frame');
55
- if (!this.inbound) {
56
- if (message.index !== 0) throw new Error('Invalid P2P data order');
57
- this.inbound = { id: message.id, total: message.total, next: 0, bytes: 0, parts: [] };
58
- }
59
- const current = this.inbound;
60
- if (current.id !== message.id || current.total !== message.total || current.next !== message.index) {
61
- throw new Error('Invalid P2P data order');
62
- }
63
- current.bytes += byteLength(message.payload);
64
- if (current.bytes > MAX_MESSAGE_BYTES) throw new Error('P2P data message too large');
65
- current.parts.push(message.payload); current.next++;
66
- if (current.next !== current.total) return { handled: true, complete: false };
67
- this.inbound = undefined;
68
- return { handled: true, complete: true, payload: current.parts.join('') };
69
- }
70
- reset() { this.inbound = undefined; }
71
- };
72
- });
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory();
3
+ else root.CodeRelaxP2pDataFramer = factory();
4
+ })(globalThis, () => {
5
+ const CHUNK_CHARS = 12000;
6
+ const MAX_MESSAGE_BYTES = 8 * 1024 * 1024;
7
+ const MAX_PARTS = 1024;
8
+ const byteLength = value => new TextEncoder().encode(value).length;
9
+
10
+ return class {
11
+ static IdleWatch = class {
12
+ constructor(send, failed) { this.send = send; this.failed = failed; this.serial = 0; this.closed = false; }
13
+ received() {
14
+ if (this.closed) return;
15
+ clearTimeout(this.timer); this.pending = undefined;
16
+ this.timer = setTimeout(() => {
17
+ this.pending = String(++this.serial);
18
+ this.timer = setTimeout(() => { this.close(); this.failed(); }, 15000);
19
+ try { this.send({ type: 'idle-ping', nonce: this.pending }); } catch { this.close(); this.failed(); }
20
+ }, 15000);
21
+ this.timer.unref?.();
22
+ }
23
+ accept(message) {
24
+ if (!['idle-ping', 'idle-pong'].includes(message.type)) return false;
25
+ if (typeof message.nonce !== 'string' || !/^[0-9]{1,12}$/.test(message.nonce)) throw new Error('Invalid idle probe');
26
+ if (message.type === 'idle-pong' && message.nonce !== this.pending) return true;
27
+ this.received();
28
+ if (message.type === 'idle-ping') this.send({ type: 'idle-pong', nonce: message.nonce });
29
+ return true;
30
+ }
31
+ close() { this.closed = true; clearTimeout(this.timer); this.pending = undefined; }
32
+ };
33
+ constructor() { this.inbound = undefined; }
34
+ create(payload, id) {
35
+ if (typeof payload !== 'string' || !/^[a-f0-9]{32}-[0-9]{1,10}$/.test(id)) throw new Error('Invalid P2P payload');
36
+ const bytes = byteLength(payload);
37
+ if (bytes > MAX_MESSAGE_BYTES) throw new Error('Code Relax 直连消息超过 8 MiB');
38
+ const total = Math.max(1, Math.ceil(payload.length / CHUNK_CHARS));
39
+ if (total > MAX_PARTS) throw new Error('Code Relax 直连消息分片过多');
40
+ return { id, payload, bytes, index: 0, total };
41
+ }
42
+ frame(item) {
43
+ if (!item || item.index >= item.total) return undefined;
44
+ const start = item.index * CHUNK_CHARS;
45
+ return JSON.stringify({ type: 'data', id: item.id, index: item.index, total: item.total,
46
+ payload: item.payload.slice(start, start + CHUNK_CHARS) });
47
+ }
48
+ commit(item) { item.index++; return item.index >= item.total; }
49
+ accept(message) {
50
+ if (!message || message.type !== 'data') return { handled: false };
51
+ if (!/^[a-f0-9]{32}-[0-9]{1,10}$/.test(message.id || '') || !Number.isSafeInteger(message.index) ||
52
+ !Number.isSafeInteger(message.total) || message.total < 1 || message.total > MAX_PARTS ||
53
+ message.index < 0 || message.index >= message.total || typeof message.payload !== 'string' ||
54
+ message.payload.length > CHUNK_CHARS) throw new Error('Invalid P2P data frame');
55
+ if (!this.inbound) {
56
+ if (message.index !== 0) throw new Error('Invalid P2P data order');
57
+ this.inbound = { id: message.id, total: message.total, next: 0, bytes: 0, parts: [] };
58
+ }
59
+ const current = this.inbound;
60
+ if (current.id !== message.id || current.total !== message.total || current.next !== message.index) {
61
+ throw new Error('Invalid P2P data order');
62
+ }
63
+ current.bytes += byteLength(message.payload);
64
+ if (current.bytes > MAX_MESSAGE_BYTES) throw new Error('P2P data message too large');
65
+ current.parts.push(message.payload); current.next++;
66
+ if (current.next !== current.total) return { handled: true, complete: false };
67
+ this.inbound = undefined;
68
+ return { handled: true, complete: true, payload: current.parts.join('') };
69
+ }
70
+ reset() { this.inbound = undefined; }
71
+ };
72
+ });
@@ -1,28 +1,28 @@
1
- (function (root, factory) {
2
- if (typeof module === 'object' && module.exports) module.exports = factory();
3
- else root.CodeRelaxP2pDiagnostics = factory();
4
- })(globalThis, () => class {
5
- constructor() {
6
- this.started = Date.now(); this.local = [0, 0, 0, 0, 0]; this.remote = [0, 0, 0, 0, 0];
7
- this.offer = false; this.answer = false; this.open = false; this.ping = false; this.pong = false;
8
- this.ice = 'new'; this.gathering = 'new'; this.error = 'none';
9
- }
10
- candidate(side, candidate) {
11
- const type = /\btyp (host|srflx|prflx|relay)\b/.exec(candidate || '')?.[1];
12
- const index = ['host', 'srflx', 'prflx', 'relay'].indexOf(type);
13
- const counts = side === 'local' ? this.local : this.remote;
14
- counts[index < 0 ? 4 : index]++;
15
- }
16
- snapshot(stage) {
17
- const known = (value, choices) => choices.includes(value) ? value : 'unknown';
18
- const counts = values => values.map(value => Math.min(value, 999)).join(',');
19
- return `stage=${known(stage, ['verified', 'timeout', 'failed', 'closed', 'complete', 'replaced', 'unsupported'])}` +
20
- `;ms=${Math.min(Date.now() - this.started, 999999)}` +
21
- `;offer=${Number(this.offer)};answer=${Number(this.answer)}` +
22
- `;ice=${known(this.ice, ['new', 'checking', 'connected', 'completed', 'failed', 'disconnected', 'closed'])}` +
23
- `;gathering=${known(this.gathering, ['new', 'in-progress', 'gathering', 'complete'])}` +
24
- `;local=${counts(this.local)};remote=${counts(this.remote)}` +
25
- `;open=${Number(this.open)};ping=${Number(this.ping)};pong=${Number(this.pong)}` +
26
- `;error=${known(this.error, ['none', 'stun', 'description', 'candidate', 'channel', 'frame', 'peer', 'initialization', 'signal', 'ice-policy'])}`;
27
- }
28
- });
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory();
3
+ else root.CodeRelaxP2pDiagnostics = factory();
4
+ })(globalThis, () => class {
5
+ constructor() {
6
+ this.started = Date.now(); this.local = [0, 0, 0, 0, 0]; this.remote = [0, 0, 0, 0, 0];
7
+ this.offer = false; this.answer = false; this.open = false; this.ping = false; this.pong = false;
8
+ this.ice = 'new'; this.gathering = 'new'; this.error = 'none';
9
+ }
10
+ candidate(side, candidate) {
11
+ const type = /\btyp (host|srflx|prflx|relay)\b/.exec(candidate || '')?.[1];
12
+ const index = ['host', 'srflx', 'prflx', 'relay'].indexOf(type);
13
+ const counts = side === 'local' ? this.local : this.remote;
14
+ counts[index < 0 ? 4 : index]++;
15
+ }
16
+ snapshot(stage) {
17
+ const known = (value, choices) => choices.includes(value) ? value : 'unknown';
18
+ const counts = values => values.map(value => Math.min(value, 999)).join(',');
19
+ return `stage=${known(stage, ['verified', 'timeout', 'failed', 'closed', 'complete', 'replaced', 'unsupported'])}` +
20
+ `;ms=${Math.min(Date.now() - this.started, 999999)}` +
21
+ `;offer=${Number(this.offer)};answer=${Number(this.answer)}` +
22
+ `;ice=${known(this.ice, ['new', 'checking', 'connected', 'completed', 'failed', 'disconnected', 'closed'])}` +
23
+ `;gathering=${known(this.gathering, ['new', 'in-progress', 'gathering', 'complete'])}` +
24
+ `;local=${counts(this.local)};remote=${counts(this.remote)}` +
25
+ `;open=${Number(this.open)};ping=${Number(this.ping)};pong=${Number(this.pong)}` +
26
+ `;error=${known(this.error, ['none', 'stun', 'description', 'candidate', 'channel', 'frame', 'peer', 'initialization', 'signal', 'ice-policy'])}`;
27
+ }
28
+ });
@@ -1,22 +1,22 @@
1
- (function (root, factory) {
2
- if (typeof module === 'object' && module.exports) module.exports = factory();
3
- else root.CodeRelaxIcePolicy = factory();
4
- })(globalThis, () => {
5
- const directType = type => ['host', 'srflx', 'prflx'].includes(type);
6
- const candidate = value => {
7
- if (typeof value !== 'string' || value.length > 2048 || /[\r\n]/.test(value)) return false;
8
- const fields = value.trim().split(/\s+/);
9
- return /^(?:a=)?candidate:/.test(fields[0]) && fields[6] === 'typ' && directType(fields[7]);
10
- };
11
- return {
12
- directType, candidate,
13
- servers: values => Array.isArray(values) && values.length <= 4 && values.every(value => {
14
- if (typeof value !== 'string' || !/^stun:[a-zA-Z0-9.-]+:[0-9]{1,5}$/.test(value)) return false;
15
- const port = Number(value.split(':').at(-1));
16
- return port > 0 && port <= 65535;
17
- }),
18
- sdp: value => typeof value === 'string' && value.length <= 65536 &&
19
- value.split(/\r?\n/).filter(line => line.startsWith('a=candidate:')).every(candidate),
20
- pair: (localType, remoteType) => directType(localType) && directType(remoteType),
21
- };
22
- });
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory();
3
+ else root.CodeRelaxIcePolicy = factory();
4
+ })(globalThis, () => {
5
+ const directType = type => ['host', 'srflx', 'prflx'].includes(type);
6
+ const candidate = value => {
7
+ if (typeof value !== 'string' || value.length > 2048 || /[\r\n]/.test(value)) return false;
8
+ const fields = value.trim().split(/\s+/);
9
+ return /^(?:a=)?candidate:/.test(fields[0]) && fields[6] === 'typ' && directType(fields[7]);
10
+ };
11
+ return {
12
+ directType, candidate,
13
+ servers: values => Array.isArray(values) && values.length <= 4 && values.every(value => {
14
+ if (typeof value !== 'string' || !/^stun:[a-zA-Z0-9.-]+:[0-9]{1,5}$/.test(value)) return false;
15
+ const port = Number(value.split(':').at(-1));
16
+ return port > 0 && port <= 65535;
17
+ }),
18
+ sdp: value => typeof value === 'string' && value.length <= 65536 &&
19
+ value.split(/\r?\n/).filter(line => line.startsWith('a=candidate:')).every(candidate),
20
+ pair: (localType, remoteType) => directType(localType) && directType(remoteType),
21
+ };
22
+ });
@@ -1,32 +1,32 @@
1
- (function (root, factory) {
2
- const pricing = factory();
3
- if (typeof module === 'object' && module.exports) module.exports = pricing;
4
- else root.CodeRelaxPlanPricing = pricing;
5
- })(globalThis, function () {
6
- // Desktop 26.1007.2314.0: usage plan row reads checkout prices, not invoices.
7
- async function read(accountId, get) {
8
- const response = await get('/accounts/check/v4-2023-04-27');
9
- const account = response?.accounts?.[accountId];
10
- if (!account || account.account?.is_deactivated || account.can_access_with_session === false) return null;
11
- const plan = account.account?.plan_type;
12
- if (!['free', 'go', 'plus', 'prolite', 'pro', 'promax'].includes(plan)) return null;
13
- const trial = account.last_active_subscription?.purchase_origin_platform === 'chatgpt_no_payment_trial';
14
- const billingCurrency = trial ? null : account.entitlement?.billing_currency;
15
- const selector = billingCurrency || 'US';
16
- if (!/^[A-Za-z]{2,3}$/.test(selector)) return null;
17
- const config = (await get(`/checkout_pricing_config/configs/${encodeURIComponent(selector)}`))?.currency_config;
18
- const amount = config?.[plan]?.month?.amount;
19
- const currency = config?.symbol_code;
20
- if (typeof amount !== 'number' || !Number.isFinite(amount) || amount < 0 || !/^[A-Z]{3}$/.test(currency || '')) return null;
21
- if (billingCurrency && currency !== billingCurrency.toUpperCase()) return null;
22
- return { accountId, plan, amount, currency, minorUnitExponent: config.minor_unit_exponent ?? null };
23
- }
24
- function format(value) {
25
- if (!value) return '';
26
- const digits = Number.isInteger(value.minorUnitExponent) && value.minorUnitExponent >= 0 && value.minorUnitExponent <= 4
27
- ? value.minorUnitExponent : undefined;
28
- return new Intl.NumberFormat('zh-CN', { style: 'currency', currency: value.currency, currencyDisplay: 'code',
29
- minimumFractionDigits: 0, maximumFractionDigits: digits }).format(value.amount);
30
- }
31
- return { read, format };
32
- });
1
+ (function (root, factory) {
2
+ const pricing = factory();
3
+ if (typeof module === 'object' && module.exports) module.exports = pricing;
4
+ else root.CodeRelaxPlanPricing = pricing;
5
+ })(globalThis, function () {
6
+ // Desktop 26.1007.2314.0: usage plan row reads checkout prices, not invoices.
7
+ async function read(accountId, get) {
8
+ const response = await get('/accounts/check/v4-2023-04-27');
9
+ const account = response?.accounts?.[accountId];
10
+ if (!account || account.account?.is_deactivated || account.can_access_with_session === false) return null;
11
+ const plan = account.account?.plan_type;
12
+ if (!['free', 'go', 'plus', 'prolite', 'pro', 'promax'].includes(plan)) return null;
13
+ const trial = account.last_active_subscription?.purchase_origin_platform === 'chatgpt_no_payment_trial';
14
+ const billingCurrency = trial ? null : account.entitlement?.billing_currency;
15
+ const selector = billingCurrency || 'US';
16
+ if (!/^[A-Za-z]{2,3}$/.test(selector)) return null;
17
+ const config = (await get(`/checkout_pricing_config/configs/${encodeURIComponent(selector)}`))?.currency_config;
18
+ const amount = config?.[plan]?.month?.amount;
19
+ const currency = config?.symbol_code;
20
+ if (typeof amount !== 'number' || !Number.isFinite(amount) || amount < 0 || !/^[A-Z]{3}$/.test(currency || '')) return null;
21
+ if (billingCurrency && currency !== billingCurrency.toUpperCase()) return null;
22
+ return { accountId, plan, amount, currency, minorUnitExponent: config.minor_unit_exponent ?? null };
23
+ }
24
+ function format(value) {
25
+ if (!value) return '';
26
+ const digits = Number.isInteger(value.minorUnitExponent) && value.minorUnitExponent >= 0 && value.minorUnitExponent <= 4
27
+ ? value.minorUnitExponent : undefined;
28
+ return new Intl.NumberFormat('zh-CN', { style: 'currency', currency: value.currency, currencyDisplay: 'code',
29
+ minimumFractionDigits: 0, maximumFractionDigits: digits }).format(value.amount);
30
+ }
31
+ return { read, format };
32
+ });
@@ -1,69 +1,69 @@
1
- (function (root, factory) {
2
- if (typeof module === 'object' && module.exports) module.exports = factory();
3
- else root.CodexQuestionAttention = factory();
4
- })(globalThis, function () {
5
- function parseQuestionReply(text) {
6
- const match = /^\s*<send_user_message_question_reply>\s*([\s\S]*?)\s*<\/send_user_message_question_reply>\s*$/.exec(text);
7
- if (!match) return null;
8
- let replies;
9
- try { replies = JSON.parse(match[1]); } catch { return null; }
10
- if (!Array.isArray(replies) || !replies.length || !replies.every(reply =>
11
- reply && typeof reply.question === 'string' && typeof reply.answer === 'string')) return null;
12
- return replies;
13
- }
14
-
15
- function questionIds(item) {
16
- if (!item?.id || item.delivery !== 'async') return [];
17
- return item.questions?.length
18
- ? item.questions.map((_, index) => JSON.stringify(['request_user_input_async', item.id, index])) : [item.id];
19
- }
20
-
21
- // Only identities cross the catalog event channel, never question/answer bodies.
22
- function fromNotification(method, params) {
23
- const turnId = params.turnId || params.turn?.id;
24
- if (!params.threadId || !turnId) return null;
25
- if (method === 'turn/completed') return { turnId, completed: true };
26
- if (method !== 'item/completed') return null;
27
- const item = params.item;
28
- if (item?.type === 'agentMessage') {
29
- const questions = questionIds(item);
30
- return questions.length ? { turnId, questions } : null;
31
- }
32
- if (item?.type === 'userMessage') {
33
- const text = (item.content || []).filter(part => part.type === 'text').map(part => part.text).join('\n');
34
- const answered = (parseQuestionReply(text) || []).map(reply => reply.questionItemId).filter(id => typeof id === 'string');
35
- return answered.length ? { turnId, answered } : null;
36
- }
37
- return null;
38
- }
39
- // A successful submission is enough to dismiss a question; model consumption
40
- // can happen later. Store identities only, never answers or replayable writes.
41
- function createAnswerStore({ storage, scope, onError }) {
42
- const records = new Map();
43
- const key = thread => 'codexRemoteAnsweredQuestions:' + JSON.stringify([
44
- scope(), thread.hostId || 'local', thread.id,
45
- ]);
46
- function read(owner) {
47
- if (!records.has(owner)) {
48
- try {
49
- const ids = JSON.parse(storage.getItem(owner) || '[]');
50
- records.set(owner, new Set(Array.isArray(ids) ? ids.filter(id => typeof id === 'string') : []));
51
- } catch (error) { records.set(owner, new Set()); onError?.(error); }
52
- }
53
- return records.get(owner);
54
- }
55
- function remember(owner, ids) {
56
- const answered = read(owner);
57
- let changed = false;
58
- for (const id of ids) if (typeof id === 'string' && !answered.has(id)) {
59
- answered.add(id); changed = true;
60
- }
61
- if (changed) {
62
- try { storage.setItem(owner, JSON.stringify([...answered])); }
63
- catch (error) { onError?.(error); }
64
- }
65
- }
66
- return { key, has: (thread, id) => read(key(thread)).has(id), remember };
67
- }
68
- return { parseQuestionReply, questionIds, fromNotification, createAnswerStore };
69
- });
1
+ (function (root, factory) {
2
+ if (typeof module === 'object' && module.exports) module.exports = factory();
3
+ else root.CodexQuestionAttention = factory();
4
+ })(globalThis, function () {
5
+ function parseQuestionReply(text) {
6
+ const match = /^\s*<send_user_message_question_reply>\s*([\s\S]*?)\s*<\/send_user_message_question_reply>\s*$/.exec(text);
7
+ if (!match) return null;
8
+ let replies;
9
+ try { replies = JSON.parse(match[1]); } catch { return null; }
10
+ if (!Array.isArray(replies) || !replies.length || !replies.every(reply =>
11
+ reply && typeof reply.question === 'string' && typeof reply.answer === 'string')) return null;
12
+ return replies;
13
+ }
14
+
15
+ function questionIds(item) {
16
+ if (!item?.id || item.delivery !== 'async') return [];
17
+ return item.questions?.length
18
+ ? item.questions.map((_, index) => JSON.stringify(['request_user_input_async', item.id, index])) : [item.id];
19
+ }
20
+
21
+ // Only identities cross the catalog event channel, never question/answer bodies.
22
+ function fromNotification(method, params) {
23
+ const turnId = params.turnId || params.turn?.id;
24
+ if (!params.threadId || !turnId) return null;
25
+ if (method === 'turn/completed') return { turnId, completed: true };
26
+ if (method !== 'item/completed') return null;
27
+ const item = params.item;
28
+ if (item?.type === 'agentMessage') {
29
+ const questions = questionIds(item);
30
+ return questions.length ? { turnId, questions } : null;
31
+ }
32
+ if (item?.type === 'userMessage') {
33
+ const text = (item.content || []).filter(part => part.type === 'text').map(part => part.text).join('\n');
34
+ const answered = (parseQuestionReply(text) || []).map(reply => reply.questionItemId).filter(id => typeof id === 'string');
35
+ return answered.length ? { turnId, answered } : null;
36
+ }
37
+ return null;
38
+ }
39
+ // A successful submission is enough to dismiss a question; model consumption
40
+ // can happen later. Store identities only, never answers or replayable writes.
41
+ function createAnswerStore({ storage, scope, onError }) {
42
+ const records = new Map();
43
+ const key = thread => 'codexRemoteAnsweredQuestions:' + JSON.stringify([
44
+ scope(), thread.hostId || 'local', thread.id,
45
+ ]);
46
+ function read(owner) {
47
+ if (!records.has(owner)) {
48
+ try {
49
+ const ids = JSON.parse(storage.getItem(owner) || '[]');
50
+ records.set(owner, new Set(Array.isArray(ids) ? ids.filter(id => typeof id === 'string') : []));
51
+ } catch (error) { records.set(owner, new Set()); onError?.(error); }
52
+ }
53
+ return records.get(owner);
54
+ }
55
+ function remember(owner, ids) {
56
+ const answered = read(owner);
57
+ let changed = false;
58
+ for (const id of ids) if (typeof id === 'string' && !answered.has(id)) {
59
+ answered.add(id); changed = true;
60
+ }
61
+ if (changed) {
62
+ try { storage.setItem(owner, JSON.stringify([...answered])); }
63
+ catch (error) { onError?.(error); }
64
+ }
65
+ }
66
+ return { key, has: (thread, id) => read(key(thread)).has(id), remember };
67
+ }
68
+ return { parseQuestionReply, questionIds, fromNotification, createAnswerStore };
69
+ });
@@ -1,31 +1,31 @@
1
- (function (root, factory) {
2
- const api = factory();
3
- if (typeof module === 'object' && module.exports) module.exports = api;
4
- else root.CodeRelaxReleaseVersion = api;
5
- })(typeof globalThis !== 'undefined' ? globalThis : this, function () {
6
- function parse(value) {
7
- if (typeof value !== 'string') return null;
8
- const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(value);
9
- if (!match) return null;
10
- const core = match.slice(1, 4).map(Number), pre = match[4]?.split('.') || [];
11
- if (core.some(part => !Number.isSafeInteger(part)) || pre.some(part => /^\d+$/.test(part) && (part.length > 1 && part[0] === '0' || !Number.isSafeInteger(Number(part))))) return null;
12
- return { core, pre };
13
- }
14
- function compare(a, b) {
15
- const left = parse(a), right = parse(b);
16
- if (!left || !right) return null;
17
- for (let i = 0; i < 3; i++) if (left.core[i] !== right.core[i]) return left.core[i] > right.core[i] ? 1 : -1;
18
- if (!left.pre.length || !right.pre.length) return left.pre.length === right.pre.length ? 0 : left.pre.length ? -1 : 1;
19
- for (let i = 0; i < Math.max(left.pre.length, right.pre.length); i++) {
20
- const x = left.pre[i], y = right.pre[i];
21
- if (x === y) continue;
22
- if (x === undefined || y === undefined) return x === undefined ? -1 : 1;
23
- const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
24
- if (nx && ny) return Number(x) > Number(y) ? 1 : -1;
25
- if (nx !== ny) return nx ? -1 : 1;
26
- return x > y ? 1 : -1;
27
- }
28
- return 0;
29
- }
30
- return { compare };
31
- });
1
+ (function (root, factory) {
2
+ const api = factory();
3
+ if (typeof module === 'object' && module.exports) module.exports = api;
4
+ else root.CodeRelaxReleaseVersion = api;
5
+ })(typeof globalThis !== 'undefined' ? globalThis : this, function () {
6
+ function parse(value) {
7
+ if (typeof value !== 'string') return null;
8
+ const match = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-([0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*))?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/.exec(value);
9
+ if (!match) return null;
10
+ const core = match.slice(1, 4).map(Number), pre = match[4]?.split('.') || [];
11
+ if (core.some(part => !Number.isSafeInteger(part)) || pre.some(part => /^\d+$/.test(part) && (part.length > 1 && part[0] === '0' || !Number.isSafeInteger(Number(part))))) return null;
12
+ return { core, pre };
13
+ }
14
+ function compare(a, b) {
15
+ const left = parse(a), right = parse(b);
16
+ if (!left || !right) return null;
17
+ for (let i = 0; i < 3; i++) if (left.core[i] !== right.core[i]) return left.core[i] > right.core[i] ? 1 : -1;
18
+ if (!left.pre.length || !right.pre.length) return left.pre.length === right.pre.length ? 0 : left.pre.length ? -1 : 1;
19
+ for (let i = 0; i < Math.max(left.pre.length, right.pre.length); i++) {
20
+ const x = left.pre[i], y = right.pre[i];
21
+ if (x === y) continue;
22
+ if (x === undefined || y === undefined) return x === undefined ? -1 : 1;
23
+ const nx = /^\d+$/.test(x), ny = /^\d+$/.test(y);
24
+ if (nx && ny) return Number(x) > Number(y) ? 1 : -1;
25
+ if (nx !== ny) return nx ? -1 : 1;
26
+ return x > y ? 1 : -1;
27
+ }
28
+ return 0;
29
+ }
30
+ return { compare };
31
+ });
@@ -1,22 +1,22 @@
1
- import { sharedThreadProjectId, dotsThreadProjectId } from './shared-catalog.mjs';
2
-
3
- // One metadata page per request. Local and hosted cursors must never be mixed.
4
- export async function archivedThreadsPage(server, localServer, hostId, cursor) {
5
- await server.connect();
6
- const identity = server.profileIdentity;
7
- const [page, projects] = await Promise.all([
8
- server.request('thread/list', { archived: true, limit: 100, sortKey: 'updated_at',
9
- sortDirection: 'desc', ...(hostId === 'local' ? { useStateDbOnly: true } : {}),
10
- ...(cursor ? { cursor } : {}) }),
11
- localServer.projects(),
12
- ]);
13
- if (hostId === 'durable' && identity !== server.profileIdentity) throw new Error('云端账号已变化,请重新读取归档列表。');
14
- const group = hostId === 'durable' ? dotsThreadProjectId : sharedThreadProjectId;
15
- return { nextCursor: page.nextCursor || null,
16
- threads: page.data.filter(thread => hostId === 'durable' ? thread.threadSource === 'aeon_child' : thread.threadSource !== 'aeon')
17
- .map(thread => ({ id: thread.id, hostId, kind: 'codex', threadSource: thread.threadSource,
18
- title: thread.name || thread.preview || '', projectId: group(thread, projects),
19
- cwd: thread.cwd, updatedAt: thread.updatedAt, recencyAt: thread.recencyAt ?? thread.updatedAt,
20
- status: typeof thread.status === 'string' ? thread.status : thread.status?.type || 'unknown',
21
- activeFlags: Array.isArray(thread.status?.activeFlags) ? thread.status.activeFlags : [] })) };
22
- }
1
+ import { sharedThreadProjectId, dotsThreadProjectId } from './shared-catalog.mjs';
2
+
3
+ // One metadata page per request. Local and hosted cursors must never be mixed.
4
+ export async function archivedThreadsPage(server, localServer, hostId, cursor) {
5
+ await server.connect();
6
+ const identity = server.profileIdentity;
7
+ const [page, projects] = await Promise.all([
8
+ server.request('thread/list', { archived: true, limit: 100, sortKey: 'updated_at',
9
+ sortDirection: 'desc', ...(hostId === 'local' ? { useStateDbOnly: true } : {}),
10
+ ...(cursor ? { cursor } : {}) }),
11
+ localServer.projects(),
12
+ ]);
13
+ if (hostId === 'durable' && identity !== server.profileIdentity) throw new Error('云端账号已变化,请重新读取归档列表。');
14
+ const group = hostId === 'durable' ? dotsThreadProjectId : sharedThreadProjectId;
15
+ return { nextCursor: page.nextCursor || null,
16
+ threads: page.data.filter(thread => hostId === 'durable' ? thread.threadSource === 'aeon_child' : thread.threadSource !== 'aeon')
17
+ .map(thread => ({ id: thread.id, hostId, kind: 'codex', threadSource: thread.threadSource,
18
+ title: thread.name || thread.preview || '', projectId: group(thread, projects),
19
+ cwd: thread.cwd, updatedAt: thread.updatedAt, recencyAt: thread.recencyAt ?? thread.updatedAt,
20
+ status: typeof thread.status === 'string' ? thread.status : thread.status?.type || 'unknown',
21
+ activeFlags: Array.isArray(thread.status?.activeFlags) ? thread.status.activeFlags : [] })) };
22
+ }
@@ -1,18 +1,18 @@
1
- import fs from 'node:fs';
2
- import { spawn } from 'node:child_process';
3
- import { startWindowsProcess } from './platform/windows/background-process.mjs';
4
-
5
- export const processAlive = pid => {
6
- try { process.kill(pid, 0); return true; }
7
- catch (error) { if (error.code === 'ESRCH') return false; throw error; }
8
- };
9
- export async function startBackground(executable, args, environment, logs = []) {
10
- if (process.platform === 'win32') return startWindowsProcess(executable, args, environment, logs);
11
- const descriptors = logs.map(file => fs.openSync(file, 'a'));
12
- try {
13
- const child = spawn(executable, args, { detached: true, env: environment,
14
- stdio: ['ignore', descriptors[0] ?? 'ignore', descriptors[1] ?? 'ignore'] });
15
- await new Promise((resolve, reject) => { child.once('spawn', resolve); child.once('error', reject); });
16
- child.unref(); return child.pid;
17
- } finally { descriptors.forEach(fd => fs.closeSync(fd)); }
18
- }
1
+ import fs from 'node:fs';
2
+ import { spawn } from 'node:child_process';
3
+ import { startWindowsProcess } from './platform/windows/background-process.mjs';
4
+
5
+ export const processAlive = pid => {
6
+ try { process.kill(pid, 0); return true; }
7
+ catch (error) { if (error.code === 'ESRCH') return false; throw error; }
8
+ };
9
+ export async function startBackground(executable, args, environment, logs = []) {
10
+ if (process.platform === 'win32') return startWindowsProcess(executable, args, environment, logs);
11
+ const descriptors = logs.map(file => fs.openSync(file, 'a'));
12
+ try {
13
+ const child = spawn(executable, args, { detached: true, env: environment,
14
+ stdio: ['ignore', descriptors[0] ?? 'ignore', descriptors[1] ?? 'ignore'] });
15
+ await new Promise((resolve, reject) => { child.once('spawn', resolve); child.once('error', reject); });
16
+ child.unref(); return child.pid;
17
+ } finally { descriptors.forEach(fd => fs.closeSync(fd)); }
18
+ }