@pingagent/sdk 0.1.9 → 0.1.10
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/bin/pingagent.js +830 -0
- package/dist/chunk-2Y6YRKTO.js +3100 -0
- package/dist/chunk-RMIRCSQ6.js +3042 -0
- package/dist/index.d.ts +37 -1
- package/dist/index.js +27 -3
- package/dist/web-server.js +175 -3
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -947,4 +947,40 @@ declare class WsSubscription {
|
|
|
947
947
|
private syncConnections;
|
|
948
948
|
}
|
|
949
949
|
|
|
950
|
-
|
|
950
|
+
declare function getActiveSessionFilePath(): string;
|
|
951
|
+
declare function getSessionMapFilePath(): string;
|
|
952
|
+
declare function getSessionBindingAlertsFilePath(): string;
|
|
953
|
+
declare function readCurrentActiveSessionKey(filePath?: string): string | null;
|
|
954
|
+
interface SessionBindingEntry {
|
|
955
|
+
conversation_id: string;
|
|
956
|
+
session_key: string;
|
|
957
|
+
}
|
|
958
|
+
interface SessionBindingAlert {
|
|
959
|
+
conversation_id: string;
|
|
960
|
+
session_key: string;
|
|
961
|
+
status: 'missing_session';
|
|
962
|
+
message: string;
|
|
963
|
+
detected_at: string;
|
|
964
|
+
}
|
|
965
|
+
declare function readSessionBindings(filePath?: string): SessionBindingEntry[];
|
|
966
|
+
declare function writeSessionBindings(entries: SessionBindingEntry[], filePath?: string): string;
|
|
967
|
+
declare function setSessionBinding(conversationId: string, sessionKey: string, filePath?: string): {
|
|
968
|
+
path: string;
|
|
969
|
+
binding: SessionBindingEntry;
|
|
970
|
+
};
|
|
971
|
+
declare function removeSessionBinding(conversationId: string, filePath?: string): {
|
|
972
|
+
path: string;
|
|
973
|
+
removed: boolean;
|
|
974
|
+
};
|
|
975
|
+
declare function readSessionBindingAlerts(filePath?: string): SessionBindingAlert[];
|
|
976
|
+
declare function writeSessionBindingAlerts(entries: SessionBindingAlert[], filePath?: string): string;
|
|
977
|
+
declare function upsertSessionBindingAlert(alert: SessionBindingAlert, filePath?: string): {
|
|
978
|
+
path: string;
|
|
979
|
+
alert: SessionBindingAlert;
|
|
980
|
+
};
|
|
981
|
+
declare function clearSessionBindingAlert(conversationId: string, filePath?: string): {
|
|
982
|
+
path: string;
|
|
983
|
+
removed: boolean;
|
|
984
|
+
};
|
|
985
|
+
|
|
986
|
+
export { A2AAdapter, type A2AAdapterOptions, type A2ATaskResult, type AgentEncryptionCard, type AgentProfile, type ClientOptions, type Contact, ContactManager, type ContactPolicyAction, type ContactPolicyDecision, type ConversationEntry, type ConversationListResponse, type DirectoryBrowseResponse, type DirectorySelfResponse, type EncryptedPayloadWrapper, type EncryptionIdentityFields, type EncryptionPrivateKeyJwk, type EncryptionPublicKeyJwk, type FeedByDidResponse, type FeedPost, type FeedPublicResponse, type FetchResponse, HistoryManager, HttpTransport, LocalStore, PingAgentClient, type RecommendationSummary, type ReplyTarget, type RuntimeMode, type SendResponse, type SessionBindingAlert, type SessionBindingEntry, SessionManager, type SessionMessageInput, type SessionState, type StoredMessage, type StoredTrustRecommendation, type SubscriptionResponse, type SubscriptionUsage, type SyncTrustRecommendationsInput, type TaskPolicyAction, type TaskPolicyDecision, type TaskResult, type TaskThread, TaskThreadManager, type TaskThreadStatus, type TaskThreadUpsert, type TransportOptions, type TrustPolicyAuditEvent, type TrustPolicyAuditEventType, type TrustPolicyAuditInput, TrustPolicyAuditManager, type TrustPolicyAuditSummary, type TrustPolicyContext, type TrustPolicyDoc, type TrustPolicyLearningSummary, type TrustPolicyRecommendation, TrustRecommendationManager, type TrustRecommendationStatus, type TrustState, WsSubscription, type WsSubscriptionOptions, buildSessionKey, buildTrustPolicyRecommendations, clearSessionBindingAlert, decideContactPolicy, decideTaskPolicy, decryptPayloadForIdentity, defaultTrustPolicyDoc, encryptPayloadForRecipients, ensureIdentityEncryptionKeys, ensureTokenValid, generateIdentity, getActiveSessionFilePath, getIdentityPath, getProfile, getRootDir, getSessionBindingAlertsFilePath, getSessionMapFilePath, getStorePath, identityExists, isEncryptedPayload, loadIdentity, matchesTrustPolicyRule, normalizeTrustPolicyDoc, previewFromPayload, readCurrentActiveSessionKey, readSessionBindingAlerts, readSessionBindings, removeSessionBinding, saveIdentity, setSessionBinding, shouldEncryptConversationPayload, summarizeTrustPolicyAudit, updateStoredToken, upsertSessionBindingAlert, upsertTrustPolicyRecommendation, writeSessionBindingAlerts, writeSessionBindings };
|
package/dist/index.js
CHANGED
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
WsSubscription,
|
|
13
13
|
buildSessionKey,
|
|
14
14
|
buildTrustPolicyRecommendations,
|
|
15
|
+
clearSessionBindingAlert,
|
|
15
16
|
decideContactPolicy,
|
|
16
17
|
decideTaskPolicy,
|
|
17
18
|
decryptPayloadForIdentity,
|
|
@@ -20,9 +21,12 @@ import {
|
|
|
20
21
|
ensureIdentityEncryptionKeys,
|
|
21
22
|
ensureTokenValid,
|
|
22
23
|
generateIdentity,
|
|
24
|
+
getActiveSessionFilePath,
|
|
23
25
|
getIdentityPath,
|
|
24
26
|
getProfile,
|
|
25
27
|
getRootDir,
|
|
28
|
+
getSessionBindingAlertsFilePath,
|
|
29
|
+
getSessionMapFilePath,
|
|
26
30
|
getStorePath,
|
|
27
31
|
identityExists,
|
|
28
32
|
isEncryptedPayload,
|
|
@@ -30,12 +34,20 @@ import {
|
|
|
30
34
|
matchesTrustPolicyRule,
|
|
31
35
|
normalizeTrustPolicyDoc,
|
|
32
36
|
previewFromPayload,
|
|
37
|
+
readCurrentActiveSessionKey,
|
|
38
|
+
readSessionBindingAlerts,
|
|
39
|
+
readSessionBindings,
|
|
40
|
+
removeSessionBinding,
|
|
33
41
|
saveIdentity,
|
|
42
|
+
setSessionBinding,
|
|
34
43
|
shouldEncryptConversationPayload,
|
|
35
44
|
summarizeTrustPolicyAudit,
|
|
36
45
|
updateStoredToken,
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
upsertSessionBindingAlert,
|
|
47
|
+
upsertTrustPolicyRecommendation,
|
|
48
|
+
writeSessionBindingAlerts,
|
|
49
|
+
writeSessionBindings
|
|
50
|
+
} from "./chunk-2Y6YRKTO.js";
|
|
39
51
|
export {
|
|
40
52
|
A2AAdapter,
|
|
41
53
|
ContactManager,
|
|
@@ -50,6 +62,7 @@ export {
|
|
|
50
62
|
WsSubscription,
|
|
51
63
|
buildSessionKey,
|
|
52
64
|
buildTrustPolicyRecommendations,
|
|
65
|
+
clearSessionBindingAlert,
|
|
53
66
|
decideContactPolicy,
|
|
54
67
|
decideTaskPolicy,
|
|
55
68
|
decryptPayloadForIdentity,
|
|
@@ -58,9 +71,12 @@ export {
|
|
|
58
71
|
ensureIdentityEncryptionKeys,
|
|
59
72
|
ensureTokenValid,
|
|
60
73
|
generateIdentity,
|
|
74
|
+
getActiveSessionFilePath,
|
|
61
75
|
getIdentityPath,
|
|
62
76
|
getProfile,
|
|
63
77
|
getRootDir,
|
|
78
|
+
getSessionBindingAlertsFilePath,
|
|
79
|
+
getSessionMapFilePath,
|
|
64
80
|
getStorePath,
|
|
65
81
|
identityExists,
|
|
66
82
|
isEncryptedPayload,
|
|
@@ -68,9 +84,17 @@ export {
|
|
|
68
84
|
matchesTrustPolicyRule,
|
|
69
85
|
normalizeTrustPolicyDoc,
|
|
70
86
|
previewFromPayload,
|
|
87
|
+
readCurrentActiveSessionKey,
|
|
88
|
+
readSessionBindingAlerts,
|
|
89
|
+
readSessionBindings,
|
|
90
|
+
removeSessionBinding,
|
|
71
91
|
saveIdentity,
|
|
92
|
+
setSessionBinding,
|
|
72
93
|
shouldEncryptConversationPayload,
|
|
73
94
|
summarizeTrustPolicyAudit,
|
|
74
95
|
updateStoredToken,
|
|
75
|
-
|
|
96
|
+
upsertSessionBindingAlert,
|
|
97
|
+
upsertTrustPolicyRecommendation,
|
|
98
|
+
writeSessionBindingAlerts,
|
|
99
|
+
writeSessionBindings
|
|
76
100
|
};
|
package/dist/web-server.js
CHANGED
|
@@ -8,12 +8,20 @@ import {
|
|
|
8
8
|
decideTaskPolicy,
|
|
9
9
|
defaultTrustPolicyDoc,
|
|
10
10
|
ensureTokenValid,
|
|
11
|
+
getActiveSessionFilePath,
|
|
12
|
+
getSessionBindingAlertsFilePath,
|
|
13
|
+
getSessionMapFilePath,
|
|
11
14
|
loadIdentity,
|
|
12
15
|
normalizeTrustPolicyDoc,
|
|
16
|
+
readCurrentActiveSessionKey,
|
|
17
|
+
readSessionBindingAlerts,
|
|
18
|
+
readSessionBindings,
|
|
19
|
+
removeSessionBinding,
|
|
20
|
+
setSessionBinding,
|
|
13
21
|
summarizeTrustPolicyAudit,
|
|
14
22
|
updateStoredToken,
|
|
15
23
|
upsertTrustPolicyRecommendation
|
|
16
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-2Y6YRKTO.js";
|
|
17
25
|
|
|
18
26
|
// src/web-server.ts
|
|
19
27
|
import * as fs from "fs";
|
|
@@ -81,10 +89,12 @@ function getHostPanelHtml() {
|
|
|
81
89
|
.session-row .top, .task-row .top, .recommendation-row .top { display: flex; justify-content: space-between; gap: 12px; align-items: center; }
|
|
82
90
|
.label { font-size: 11px; text-transform: uppercase; letter-spacing: 0.06em; color: #94a3b8; }
|
|
83
91
|
.badge { display: inline-flex; align-items: center; padding: 2px 8px; border-radius: 999px; font-size: 11px; border: 1px solid #334155; }
|
|
92
|
+
button.badge { cursor: pointer; font: inherit; }
|
|
84
93
|
.badge.trusted { background: rgba(34, 197, 94, 0.12); color: #86efac; border-color: rgba(34, 197, 94, 0.35); }
|
|
85
94
|
.badge.pending { background: rgba(250, 204, 21, 0.12); color: #fde68a; border-color: rgba(250, 204, 21, 0.35); }
|
|
86
95
|
.badge.blocked, .badge.revoked { background: rgba(248, 113, 113, 0.12); color: #fca5a5; border-color: rgba(248, 113, 113, 0.35); }
|
|
87
96
|
.badge.stranger { background: rgba(148, 163, 184, 0.12); color: #cbd5e1; border-color: rgba(148, 163, 184, 0.35); }
|
|
97
|
+
.badge.alert { background: rgba(248, 113, 113, 0.14); color: #fecaca; border-color: rgba(248, 113, 113, 0.45); }
|
|
88
98
|
.policy-grid { grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); align-items: start; }
|
|
89
99
|
.two-col { display: grid; grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); gap: 16px; }
|
|
90
100
|
.panel { display: none; }
|
|
@@ -361,11 +371,17 @@ function getHostPanelHtml() {
|
|
|
361
371
|
if (!state.selectedSessionKey) state.selectedSessionKey = sessions[0].session_key;
|
|
362
372
|
document.getElementById('sessionList').innerHTML = sessions.map(function (session) {
|
|
363
373
|
const active = session.session_key === state.selectedSessionKey ? ' active' : '';
|
|
364
|
-
const
|
|
374
|
+
const badges = [
|
|
375
|
+
'<span class="badge ' + esc(session.trust_state) + '">' + esc(session.trust_state) + '</span>',
|
|
376
|
+
session.binding_alert
|
|
377
|
+
? '<button type="button" class="badge alert rebind-badge-btn" data-session="' + esc(session.session_key) + '" data-conversation="' + esc(session.conversation_id || '') + '" data-bound-session="' + esc(session.mapped_work_session || '') + '" data-remote-did="' + esc(session.remote_did || '') + '" title="' + esc(session.binding_alert.message || 'Rebind this conversation to the current chat session') + '">Needs rebind</button>'
|
|
378
|
+
: '',
|
|
379
|
+
].filter(Boolean).join('');
|
|
365
380
|
return '<div class="session-row' + active + '" data-session="' + esc(session.session_key) + '">' +
|
|
366
|
-
'<div class="top"><strong>' + esc(session.remote_did || session.conversation_id || 'unknown') + '</strong>' +
|
|
381
|
+
'<div class="top"><strong>' + esc(session.remote_did || session.conversation_id || 'unknown') + '</strong><div style="display:flex;gap:6px;flex-wrap:wrap;justify-content:flex-end">' + badges + '</div></div>' +
|
|
367
382
|
'<div class="muted small" style="margin-top:6px">conversation=' + esc(session.conversation_id || '(none)') + '</div>' +
|
|
368
383
|
'<div class="muted small">unread=' + esc(session.unread_count) + ' \xB7 last=' + esc(fmtTs(session.last_remote_activity_at || session.updated_at)) + '</div>' +
|
|
384
|
+
'<div class="muted small">work_session=' + esc(session.mapped_work_session || '(unbound)') + (session.is_active_work_session ? ' \xB7 active_chat=true' : '') + '</div>' +
|
|
369
385
|
'<div class="muted small" style="margin-top:6px">' + esc(session.last_message_preview || '(no preview)') + '</div>' +
|
|
370
386
|
'</div>';
|
|
371
387
|
}).join('');
|
|
@@ -376,6 +392,20 @@ function getHostPanelHtml() {
|
|
|
376
392
|
loadSession(state.selectedSessionKey);
|
|
377
393
|
});
|
|
378
394
|
});
|
|
395
|
+
document.getElementById('sessionList').querySelectorAll('.rebind-badge-btn').forEach(function (btn) {
|
|
396
|
+
btn.addEventListener('click', async function (event) {
|
|
397
|
+
event.stopPropagation();
|
|
398
|
+
const sessionKey = btn.getAttribute('data-session');
|
|
399
|
+
const conversationId = btn.getAttribute('data-conversation');
|
|
400
|
+
const previousBinding = btn.getAttribute('data-bound-session');
|
|
401
|
+
const remoteDid = btn.getAttribute('data-remote-did');
|
|
402
|
+
if (!sessionKey || !conversationId) return;
|
|
403
|
+
state.selectedSessionKey = sessionKey;
|
|
404
|
+
renderOverview();
|
|
405
|
+
await loadSession(sessionKey);
|
|
406
|
+
await promptBindCurrentChat(conversationId, previousBinding, remoteDid);
|
|
407
|
+
});
|
|
408
|
+
});
|
|
379
409
|
}
|
|
380
410
|
|
|
381
411
|
const tasks = Array.isArray(overview.tasks) ? overview.tasks : [];
|
|
@@ -419,6 +449,9 @@ function getHostPanelHtml() {
|
|
|
419
449
|
const messages = Array.isArray(detail.messages) ? detail.messages : [];
|
|
420
450
|
const auditEvents = Array.isArray(detail.auditEvents) ? detail.auditEvents : [];
|
|
421
451
|
const recommendations = Array.isArray(detail.recommendations) ? detail.recommendations : [];
|
|
452
|
+
const binding = detail.binding || null;
|
|
453
|
+
const bindingAlert = detail.bindingAlert || null;
|
|
454
|
+
const activeWorkSession = detail.activeWorkSession || null;
|
|
422
455
|
|
|
423
456
|
el.innerHTML = '' +
|
|
424
457
|
'<div class="two-col">' +
|
|
@@ -429,6 +462,15 @@ function getHostPanelHtml() {
|
|
|
429
462
|
'<div class="muted small">conversation=' + esc(session.conversation_id || '(none)') + '</div>' +
|
|
430
463
|
'<div class="muted small">trust=' + esc(session.trust_state) + ' \xB7 unread=' + esc(session.unread_count) + '</div>' +
|
|
431
464
|
'<div class="muted small">last activity=' + esc(fmtTs(session.last_remote_activity_at || session.updated_at)) + '</div>' +
|
|
465
|
+
'<div class="muted small" style="margin-top:8px">active_chat_session=' + esc(activeWorkSession || '(none)') + '</div>' +
|
|
466
|
+
'<div class="muted small">binding=' + esc(binding ? binding.session_key : '(unbound)') + '</div>' +
|
|
467
|
+
(bindingAlert
|
|
468
|
+
? '<div style="margin-top:10px;padding:10px 12px;border:1px solid #ef4444;border-radius:10px;background:rgba(127,29,29,0.25);color:#fecaca"><strong>Needs rebind</strong><div class="small" style="margin-top:6px">' + esc(bindingAlert.message || 'Bound work session is missing. Rebind this PingAgent conversation to the current chat session.') + '</div></div>'
|
|
469
|
+
: '') +
|
|
470
|
+
'<div class="row-actions">' +
|
|
471
|
+
'<button class="action-btn bind-current-btn" data-conversation="' + esc(session.conversation_id || '') + '">Bind Current Chat</button>' +
|
|
472
|
+
'<button class="danger-btn clear-binding-btn" data-conversation="' + esc(session.conversation_id || '') + '">Clear Binding</button>' +
|
|
473
|
+
'</div>' +
|
|
432
474
|
'</div>' +
|
|
433
475
|
'<div>' +
|
|
434
476
|
'<div class="label">Policy Decisions</div>' +
|
|
@@ -473,6 +515,54 @@ function getHostPanelHtml() {
|
|
|
473
515
|
}).join('') : '<div class="empty">No audit events for this session.</div>') +
|
|
474
516
|
'</div></div>' +
|
|
475
517
|
'</div>';
|
|
518
|
+
|
|
519
|
+
el.querySelectorAll('.bind-current-btn').forEach(function (btn) {
|
|
520
|
+
btn.addEventListener('click', async function () {
|
|
521
|
+
const conversationId = btn.getAttribute('data-conversation');
|
|
522
|
+
if (!conversationId) return;
|
|
523
|
+
await promptBindCurrentChat(conversationId);
|
|
524
|
+
});
|
|
525
|
+
});
|
|
526
|
+
el.querySelectorAll('.clear-binding-btn').forEach(function (btn) {
|
|
527
|
+
btn.addEventListener('click', async function () {
|
|
528
|
+
await api('/api/runtime/session-bindings/clear', {
|
|
529
|
+
method: 'POST',
|
|
530
|
+
headers: { 'Content-Type': 'application/json' },
|
|
531
|
+
body: JSON.stringify({ conversation_id: btn.getAttribute('data-conversation') }),
|
|
532
|
+
});
|
|
533
|
+
await refreshAll();
|
|
534
|
+
setTab('runtime');
|
|
535
|
+
});
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
async function promptBindCurrentChat(conversationId, previousBinding, remoteDid) {
|
|
540
|
+
const current = state.session && state.session.activeWorkSession
|
|
541
|
+
? state.session.activeWorkSession
|
|
542
|
+
: (state.overview && state.overview.activeWorkSession ? state.overview.activeWorkSession : null);
|
|
543
|
+
const previous = previousBinding || (state.session && state.session.binding ? state.session.binding.session_key : null) || '(unbound)';
|
|
544
|
+
const targetRemoteDid = remoteDid || (state.session && state.session.session ? state.session.session.remote_did : null) || '(unknown)';
|
|
545
|
+
const confirmed = window.confirm(
|
|
546
|
+
'Rebind this PingAgent conversation to the current chat session?' +
|
|
547
|
+
'
|
|
548
|
+
|
|
549
|
+
Conversation: ' + conversationId +
|
|
550
|
+
'
|
|
551
|
+
Remote DID: ' + targetRemoteDid +
|
|
552
|
+
'
|
|
553
|
+
|
|
554
|
+
Current chat: ' + (current || '(none)') +
|
|
555
|
+
'
|
|
556
|
+
Previous binding: ' + previous
|
|
557
|
+
);
|
|
558
|
+
if (!confirmed) return;
|
|
559
|
+
await api('/api/runtime/session-bindings/bind-current', {
|
|
560
|
+
method: 'POST',
|
|
561
|
+
headers: { 'Content-Type': 'application/json' },
|
|
562
|
+
body: JSON.stringify({ conversation_id: conversationId }),
|
|
563
|
+
});
|
|
564
|
+
await refreshAll();
|
|
565
|
+
setTab('runtime');
|
|
476
566
|
}
|
|
477
567
|
|
|
478
568
|
function renderPolicy() {
|
|
@@ -990,6 +1080,11 @@ async function buildRuntimeOverviewPayload(ctx) {
|
|
|
990
1080
|
limit: 12
|
|
991
1081
|
});
|
|
992
1082
|
const unreadTotal = sessions.reduce((sum, session) => sum + session.unread_count, 0);
|
|
1083
|
+
const sessionBindings = readSessionBindings();
|
|
1084
|
+
const sessionBindingAlerts = readSessionBindingAlerts();
|
|
1085
|
+
const activeWorkSession = readCurrentActiveSessionKey();
|
|
1086
|
+
const bindingByConversation = new Map(sessionBindings.map((row) => [row.conversation_id, row.session_key]));
|
|
1087
|
+
const bindingAlertByConversation = new Map(sessionBindingAlerts.map((row) => [row.conversation_id, row]));
|
|
993
1088
|
const trustCounts = sessions.reduce((acc, session) => {
|
|
994
1089
|
acc[session.trust_state] = (acc[session.trust_state] ?? 0) + 1;
|
|
995
1090
|
return acc;
|
|
@@ -999,6 +1094,12 @@ async function buildRuntimeOverviewPayload(ctx) {
|
|
|
999
1094
|
serverUrl: ctx.serverUrl,
|
|
1000
1095
|
runtimeMode,
|
|
1001
1096
|
trustPolicyPath: getTrustPolicyPath(ctx.identityPath),
|
|
1097
|
+
activeWorkSessionFile: getActiveSessionFilePath(),
|
|
1098
|
+
activeWorkSession,
|
|
1099
|
+
sessionMapPath: getSessionMapFilePath(),
|
|
1100
|
+
sessionBindingAlertsPath: getSessionBindingAlertsFilePath(),
|
|
1101
|
+
sessionBindings,
|
|
1102
|
+
sessionBindingAlerts,
|
|
1002
1103
|
subscription: subscription ? {
|
|
1003
1104
|
tier: subscription.tier,
|
|
1004
1105
|
summary: describeHostedTier(subscription.tier),
|
|
@@ -1021,6 +1122,9 @@ async function buildRuntimeOverviewPayload(ctx) {
|
|
|
1021
1122
|
recommendationSummary: recommendationState.summary,
|
|
1022
1123
|
sessions: sessions.map((session) => ({
|
|
1023
1124
|
...session,
|
|
1125
|
+
mapped_work_session: session.conversation_id ? bindingByConversation.get(session.conversation_id) ?? null : null,
|
|
1126
|
+
binding_alert: session.conversation_id ? bindingAlertByConversation.get(session.conversation_id) ?? null : null,
|
|
1127
|
+
is_active_work_session: session.session_key === activeWorkSession,
|
|
1024
1128
|
latest_messages: session.conversation_id ? historyManager.listRecent(session.conversation_id, 3) : []
|
|
1025
1129
|
})),
|
|
1026
1130
|
tasks: refreshedTasks,
|
|
@@ -1054,6 +1158,11 @@ async function buildSessionOverviewPayload(ctx, sessionKey) {
|
|
|
1054
1158
|
auditStore.close();
|
|
1055
1159
|
}
|
|
1056
1160
|
const policy = readTrustPolicyDoc(ctx.identityPath);
|
|
1161
|
+
const bindings = readSessionBindings();
|
|
1162
|
+
const bindingAlerts = readSessionBindingAlerts();
|
|
1163
|
+
const binding = session.conversation_id ? bindings.find((row) => row.conversation_id === session.conversation_id) ?? null : null;
|
|
1164
|
+
const bindingAlert = session.conversation_id ? bindingAlerts.find((row) => row.conversation_id === session.conversation_id) ?? null : null;
|
|
1165
|
+
const activeWorkSession = readCurrentActiveSessionKey();
|
|
1057
1166
|
const recommendationState = syncTrustRecommendations(ctx.storePath, {
|
|
1058
1167
|
policyDoc: policy,
|
|
1059
1168
|
sessions: sessionManager.listRecentSessions(50),
|
|
@@ -1064,6 +1173,12 @@ async function buildSessionOverviewPayload(ctx, sessionKey) {
|
|
|
1064
1173
|
});
|
|
1065
1174
|
return {
|
|
1066
1175
|
session,
|
|
1176
|
+
binding,
|
|
1177
|
+
bindingAlert,
|
|
1178
|
+
activeWorkSession,
|
|
1179
|
+
activeWorkSessionFile: getActiveSessionFilePath(),
|
|
1180
|
+
sessionMapPath: getSessionMapFilePath(),
|
|
1181
|
+
sessionBindingAlertsPath: getSessionBindingAlertsFilePath(),
|
|
1067
1182
|
policyExplain: buildPolicyDecisionShape(ctx.identityPath, session.remote_did, { runtimeMode: getRuntimeMode() }),
|
|
1068
1183
|
tasks,
|
|
1069
1184
|
messages,
|
|
@@ -1089,6 +1204,63 @@ async function handleApi(pathname, req, ctx) {
|
|
|
1089
1204
|
const sessionKey = url.searchParams.get("session_key");
|
|
1090
1205
|
return buildSessionOverviewPayload(ctx, sessionKey);
|
|
1091
1206
|
}
|
|
1207
|
+
if (parts[1] === "session-bindings") {
|
|
1208
|
+
if ((!parts[2] || parts[2] === "list") && req.method === "GET") {
|
|
1209
|
+
const url = new URL(req.url || "", "http://x");
|
|
1210
|
+
const conversationId = url.searchParams.get("conversation_id");
|
|
1211
|
+
const rows = conversationId ? readSessionBindings().filter((row) => row.conversation_id === conversationId) : readSessionBindings();
|
|
1212
|
+
return {
|
|
1213
|
+
activeWorkSessionFile: getActiveSessionFilePath(),
|
|
1214
|
+
activeWorkSession: readCurrentActiveSessionKey(),
|
|
1215
|
+
sessionMapPath: getSessionMapFilePath(),
|
|
1216
|
+
sessionBindingAlertsPath: getSessionBindingAlertsFilePath(),
|
|
1217
|
+
alerts: conversationId ? readSessionBindingAlerts().filter((row) => row.conversation_id === conversationId) : readSessionBindingAlerts(),
|
|
1218
|
+
bindings: rows
|
|
1219
|
+
};
|
|
1220
|
+
}
|
|
1221
|
+
if (parts[2] === "bind-current" && req.method === "POST") {
|
|
1222
|
+
const body = await readBody(req);
|
|
1223
|
+
const conversationId = String(body?.conversation_id ?? "").trim();
|
|
1224
|
+
if (!conversationId) throw new Error("conversation_id is required");
|
|
1225
|
+
const current = readCurrentActiveSessionKey();
|
|
1226
|
+
if (!current) {
|
|
1227
|
+
throw new Error(`No active OpenClaw chat session found in ${getActiveSessionFilePath()}`);
|
|
1228
|
+
}
|
|
1229
|
+
const result = setSessionBinding(conversationId, current);
|
|
1230
|
+
return {
|
|
1231
|
+
ok: true,
|
|
1232
|
+
activeWorkSessionFile: getActiveSessionFilePath(),
|
|
1233
|
+
activeWorkSession: current,
|
|
1234
|
+
sessionMapPath: result.path,
|
|
1235
|
+
binding: result.binding
|
|
1236
|
+
};
|
|
1237
|
+
}
|
|
1238
|
+
if (parts[2] === "set" && req.method === "POST") {
|
|
1239
|
+
const body = await readBody(req);
|
|
1240
|
+
const conversationId = String(body?.conversation_id ?? "").trim();
|
|
1241
|
+
const sessionKey = String(body?.session_key ?? "").trim();
|
|
1242
|
+
if (!conversationId || !sessionKey) throw new Error("conversation_id and session_key are required");
|
|
1243
|
+
const result = setSessionBinding(conversationId, sessionKey);
|
|
1244
|
+
return {
|
|
1245
|
+
ok: true,
|
|
1246
|
+
activeWorkSessionFile: getActiveSessionFilePath(),
|
|
1247
|
+
activeWorkSession: readCurrentActiveSessionKey(),
|
|
1248
|
+
sessionMapPath: result.path,
|
|
1249
|
+
binding: result.binding
|
|
1250
|
+
};
|
|
1251
|
+
}
|
|
1252
|
+
if (parts[2] === "clear" && req.method === "POST") {
|
|
1253
|
+
const body = await readBody(req);
|
|
1254
|
+
const conversationId = String(body?.conversation_id ?? "").trim();
|
|
1255
|
+
if (!conversationId) throw new Error("conversation_id is required");
|
|
1256
|
+
const result = removeSessionBinding(conversationId);
|
|
1257
|
+
return {
|
|
1258
|
+
ok: true,
|
|
1259
|
+
removed: result.removed,
|
|
1260
|
+
sessionMapPath: result.path
|
|
1261
|
+
};
|
|
1262
|
+
}
|
|
1263
|
+
}
|
|
1092
1264
|
if (parts[1] === "policy") {
|
|
1093
1265
|
const policyPath = getTrustPolicyPath(ctx.identityPath);
|
|
1094
1266
|
const runtimeMode = getRuntimeMode();
|