antri_cli 1.45.0 → 1.47.0
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/dist/cli/shortcuts.d.ts.map +1 -1
- package/dist/cli/shortcuts.js +23 -0
- package/dist/cli/shortcuts.js.map +1 -1
- package/dist/cloud/auth.d.ts.map +1 -1
- package/dist/cloud/auth.js +26 -5
- package/dist/cloud/auth.js.map +1 -1
- package/dist/core/agent.d.ts +2 -0
- package/dist/core/agent.d.ts.map +1 -1
- package/dist/core/agent.js +6 -1
- package/dist/core/agent.js.map +1 -1
- package/dist/core/config.js +1 -1
- package/dist/core/tools.d.ts +4 -1
- package/dist/core/tools.d.ts.map +1 -1
- package/dist/core/tools.js +21 -2
- package/dist/core/tools.js.map +1 -1
- package/dist/core/updater.d.ts +1 -1
- package/dist/core/updater.d.ts.map +1 -1
- package/dist/core/updater.js +1 -1
- package/dist/core/updater.js.map +1 -1
- package/dist/desktop/public/app.js +163 -1
- package/dist/desktop/public/index.html +38 -1
- package/dist/desktop/public/style.css +173 -0
- package/dist/desktop/server.d.ts +3 -0
- package/dist/desktop/server.d.ts.map +1 -1
- package/dist/desktop/server.js +74 -1
- package/dist/desktop/server.js.map +1 -1
- package/dist/profiles/profileManager.d.ts +1 -1
- package/dist/profiles/profileManager.d.ts.map +1 -1
- package/dist/profiles/profileManager.js +51 -12
- package/dist/profiles/profileManager.js.map +1 -1
- package/package.json +2 -2
|
@@ -16,6 +16,7 @@ let skillSearchQuery = '';
|
|
|
16
16
|
|
|
17
17
|
// Initialize on Load
|
|
18
18
|
document.addEventListener('DOMContentLoaded', async () => {
|
|
19
|
+
await checkAuthStatus();
|
|
19
20
|
await loadStatus();
|
|
20
21
|
await loadCommands();
|
|
21
22
|
await loadProfiles();
|
|
@@ -455,7 +456,24 @@ async function submitPrompt() {
|
|
|
455
456
|
if (line.startsWith('data: ')) {
|
|
456
457
|
try {
|
|
457
458
|
const data = JSON.parse(line.slice(6));
|
|
458
|
-
if (data.
|
|
459
|
+
if (data.requestId && data.name && data.args !== undefined) {
|
|
460
|
+
// Interactive Permission Request Card
|
|
461
|
+
const permCard = document.createElement('div');
|
|
462
|
+
permCard.className = 'permission-prompt-card';
|
|
463
|
+
permCard.id = `card-${data.requestId}`;
|
|
464
|
+
permCard.innerHTML = `
|
|
465
|
+
<div class="perm-title">⚠️ Privacy & Security Permission Request</div>
|
|
466
|
+
<div class="perm-desc">Agent requested to execute tool: <b style="color:var(--accent-primary);">${data.name}</b></div>
|
|
467
|
+
<pre class="perm-args">${JSON.stringify(data.args, null, 2)}</pre>
|
|
468
|
+
<div class="perm-actions">
|
|
469
|
+
<button class="perm-btn perm-allow" onclick="respondDesktopPermission('${data.requestId}', true, false)">Allow Once</button>
|
|
470
|
+
<button class="perm-btn perm-always" onclick="respondDesktopPermission('${data.requestId}', true, true)">Always Allow</button>
|
|
471
|
+
<button class="perm-btn perm-deny" onclick="respondDesktopPermission('${data.requestId}', false, false)">Deny</button>
|
|
472
|
+
</div>
|
|
473
|
+
`;
|
|
474
|
+
assistantMsgEl.insertBefore(permCard, contentEl);
|
|
475
|
+
scrollToBottom();
|
|
476
|
+
} else if (data.token) {
|
|
459
477
|
accumulated += data.token;
|
|
460
478
|
contentEl.textContent = accumulated;
|
|
461
479
|
scrollToBottom();
|
|
@@ -479,6 +497,26 @@ async function submitPrompt() {
|
|
|
479
497
|
}
|
|
480
498
|
}
|
|
481
499
|
|
|
500
|
+
async function respondDesktopPermission(requestId, allowed, alwaysAllow) {
|
|
501
|
+
const card = document.getElementById(`card-${requestId}`);
|
|
502
|
+
if (card) {
|
|
503
|
+
card.innerHTML = `<div style="font-size:12px;font-weight:600;color:${allowed ? '#10b981' : '#f43f5e'};padding:4px 0;">${allowed ? '✓ Permission granted by user.' : '✕ Permission denied by user.'}</div>`;
|
|
504
|
+
}
|
|
505
|
+
try {
|
|
506
|
+
await fetch('/api/permission/response', {
|
|
507
|
+
method: 'POST',
|
|
508
|
+
headers: { 'Content-Type': 'application/json' },
|
|
509
|
+
body: JSON.stringify({ requestId, allowed, alwaysAllow }),
|
|
510
|
+
});
|
|
511
|
+
if (alwaysAllow) {
|
|
512
|
+
showToast('Permissions set to Always-Allow.');
|
|
513
|
+
await loadStatus();
|
|
514
|
+
}
|
|
515
|
+
} catch (e) {
|
|
516
|
+
console.error('Failed to submit permission response:', e);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
|
|
482
520
|
function appendMessage(role, text) {
|
|
483
521
|
const container = document.getElementById('chat-messages');
|
|
484
522
|
const row = document.createElement('div');
|
|
@@ -688,6 +726,37 @@ async function saveActiveProfile() {
|
|
|
688
726
|
showToast('Profile saved successfully.');
|
|
689
727
|
}
|
|
690
728
|
|
|
729
|
+
async function pushProfilesToCloud() {
|
|
730
|
+
try {
|
|
731
|
+
showToast('Pushing profiles to Google Cloud Firestore...');
|
|
732
|
+
const res = await fetch('/api/profile/push', { method: 'POST' });
|
|
733
|
+
const data = await res.json();
|
|
734
|
+
if (data.success) {
|
|
735
|
+
showToast(`Pushed ${data.count} profile(s) to Google Cloud Firestore.`);
|
|
736
|
+
} else {
|
|
737
|
+
showToast(`Push failed: ${data.error || 'Check network connection'}`, true);
|
|
738
|
+
}
|
|
739
|
+
} catch (err) {
|
|
740
|
+
showToast(`Push failed: ${err.message}`, true);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
|
|
744
|
+
async function pullProfilesFromCloud() {
|
|
745
|
+
try {
|
|
746
|
+
showToast('Pulling profiles from Google Cloud Firestore...');
|
|
747
|
+
const res = await fetch('/api/profile/pull', { method: 'POST' });
|
|
748
|
+
const data = await res.json();
|
|
749
|
+
if (data.success) {
|
|
750
|
+
await loadProfiles();
|
|
751
|
+
showToast(`Pulled ${data.count} profile(s) from Google Cloud Firestore.`);
|
|
752
|
+
} else {
|
|
753
|
+
showToast(`Pull failed: ${data.error || 'Check network connection'}`, true);
|
|
754
|
+
}
|
|
755
|
+
} catch (err) {
|
|
756
|
+
showToast(`Pull failed: ${err.message}`, true);
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
|
|
691
760
|
function exportActiveProfile() {
|
|
692
761
|
const activeTitle = document.getElementById('active-profile-title').textContent || 'profile.md';
|
|
693
762
|
const content = document.getElementById('profile-editor').value;
|
|
@@ -953,3 +1022,96 @@ async function loadMemory() {
|
|
|
953
1022
|
console.error('Failed to load memory:', err);
|
|
954
1023
|
}
|
|
955
1024
|
}
|
|
1025
|
+
|
|
1026
|
+
// Authentication Helpers
|
|
1027
|
+
let currentAuthUser = null;
|
|
1028
|
+
|
|
1029
|
+
async function checkAuthStatus() {
|
|
1030
|
+
try {
|
|
1031
|
+
const res = await fetch('/api/auth/status');
|
|
1032
|
+
const data = await res.json();
|
|
1033
|
+
const dot = document.getElementById('auth-status-dot');
|
|
1034
|
+
const text = document.getElementById('auth-status-text');
|
|
1035
|
+
|
|
1036
|
+
if (data.isAuthenticated && data.user) {
|
|
1037
|
+
currentAuthUser = data.user;
|
|
1038
|
+
if (dot) dot.classList.add('logged-in');
|
|
1039
|
+
if (text) text.textContent = data.user.email.split('@')[0];
|
|
1040
|
+
} else {
|
|
1041
|
+
currentAuthUser = null;
|
|
1042
|
+
if (dot) dot.classList.remove('logged-in');
|
|
1043
|
+
if (text) text.textContent = 'Login';
|
|
1044
|
+
}
|
|
1045
|
+
} catch (e) {
|
|
1046
|
+
console.error('Failed to check auth status:', e);
|
|
1047
|
+
}
|
|
1048
|
+
}
|
|
1049
|
+
|
|
1050
|
+
function openAuthModal() {
|
|
1051
|
+
const modal = document.getElementById('auth-modal');
|
|
1052
|
+
const formView = document.getElementById('auth-form-view');
|
|
1053
|
+
const loggedView = document.getElementById('auth-logged-view');
|
|
1054
|
+
const emailText = document.getElementById('logged-user-email');
|
|
1055
|
+
const idText = document.getElementById('logged-user-id');
|
|
1056
|
+
|
|
1057
|
+
if (currentAuthUser) {
|
|
1058
|
+
if (formView) formView.style.display = 'none';
|
|
1059
|
+
if (loggedView) loggedView.style.display = 'block';
|
|
1060
|
+
if (emailText) emailText.textContent = currentAuthUser.email;
|
|
1061
|
+
if (idText) idText.textContent = `Cloud Partition: ${currentAuthUser.userId}`;
|
|
1062
|
+
} else {
|
|
1063
|
+
if (formView) formView.style.display = 'block';
|
|
1064
|
+
if (loggedView) loggedView.style.display = 'none';
|
|
1065
|
+
}
|
|
1066
|
+
|
|
1067
|
+
if (modal) modal.style.display = 'flex';
|
|
1068
|
+
}
|
|
1069
|
+
|
|
1070
|
+
function closeAuthModal() {
|
|
1071
|
+
const modal = document.getElementById('auth-modal');
|
|
1072
|
+
if (modal) modal.style.display = 'none';
|
|
1073
|
+
}
|
|
1074
|
+
|
|
1075
|
+
async function submitDesktopLogin() {
|
|
1076
|
+
const emailInput = document.getElementById('modal-email-input');
|
|
1077
|
+
const passInput = document.getElementById('modal-pass-input');
|
|
1078
|
+
const email = (emailInput ? emailInput.value : '').trim();
|
|
1079
|
+
const password = passInput ? passInput.value : '';
|
|
1080
|
+
|
|
1081
|
+
if (!email || !email.includes('@')) {
|
|
1082
|
+
alert('Please enter a valid email address.');
|
|
1083
|
+
return;
|
|
1084
|
+
}
|
|
1085
|
+
|
|
1086
|
+
try {
|
|
1087
|
+
const res = await fetch('/api/auth/login', {
|
|
1088
|
+
method: 'POST',
|
|
1089
|
+
headers: { 'Content-Type': 'application/json' },
|
|
1090
|
+
body: JSON.stringify({ email, password }),
|
|
1091
|
+
});
|
|
1092
|
+
const data = await res.json();
|
|
1093
|
+
if (data.success && data.user) {
|
|
1094
|
+
currentAuthUser = data.user;
|
|
1095
|
+
closeAuthModal();
|
|
1096
|
+
await checkAuthStatus();
|
|
1097
|
+
await loadProfiles();
|
|
1098
|
+
showToast(`Logged in as ${data.user.email}`);
|
|
1099
|
+
} else {
|
|
1100
|
+
alert(data.error || 'Login failed.');
|
|
1101
|
+
}
|
|
1102
|
+
} catch (err) {
|
|
1103
|
+
alert('Login error: ' + err.message);
|
|
1104
|
+
}
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
async function submitDesktopLogout() {
|
|
1108
|
+
try {
|
|
1109
|
+
await fetch('/api/auth/logout', { method: 'POST' });
|
|
1110
|
+
currentAuthUser = null;
|
|
1111
|
+
closeAuthModal();
|
|
1112
|
+
await checkAuthStatus();
|
|
1113
|
+
showToast('Logged out of ANTRI.');
|
|
1114
|
+
} catch (err) {
|
|
1115
|
+
console.error('Logout error:', err);
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
<header class="app-header">
|
|
16
16
|
<div class="brand-zone">
|
|
17
17
|
<span class="logo-mark">ANTRI</span>
|
|
18
|
-
<span class="version-tag">v1.
|
|
18
|
+
<span class="version-tag">v1.47.0</span>
|
|
19
19
|
</div>
|
|
20
20
|
|
|
21
21
|
<!-- Mode Toggle -->
|
|
@@ -63,6 +63,11 @@
|
|
|
63
63
|
<button id="btn-perms-toggle" class="perms-badge" onclick="toggleAlwaysAllow()">
|
|
64
64
|
<span id="perms-text">Ask-First</span>
|
|
65
65
|
</button>
|
|
66
|
+
|
|
67
|
+
<button id="btn-auth-status" class="auth-header-btn" onclick="openAuthModal()">
|
|
68
|
+
<span id="auth-status-dot" class="status-dot"></span>
|
|
69
|
+
<span id="auth-status-text">Login</span>
|
|
70
|
+
</button>
|
|
66
71
|
</div>
|
|
67
72
|
</header>
|
|
68
73
|
|
|
@@ -276,6 +281,8 @@
|
|
|
276
281
|
<input type="text" id="new-profile-name" placeholder="New profile name (e.g. backend_architect)" />
|
|
277
282
|
<button class="action-btn" onclick="createProfile()">+ Create</button>
|
|
278
283
|
<button class="action-btn-secondary" onclick="document.getElementById('profile-import-input').click()">📁 Import .md</button>
|
|
284
|
+
<button class="action-btn-secondary" onclick="pushProfilesToCloud()">☁️ Push</button>
|
|
285
|
+
<button class="action-btn-secondary" onclick="pullProfilesFromCloud()">☁️ Pull</button>
|
|
279
286
|
</div>
|
|
280
287
|
</div>
|
|
281
288
|
|
|
@@ -378,6 +385,36 @@
|
|
|
378
385
|
</main>
|
|
379
386
|
</div>
|
|
380
387
|
|
|
388
|
+
<!-- AUTH MODAL -->
|
|
389
|
+
<div id="auth-modal" class="modal-backdrop" style="display:none;" onclick="if(event.target===this)closeAuthModal()">
|
|
390
|
+
<div class="modal-box">
|
|
391
|
+
<div class="modal-header">
|
|
392
|
+
<h3 id="modal-auth-title">ANTRI Account</h3>
|
|
393
|
+
<button class="modal-close" onclick="closeAuthModal()">✕</button>
|
|
394
|
+
</div>
|
|
395
|
+
<div class="modal-body" id="modal-auth-body">
|
|
396
|
+
<div id="auth-form-view">
|
|
397
|
+
<p style="font-size:13px;color:var(--text-muted);margin-bottom:16px;">Sign in to sync your thinking profiles and memories across CLI, Desktop, and Mobile.</p>
|
|
398
|
+
<div style="margin-bottom:12px;">
|
|
399
|
+
<label style="display:block;font-size:12px;font-weight:600;margin-bottom:6px;">Email Address</label>
|
|
400
|
+
<input type="email" id="modal-email-input" class="modal-input" placeholder="user@gmail.com" />
|
|
401
|
+
</div>
|
|
402
|
+
<div style="margin-bottom:16px;">
|
|
403
|
+
<label style="display:block;font-size:12px;font-weight:600;margin-bottom:6px;">Password</label>
|
|
404
|
+
<input type="password" id="modal-pass-input" class="modal-input" placeholder="••••••••" />
|
|
405
|
+
</div>
|
|
406
|
+
<button class="action-btn" style="width:100%;margin-bottom:8px;" onclick="submitDesktopLogin()">Sign In / Register</button>
|
|
407
|
+
</div>
|
|
408
|
+
<div id="auth-logged-view" style="display:none;text-align:center;padding:12px 0;">
|
|
409
|
+
<div style="font-size:32px;margin-bottom:8px;">👤</div>
|
|
410
|
+
<div id="logged-user-email" style="font-weight:700;font-size:15px;color:var(--primary);margin-bottom:4px;"></div>
|
|
411
|
+
<div id="logged-user-id" style="font-size:12px;color:var(--text-muted);margin-bottom:16px;"></div>
|
|
412
|
+
<button class="action-btn-danger" style="width:100%;" onclick="submitDesktopLogout()">Logout</button>
|
|
413
|
+
</div>
|
|
414
|
+
</div>
|
|
415
|
+
</div>
|
|
416
|
+
</div>
|
|
417
|
+
|
|
381
418
|
<script src="app.js"></script>
|
|
382
419
|
</body>
|
|
383
420
|
</html>
|
|
@@ -1146,3 +1146,176 @@ body.antri-app {
|
|
|
1146
1146
|
transform: translateY(0);
|
|
1147
1147
|
}
|
|
1148
1148
|
|
|
1149
|
+
/* Auth Header Button & Modal */
|
|
1150
|
+
.auth-header-btn {
|
|
1151
|
+
background: var(--bg-surface);
|
|
1152
|
+
border: 1px solid var(--border-color);
|
|
1153
|
+
color: var(--text-primary);
|
|
1154
|
+
padding: 0.35rem 0.75rem;
|
|
1155
|
+
border-radius: var(--radius-xs);
|
|
1156
|
+
font-size: 0.8rem;
|
|
1157
|
+
font-weight: 600;
|
|
1158
|
+
display: inline-flex;
|
|
1159
|
+
align-items: center;
|
|
1160
|
+
gap: 6px;
|
|
1161
|
+
cursor: pointer;
|
|
1162
|
+
transition: all 0.15s ease;
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
.auth-header-btn:hover {
|
|
1166
|
+
background: var(--bg-surface-elevated);
|
|
1167
|
+
border-color: var(--accent-primary);
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
.status-dot {
|
|
1171
|
+
width: 7px;
|
|
1172
|
+
height: 7px;
|
|
1173
|
+
border-radius: 50%;
|
|
1174
|
+
background: #f43f5e;
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
.status-dot.logged-in {
|
|
1178
|
+
background: #10b981;
|
|
1179
|
+
}
|
|
1180
|
+
|
|
1181
|
+
.modal-backdrop {
|
|
1182
|
+
position: fixed;
|
|
1183
|
+
inset: 0;
|
|
1184
|
+
background: rgba(0, 0, 0, 0.6);
|
|
1185
|
+
backdrop-filter: blur(4px);
|
|
1186
|
+
display: flex;
|
|
1187
|
+
align-items: center;
|
|
1188
|
+
justify-content: center;
|
|
1189
|
+
z-index: 9999;
|
|
1190
|
+
}
|
|
1191
|
+
|
|
1192
|
+
.modal-box {
|
|
1193
|
+
background: var(--bg-surface-elevated, #18181b);
|
|
1194
|
+
border: 1px solid var(--border-color, #27272a);
|
|
1195
|
+
border-radius: 12px;
|
|
1196
|
+
width: 100%;
|
|
1197
|
+
max-width: 400px;
|
|
1198
|
+
padding: 24px;
|
|
1199
|
+
box-shadow: 0 10px 30px rgba(0, 0, 0, 0.4);
|
|
1200
|
+
}
|
|
1201
|
+
|
|
1202
|
+
.modal-header {
|
|
1203
|
+
display: flex;
|
|
1204
|
+
justify-content: space-between;
|
|
1205
|
+
align-items: center;
|
|
1206
|
+
margin-bottom: 16px;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
.modal-close {
|
|
1210
|
+
background: transparent;
|
|
1211
|
+
border: none;
|
|
1212
|
+
color: var(--text-tertiary);
|
|
1213
|
+
font-size: 16px;
|
|
1214
|
+
cursor: pointer;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1217
|
+
.modal-close:hover {
|
|
1218
|
+
color: var(--text-primary);
|
|
1219
|
+
}
|
|
1220
|
+
|
|
1221
|
+
.modal-input {
|
|
1222
|
+
width: 100%;
|
|
1223
|
+
padding: 10px 12px;
|
|
1224
|
+
background: var(--bg-surface, #09090b);
|
|
1225
|
+
border: 1px solid var(--border-color, #27272a);
|
|
1226
|
+
border-radius: 6px;
|
|
1227
|
+
color: var(--text-primary, #f4f4f5);
|
|
1228
|
+
font-size: 13px;
|
|
1229
|
+
outline: none;
|
|
1230
|
+
}
|
|
1231
|
+
|
|
1232
|
+
.modal-input:focus {
|
|
1233
|
+
border-color: var(--accent-primary, #6366f1);
|
|
1234
|
+
}
|
|
1235
|
+
|
|
1236
|
+
.action-btn-danger {
|
|
1237
|
+
background: #dc2626;
|
|
1238
|
+
color: #fff;
|
|
1239
|
+
border: none;
|
|
1240
|
+
padding: 8px 16px;
|
|
1241
|
+
border-radius: 6px;
|
|
1242
|
+
font-weight: 600;
|
|
1243
|
+
font-size: 13px;
|
|
1244
|
+
cursor: pointer;
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
.action-btn-danger:hover {
|
|
1248
|
+
background: #b91c1c;
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
/* Tool Permission Prompt Card */
|
|
1252
|
+
.permission-prompt-card {
|
|
1253
|
+
background: var(--bg-surface-elevated, #18181b);
|
|
1254
|
+
border: 1px solid #f59e0b;
|
|
1255
|
+
border-radius: 8px;
|
|
1256
|
+
padding: 12px 14px;
|
|
1257
|
+
margin: 10px 0;
|
|
1258
|
+
box-shadow: 0 4px 12px rgba(245, 158, 11, 0.1);
|
|
1259
|
+
}
|
|
1260
|
+
|
|
1261
|
+
.perm-title {
|
|
1262
|
+
font-size: 12px;
|
|
1263
|
+
font-weight: 700;
|
|
1264
|
+
color: #f59e0b;
|
|
1265
|
+
margin-bottom: 4px;
|
|
1266
|
+
}
|
|
1267
|
+
|
|
1268
|
+
.perm-desc {
|
|
1269
|
+
font-size: 13px;
|
|
1270
|
+
color: var(--text-primary);
|
|
1271
|
+
margin-bottom: 8px;
|
|
1272
|
+
}
|
|
1273
|
+
|
|
1274
|
+
.perm-args {
|
|
1275
|
+
background: var(--bg-surface, #09090b);
|
|
1276
|
+
border: 1px solid var(--border-color);
|
|
1277
|
+
padding: 8px 10px;
|
|
1278
|
+
border-radius: 6px;
|
|
1279
|
+
font-family: var(--font-mono);
|
|
1280
|
+
font-size: 11px;
|
|
1281
|
+
max-height: 120px;
|
|
1282
|
+
overflow-y: auto;
|
|
1283
|
+
margin-bottom: 10px;
|
|
1284
|
+
color: #38bdf8;
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
.perm-actions {
|
|
1288
|
+
display: flex;
|
|
1289
|
+
gap: 8px;
|
|
1290
|
+
}
|
|
1291
|
+
|
|
1292
|
+
.perm-btn {
|
|
1293
|
+
padding: 6px 12px;
|
|
1294
|
+
border-radius: 4px;
|
|
1295
|
+
font-size: 12px;
|
|
1296
|
+
font-weight: 600;
|
|
1297
|
+
cursor: pointer;
|
|
1298
|
+
border: none;
|
|
1299
|
+
transition: opacity 0.15s;
|
|
1300
|
+
}
|
|
1301
|
+
|
|
1302
|
+
.perm-btn:hover {
|
|
1303
|
+
opacity: 0.9;
|
|
1304
|
+
}
|
|
1305
|
+
|
|
1306
|
+
.perm-allow {
|
|
1307
|
+
background: #10b981;
|
|
1308
|
+
color: #fff;
|
|
1309
|
+
}
|
|
1310
|
+
|
|
1311
|
+
.perm-always {
|
|
1312
|
+
background: #6366f1;
|
|
1313
|
+
color: #fff;
|
|
1314
|
+
}
|
|
1315
|
+
|
|
1316
|
+
.perm-deny {
|
|
1317
|
+
background: #ef4444;
|
|
1318
|
+
color: #fff;
|
|
1319
|
+
}
|
|
1320
|
+
|
|
1321
|
+
|
package/dist/desktop/server.d.ts
CHANGED
|
@@ -2,7 +2,10 @@ export declare class DesktopServer {
|
|
|
2
2
|
private server;
|
|
3
3
|
private port;
|
|
4
4
|
private activeAgent;
|
|
5
|
+
private pendingPermissions;
|
|
6
|
+
private currentSseSender;
|
|
5
7
|
constructor();
|
|
8
|
+
private setupPermissionHandler;
|
|
6
9
|
start(): Promise<number>;
|
|
7
10
|
stop(): Promise<void>;
|
|
8
11
|
private handleApi;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/desktop/server.ts"],"names":[],"mappings":"AAqCA,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,WAAW,CAAa;;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/desktop/server.ts"],"names":[],"mappings":"AAqCA,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAA4B;IAC1C,OAAO,CAAC,IAAI,CAAQ;IACpB,OAAO,CAAC,WAAW,CAAa;IAChC,OAAO,CAAC,kBAAkB,CAAiD;IAC3E,OAAO,CAAC,gBAAgB,CAAqD;;IAO7E,OAAO,CAAC,sBAAsB;IA2BjB,KAAK,IAAI,OAAO,CAAC,MAAM,CAAC;IAqExB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;YAUpB,SAAS;WA2aH,aAAa,IAAI,OAAO,CAAC,IAAI,CAAC;CAyBnD"}
|
package/dist/desktop/server.js
CHANGED
|
@@ -12,7 +12,7 @@ import { profileManager } from '../profiles/profileManager.js';
|
|
|
12
12
|
import { memoryManager } from '../memory/manager.js';
|
|
13
13
|
import { skillManager } from '../skills/skillManager.js';
|
|
14
14
|
import { SkillSynthesizer } from '../core/skillSynthesizer.js';
|
|
15
|
-
import { getAllActiveTools } from '../core/tools.js';
|
|
15
|
+
import { getAllActiveTools, ToolExecutor } from '../core/tools.js';
|
|
16
16
|
import { getAvailableModels } from '../providers/models.js';
|
|
17
17
|
import { PROMPT_TOOLKIT_COMMANDS } from '../cli/promptToolkit.js';
|
|
18
18
|
import { FilePickerService } from '../cli/dialogs/filePicker.js';
|
|
@@ -36,8 +36,37 @@ export class DesktopServer {
|
|
|
36
36
|
server = null;
|
|
37
37
|
port = 3456;
|
|
38
38
|
activeAgent;
|
|
39
|
+
pendingPermissions = new Map();
|
|
40
|
+
currentSseSender = null;
|
|
39
41
|
constructor() {
|
|
40
42
|
this.activeAgent = new AntriAgent(configManager.get());
|
|
43
|
+
this.setupPermissionHandler();
|
|
44
|
+
}
|
|
45
|
+
setupPermissionHandler() {
|
|
46
|
+
this.activeAgent.getToolExecutor().setPermissionHandler(async (name, args) => {
|
|
47
|
+
const cfg = configManager.get();
|
|
48
|
+
if (cfg.alwaysAllow)
|
|
49
|
+
return true;
|
|
50
|
+
if (!ToolExecutor.isSensitive(name))
|
|
51
|
+
return true;
|
|
52
|
+
const reqId = `perm_${Date.now()}_${Math.random().toString(36).slice(2, 7)}`;
|
|
53
|
+
if (this.currentSseSender) {
|
|
54
|
+
this.currentSseSender('permission_request', {
|
|
55
|
+
requestId: reqId,
|
|
56
|
+
name,
|
|
57
|
+
args,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
return new Promise((resolve) => {
|
|
61
|
+
this.pendingPermissions.set(reqId, resolve);
|
|
62
|
+
setTimeout(() => {
|
|
63
|
+
if (this.pendingPermissions.has(reqId)) {
|
|
64
|
+
this.pendingPermissions.delete(reqId);
|
|
65
|
+
resolve(false);
|
|
66
|
+
}
|
|
67
|
+
}, 90000);
|
|
68
|
+
});
|
|
69
|
+
});
|
|
41
70
|
}
|
|
42
71
|
async start() {
|
|
43
72
|
const publicDir = getPublicDir();
|
|
@@ -213,6 +242,22 @@ export class DesktopServer {
|
|
|
213
242
|
}));
|
|
214
243
|
return;
|
|
215
244
|
}
|
|
245
|
+
// POST /api/permission/response (Desktop tool confirmation response)
|
|
246
|
+
if (pathname === '/api/permission/response' && req.method === 'POST') {
|
|
247
|
+
const { requestId, allowed, alwaysAllow } = payload;
|
|
248
|
+
if (alwaysAllow) {
|
|
249
|
+
configManager.setAlwaysAllow(true);
|
|
250
|
+
this.activeAgent.updateConfig(configManager.get());
|
|
251
|
+
}
|
|
252
|
+
const resolver = this.pendingPermissions.get(requestId);
|
|
253
|
+
if (resolver) {
|
|
254
|
+
this.pendingPermissions.delete(requestId);
|
|
255
|
+
resolver(!!allowed);
|
|
256
|
+
}
|
|
257
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
258
|
+
res.end(JSON.stringify({ success: true }));
|
|
259
|
+
return;
|
|
260
|
+
}
|
|
216
261
|
// POST /api/chat (Real-Time SSE Token Streaming)
|
|
217
262
|
if (pathname === '/api/chat' && req.method === 'POST') {
|
|
218
263
|
res.writeHead(200, {
|
|
@@ -223,6 +268,7 @@ export class DesktopServer {
|
|
|
223
268
|
const sendEvent = (event, data) => {
|
|
224
269
|
res.write(`event: ${event}\ndata: ${JSON.stringify(data)}\n\n`);
|
|
225
270
|
};
|
|
271
|
+
this.currentSseSender = sendEvent;
|
|
226
272
|
const userPrompt = payload.prompt || '';
|
|
227
273
|
this.activeAgent.updateConfig(configManager.get());
|
|
228
274
|
try {
|
|
@@ -241,6 +287,9 @@ export class DesktopServer {
|
|
|
241
287
|
sendEvent('error', { message: err.message });
|
|
242
288
|
res.end();
|
|
243
289
|
}
|
|
290
|
+
finally {
|
|
291
|
+
this.currentSseSender = null;
|
|
292
|
+
}
|
|
244
293
|
return;
|
|
245
294
|
}
|
|
246
295
|
// POST /api/debate (SSE Streaming)
|
|
@@ -337,6 +386,14 @@ export class DesktopServer {
|
|
|
337
386
|
res.end(JSON.stringify({ success: true }));
|
|
338
387
|
return;
|
|
339
388
|
}
|
|
389
|
+
// GET/POST /api/auth/status
|
|
390
|
+
if (pathname === '/api/auth/status') {
|
|
391
|
+
const { AuthManager } = await import('../cloud/auth.js');
|
|
392
|
+
const user = AuthManager.getCurrentUser();
|
|
393
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
394
|
+
res.end(JSON.stringify({ isAuthenticated: !!user, user }));
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
340
397
|
// POST /api/auth/login
|
|
341
398
|
if (pathname === '/api/auth/login' && req.method === 'POST') {
|
|
342
399
|
const { AuthManager } = await import('../cloud/auth.js');
|
|
@@ -391,6 +448,22 @@ export class DesktopServer {
|
|
|
391
448
|
res.end(JSON.stringify({ success: ok }));
|
|
392
449
|
return;
|
|
393
450
|
}
|
|
451
|
+
// POST /api/profile/push
|
|
452
|
+
if (pathname === '/api/profile/push' && req.method === 'POST') {
|
|
453
|
+
const { FirestoreSyncManager } = await import('../cloud/firestore.js');
|
|
454
|
+
const result = await FirestoreSyncManager.pushToFirestore();
|
|
455
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
456
|
+
res.end(JSON.stringify(result));
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
// POST /api/profile/pull
|
|
460
|
+
if (pathname === '/api/profile/pull' && req.method === 'POST') {
|
|
461
|
+
const { FirestoreSyncManager } = await import('../cloud/firestore.js');
|
|
462
|
+
const result = await FirestoreSyncManager.pullFromFirestore();
|
|
463
|
+
res.writeHead(200, { 'Content-Type': 'application/json' });
|
|
464
|
+
res.end(JSON.stringify(result));
|
|
465
|
+
return;
|
|
466
|
+
}
|
|
394
467
|
// POST /api/skill/create
|
|
395
468
|
if (pathname === '/api/skill/create' && req.method === 'POST') {
|
|
396
469
|
const skill = skillManager.createSkill(payload.name, payload.description || '', payload.category || 'Custom', payload.triggers || [], payload.content);
|