@walkhi/code-relax 0.1.0-beta.2 → 0.1.0-beta.20

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/README.md +55 -71
  2. package/dist/bin/codex-remote.mjs +150 -126
  3. package/dist/bin/manage-relay-admin.mjs +20 -0
  4. package/dist/bin/migrate-relay-db.mjs +107 -0
  5. package/dist/bin/self-relay-admin.mjs +8 -0
  6. package/dist/bin/self-relay-demo.mjs +2 -2
  7. package/dist/bin/self-relay-server.mjs +18 -10
  8. package/dist/shared/app-server-events.cjs +42 -15
  9. package/dist/shared/file-mentions.cjs +35 -0
  10. package/dist/shared/server-requests.cjs +86 -58
  11. package/dist/skills/code-relax/SKILL.md +7 -6
  12. package/dist/src/desktop-launcher.mjs +16 -21
  13. package/dist/src/file-upload-session.mjs +124 -0
  14. package/dist/src/lan-socket-server.mjs +52 -9
  15. package/dist/src/managed-app-server.mjs +44 -13
  16. package/dist/src/message-images.mjs +0 -18
  17. package/dist/src/onboarding.mjs +9 -11
  18. package/dist/src/platform/README.md +1 -1
  19. package/dist/src/platform/windows/background-process.mjs +1 -1
  20. package/dist/src/platform/windows/codex-runtime.mjs +251 -0
  21. package/dist/src/platform/windows/desktop-host.mjs +17 -3
  22. package/dist/src/platform/windows/desktop-info.ps1 +2 -4
  23. package/dist/src/platform/windows/desktop-runtime.ps1 +10 -0
  24. package/dist/src/platform/windows/desktop-shortcuts.ps1 +7 -14
  25. package/dist/src/platform/windows/launch-worker.mjs +42 -0
  26. package/dist/src/platform/windows/resident-start.js +20 -0
  27. package/dist/src/platform/windows/resident-startup.ps1 +76 -20
  28. package/dist/src/platform/windows/service-host.mjs +4 -16
  29. package/dist/src/platform/windows/start-hidden-console.ps1 +10 -5
  30. package/dist/src/platform/windows/stop-desktop.ps1 +7 -4
  31. package/dist/src/platform/windows/user-environment.mjs +1 -1
  32. package/dist/src/runtime-discovery.mjs +43 -0
  33. package/dist/src/self-relay/admin-cloud.mjs +101 -0
  34. package/dist/src/self-relay/admin-page.mjs +79 -0
  35. package/dist/src/self-relay/admin-server.mjs +66 -0
  36. package/dist/src/self-relay/admin-state.mjs +82 -19
  37. package/dist/src/self-relay/admin-style.mjs +9 -0
  38. package/dist/src/self-relay/admin-usage-page.mjs +28 -0
  39. package/dist/src/self-relay/connector.mjs +243 -30
  40. package/dist/src/self-relay/demo.mjs +3 -4
  41. package/dist/src/self-relay/email-accounts.mjs +141 -0
  42. package/dist/src/self-relay/lifecycle.mjs +99 -142
  43. package/dist/src/self-relay/mysql-state.mjs +104 -0
  44. package/dist/src/self-relay/p2p-probe.mjs +1 -1
  45. package/dist/src/self-relay/server.mjs +335 -59
  46. package/dist/src/self-relay/usage-diagnostics.mjs +46 -0
  47. package/dist/src/self-relay/usage-meter.mjs +125 -0
  48. package/dist/src/server.mjs +731 -1439
  49. package/dist/src/service-control.mjs +4 -4
  50. package/dist/src/service-doctor.mjs +27 -29
  51. package/dist/src/service-health.mjs +2 -2
  52. package/dist/src/service-install.mjs +1 -4
  53. package/dist/src/service-lifecycle.mjs +19 -19
  54. package/dist/src/shared-app-server.mjs +277 -270
  55. package/dist/src/shared-catalog.mjs +1 -11
  56. package/dist/src/shared-recovery.mjs +11 -9
  57. package/dist/src/shared-thread-stream.mjs +1 -1
  58. package/dist/src/skill-install.mjs +0 -13
  59. package/package.json +17 -18
  60. package/tools/postinstall.mjs +69 -15
  61. package/dist/src/app-server-client.mjs +0 -468
  62. package/dist/src/app-server-tasks.mjs +0 -358
  63. package/dist/src/debug-ui.mjs +0 -131
  64. package/dist/src/platform/windows/desktop-monitor.mjs +0 -34
  65. package/dist/src/platform/windows/desktop-shortcut-run.ps1 +0 -5
  66. package/dist/src/platform/windows/desktop-tools.mjs +0 -48
  67. package/dist/src/platform/windows/launch-worker.ps1 +0 -20
  68. package/dist/src/thread-catalog.mjs +0 -47
  69. package/dist/tools/find-desktop-pipe.mjs +0 -10
  70. package/dist/web/activity-view.js +0 -283
  71. package/dist/web/approval-ui.js +0 -188
  72. package/dist/web/capabilities.js +0 -57
  73. package/dist/web/chat-transport.js +0 -202
  74. package/dist/web/chat.css +0 -782
  75. package/dist/web/chat.js +0 -3830
  76. package/dist/web/client-platform.js +0 -11
  77. package/dist/web/community-view.js +0 -20
  78. package/dist/web/community.css +0 -77
  79. package/dist/web/community.html +0 -37
  80. package/dist/web/composer-controller.js +0 -101
  81. package/dist/web/conversation-controller.js +0 -99
  82. package/dist/web/disclosure-state-controller.js +0 -95
  83. package/dist/web/draft-controller.js +0 -103
  84. package/dist/web/harmony-platform.js +0 -52
  85. package/dist/web/highlight-powershell.min.js +0 -39
  86. package/dist/web/highlight.min.js +0 -1262
  87. package/dist/web/history-cache.js +0 -240
  88. package/dist/web/history-controller.js +0 -167
  89. package/dist/web/index.html +0 -325
  90. package/dist/web/lan-session.js +0 -122
  91. package/dist/web/link-action-controller.js +0 -212
  92. package/dist/web/message-send-controller.js +0 -177
  93. package/dist/web/message-view.js +0 -98
  94. package/dist/web/p2p-data-channel.js +0 -50
  95. package/dist/web/p2p-diagnostics.js +0 -28
  96. package/dist/web/p2p-probe.js +0 -123
  97. package/dist/web/page-resume.js +0 -28
  98. package/dist/web/pending-message-store.js +0 -108
  99. package/dist/web/queue-controller.js +0 -82
  100. package/dist/web/resources.json +0 -1
  101. package/dist/web/self-relay-session.js +0 -129
  102. package/dist/web/server-requests.js +0 -67
  103. package/dist/web/station-connection-controller.js +0 -75
  104. package/dist/web/task-list-view.js +0 -296
  105. package/dist/web/thread-attention-controller.js +0 -124
  106. package/dist/web/thread-context-controller.js +0 -30
  107. package/dist/web/thread-list-controller.js +0 -61
  108. package/dist/web/thread-list-sync.js +0 -86
  109. package/dist/web/thread-title-controller.js +0 -57
  110. package/dist/web/timeline-formatters.js +0 -249
  111. package/dist/web/timeline-reducer.js +0 -81
  112. package/dist/web/timeline-renderer.js +0 -161
  113. package/dist/web/timeline-scroll-controller.js +0 -50
  114. package/dist/web/timeline-sync.js +0 -67
  115. package/dist/web/usage-controller.js +0 -258
  116. package/dist/web/vendor/README.md +0 -14
  117. package/dist/web/vendor/highlight-powershell.min.js +0 -39
  118. package/dist/web/vendor/highlight.LICENSE.txt +0 -29
  119. package/dist/web/vendor/highlight.min.js +0 -1262
  120. package/dist/web/vendor/lucide.LICENSE.txt +0 -17
@@ -0,0 +1,125 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
3
+ const epoch = value => new Date(`${value.replace(' ', 'T')}Z`).getTime();
4
+
5
+ // Count confirmed intervals only; a lost connection never creates estimated time.
6
+ export function usageMeter(pool) {
7
+ async function action(connection, computerId, clientId, kind, key) {
8
+ if (!connection.userId || !['message', 'turn'].includes(kind) || typeof key !== 'string' || !key || key.length > 128) return;
9
+ const column = kind === 'message' ? 'message_count' : 'turn_count';
10
+ const db = await pool.getConnection();
11
+ try {
12
+ await db.beginTransaction();
13
+ const [result] = await db.execute(`INSERT IGNORE INTO relay_usage_actions
14
+ (computer_id,kind,action_key,user_id,client_id,occurred_at)
15
+ VALUES (?,?,?,?,?,UTC_TIMESTAMP(3))`,
16
+ [computerId, kind, key, connection.userId, clientId]);
17
+ if (result.affectedRows === 1) {
18
+ await db.execute(`INSERT INTO relay_usage_totals (user_id,${column},updated_at)
19
+ VALUES (?,1,UTC_TIMESTAMP(3)) ON DUPLICATE KEY UPDATE ${column}=${column}+1,
20
+ updated_at=VALUES(updated_at)`, [connection.userId]);
21
+ await db.execute(`INSERT INTO relay_usage_computer_totals (computer_id,${column},updated_at)
22
+ VALUES (?,1,UTC_TIMESTAMP(3)) ON DUPLICATE KEY UPDATE ${column}=${column}+1,
23
+ updated_at=VALUES(updated_at)`, [computerId]);
24
+ }
25
+ await db.commit();
26
+ return result.affectedRows === 1;
27
+ } catch (error) { await db.rollback(); throw error; }
28
+ finally { db.release(); }
29
+ }
30
+ async function turnOrigin(computerId, key) {
31
+ const [rows] = await pool.execute(`SELECT user_id,client_id FROM relay_usage_actions
32
+ WHERE computer_id=? AND kind='turn' AND action_key=?`, [computerId, key]);
33
+ return rows[0] ? { userId: rows[0].user_id, clientId: rows[0].client_id } : null;
34
+ }
35
+ async function pulse(connection, active, computerId, clientId, externalKey = null) {
36
+ if (!connection.userId) return;
37
+ if (!active && !connection.usageSessionId) return;
38
+ if (active && !connection.usageSessionId) {
39
+ const id = randomUUID();
40
+ await pool.execute(`INSERT INTO relay_usage_sessions
41
+ (id,kind,external_key,user_id,computer_id,client_id,started_at,confirmed_until,charged_seconds)
42
+ VALUES (?,'task',?,?,?,?,UTC_TIMESTAMP(3),UTC_TIMESTAMP(3),0)`, [id, externalKey, connection.userId, computerId, clientId]);
43
+ connection.usageSessionId = id;
44
+ return;
45
+ }
46
+ const id = connection.usageSessionId;
47
+ const db = await pool.getConnection();
48
+ try {
49
+ await db.beginTransaction();
50
+ const [rows] = await db.execute('SELECT user_id,computer_id,confirmed_until,ended_at FROM relay_usage_sessions WHERE id=? FOR UPDATE', [id]);
51
+ const row = rows[0];
52
+ if (!row || row.ended_at) throw new Error('Invalid relay usage session');
53
+ const [clock] = await db.query('SELECT UTC_TIMESTAMP(3) AS now');
54
+ const now = clock[0].now;
55
+ const elapsedMs = Math.max(0, epoch(now) - epoch(row.confirmed_until));
56
+ const seconds = Math.min(elapsedMs, 20000) / 1000;
57
+ const [plans] = await db.execute('SELECT tier,valid_until FROM relay_usage_entitlements WHERE user_id=?', [row.user_id]);
58
+ const subscribed = plans[0]?.tier === 'subscriber' && plans[0].valid_until && epoch(plans[0].valid_until) > epoch(now);
59
+ const freeSeconds = subscribed ? 0 : seconds;
60
+ await db.execute(`UPDATE relay_usage_sessions SET confirmed_until=?,ended_at=?,charged_seconds=charged_seconds+?,
61
+ free_charged_seconds=free_charged_seconds+? WHERE id=?`, [now, active ? null : now, seconds, freeSeconds, id]);
62
+ if (seconds > 0) {
63
+ await db.execute(`INSERT INTO relay_usage_totals (user_id,task_seconds,updated_at)
64
+ VALUES (?,?,?) ON DUPLICATE KEY UPDATE task_seconds=task_seconds+VALUES(task_seconds),
65
+ updated_at=VALUES(updated_at)`, [row.user_id, seconds, now]);
66
+ await db.execute(`INSERT INTO relay_usage_computer_totals (computer_id,task_seconds,free_task_seconds,updated_at)
67
+ VALUES (?,?,?,?) ON DUPLICATE KEY UPDATE task_seconds=task_seconds+VALUES(task_seconds),
68
+ free_task_seconds=free_task_seconds+VALUES(free_task_seconds),updated_at=VALUES(updated_at)`,
69
+ [row.computer_id, seconds, freeSeconds, now]);
70
+ }
71
+ await db.commit();
72
+ if (!active) connection.usageSessionId = undefined;
73
+ } catch (error) { await db.rollback(); throw error; }
74
+ finally { db.release(); }
75
+ }
76
+
77
+ async function lost(connection) {
78
+ const id = connection.usageSessionId;
79
+ connection.usageSessionId = undefined;
80
+ if (!id) return;
81
+ await pool.execute(`UPDATE relay_usage_sessions SET ended_at=confirmed_until
82
+ WHERE id=? AND ended_at IS NULL`, [id]);
83
+ }
84
+
85
+ return { action, turnOrigin, pulse, lost };
86
+ }
87
+
88
+ export async function usageReport(pool, page, userId = '') {
89
+ if (userId) {
90
+ const [users] = await pool.execute(`SELECT u.id,i.normalized_value AS email,
91
+ COALESCE(t.task_seconds,0) AS task_seconds,
92
+ COALESCE(t.message_count,0) AS message_count,COALESCE(t.turn_count,0) AS turn_count
93
+ FROM users u JOIN user_login_identities i ON i.user_id=u.id AND i.kind='email'
94
+ LEFT JOIN relay_usage_totals t ON t.user_id=u.id WHERE u.id=?`, [userId]);
95
+ if (!users.length) return null;
96
+ const [computers] = await pool.execute(`SELECT c.id AS computer_id,
97
+ COALESCE(s.task_seconds,0) AS task_seconds,
98
+ COALESCE(a.message_count,0) AS message_count,
99
+ COALESCE(a.turn_count,0) AS turn_count,
100
+ COALESCE(GREATEST(s.last_used_at,a.last_used_at),s.last_used_at,a.last_used_at) AS last_used_at
101
+ FROM computers c
102
+ LEFT JOIN (SELECT computer_id,
103
+ SUM(charged_seconds) AS task_seconds,
104
+ MAX(started_at) AS last_used_at FROM relay_usage_sessions WHERE user_id=? GROUP BY computer_id) s ON s.computer_id=c.id
105
+ LEFT JOIN (SELECT computer_id,
106
+ SUM(kind='message') AS message_count,SUM(kind='turn') AS turn_count,
107
+ MAX(occurred_at) AS last_used_at
108
+ FROM relay_usage_actions WHERE user_id=? GROUP BY computer_id) a ON a.computer_id=c.id
109
+ WHERE s.computer_id IS NOT NULL OR a.computer_id IS NOT NULL
110
+ ORDER BY last_used_at DESC`, [userId, userId]);
111
+ return { user: users[0], computers };
112
+ }
113
+ const offset = (page - 1) * 30;
114
+ const [counts] = await pool.query(`SELECT COUNT(*) AS total FROM user_login_identities WHERE kind='email'`);
115
+ const [rows] = await pool.execute(`SELECT u.id,i.normalized_value AS email,
116
+ COALESCE(t.task_seconds,0) AS task_seconds,
117
+ COALESCE(t.message_count,0) AS message_count,COALESCE(t.turn_count,0) AS turn_count,
118
+ COALESCE(GREATEST(s.last_used_at,a.last_used_at),s.last_used_at,a.last_used_at) AS last_used_at
119
+ FROM users u JOIN user_login_identities i ON i.user_id=u.id AND i.kind='email'
120
+ LEFT JOIN relay_usage_totals t ON t.user_id=u.id
121
+ LEFT JOIN (SELECT user_id,MAX(started_at) AS last_used_at FROM relay_usage_sessions GROUP BY user_id) s ON s.user_id=u.id
122
+ LEFT JOIN (SELECT user_id,MAX(occurred_at) AS last_used_at FROM relay_usage_actions GROUP BY user_id) a ON a.user_id=u.id
123
+ ORDER BY task_seconds DESC,last_used_at DESC,u.id LIMIT ? OFFSET ?`, [30, offset]);
124
+ return { page, pageSize: 30, total: counts[0].total, rows };
125
+ }