@pingagent/sdk 0.1.14 → 0.1.15
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/pingagent.js +205 -11
- package/dist/chunk-BCYHGKQE.js +4825 -0
- package/dist/index.d.ts +184 -19
- package/dist/index.js +35 -3
- package/dist/web-server.js +365 -10
- package/package.json +3 -3
package/bin/pingagent.js
CHANGED
|
@@ -25,12 +25,21 @@ import {
|
|
|
25
25
|
TaskHandoffManager,
|
|
26
26
|
TrustPolicyAuditManager,
|
|
27
27
|
CollaborationEventManager,
|
|
28
|
+
CollaborationProjectionOutboxManager,
|
|
29
|
+
OperatorSeenStateManager,
|
|
28
30
|
TrustRecommendationManager,
|
|
29
31
|
getTrustRecommendationActionLabel,
|
|
30
32
|
formatCapabilityCardSummary,
|
|
31
33
|
defaultTrustPolicyDoc,
|
|
32
34
|
normalizeTrustPolicyDoc,
|
|
33
35
|
upsertTrustPolicyRecommendation,
|
|
36
|
+
summarizeSinceLastSeen,
|
|
37
|
+
buildDeliveryTimeline,
|
|
38
|
+
buildProjectionPreview,
|
|
39
|
+
listPendingDecisionViews,
|
|
40
|
+
deriveTransportHealth,
|
|
41
|
+
readTransportPreference,
|
|
42
|
+
switchTransportPreference,
|
|
34
43
|
getActiveSessionFilePath,
|
|
35
44
|
getSessionMapFilePath,
|
|
36
45
|
getSessionBindingAlertsFilePath,
|
|
@@ -243,7 +252,16 @@ function formatSessionRow(session, selected) {
|
|
|
243
252
|
const trust = session.trust_state || 'unknown';
|
|
244
253
|
const unread = session.unread_count ?? 0;
|
|
245
254
|
const who = truncateLine(session.remote_did || session.conversation_id || 'unknown', 40);
|
|
246
|
-
|
|
255
|
+
const seen = session.since_last_seen || {};
|
|
256
|
+
const sinceCount = (seen.new_external_messages ?? 0)
|
|
257
|
+
+ (seen.new_conclusions ?? 0)
|
|
258
|
+
+ (seen.new_handoffs ?? 0)
|
|
259
|
+
+ (seen.new_decisions ?? 0)
|
|
260
|
+
+ (seen.new_failures ?? 0)
|
|
261
|
+
+ (seen.new_repairs ?? 0)
|
|
262
|
+
+ (seen.new_projection_failures ?? 0);
|
|
263
|
+
const sinceBadge = sinceCount > 0 ? ` new=${sinceCount}` : '';
|
|
264
|
+
return `${marker} ${who} [${trust}] unread=${unread}${sinceBadge}${reconnect}`;
|
|
247
265
|
}
|
|
248
266
|
|
|
249
267
|
function formatMessageRow(message) {
|
|
@@ -346,6 +364,21 @@ function buildHostState(identityPath, selectedSessionKey = null, historyPageInde
|
|
|
346
364
|
const alertByConversation = new Map(alerts.map((row) => [row.conversation_id, row]));
|
|
347
365
|
const activeChatSession = readCurrentActiveSessionKey();
|
|
348
366
|
const ingressRuntime = readIngressRuntimeStatus();
|
|
367
|
+
const transportPreference = readTransportPreference();
|
|
368
|
+
const transportHealth = deriveTransportHealth({
|
|
369
|
+
runtime_status: ingressRuntime
|
|
370
|
+
? {
|
|
371
|
+
...ingressRuntime,
|
|
372
|
+
preferred_transport_mode: transportPreference?.preferred_mode ?? ingressRuntime.preferred_transport_mode ?? 'bridge',
|
|
373
|
+
}
|
|
374
|
+
: {
|
|
375
|
+
receive_mode: 'webhook',
|
|
376
|
+
transport_mode: transportPreference?.preferred_mode ?? 'bridge',
|
|
377
|
+
preferred_transport_mode: transportPreference?.preferred_mode ?? 'bridge',
|
|
378
|
+
},
|
|
379
|
+
recent_events: collaborationEventManager.listRecent(30),
|
|
380
|
+
projection_outbox_failed: new CollaborationProjectionOutboxManager(store).listByStatus('failed', 20),
|
|
381
|
+
});
|
|
349
382
|
const desiredSelectedSessionKey =
|
|
350
383
|
(selectedSessionKey && sessions.some((session) => session.session_key === selectedSessionKey) ? selectedSessionKey : null) ??
|
|
351
384
|
sessionManager.getActiveSession()?.session_key ??
|
|
@@ -376,9 +409,9 @@ function buildHostState(identityPath, selectedSessionKey = null, historyPageInde
|
|
|
376
409
|
? collaborationEventManager.listBySession(selectedSession.session_key, 12)
|
|
377
410
|
: [];
|
|
378
411
|
const selectedPendingCollaborationEvents = selectedSession
|
|
379
|
-
?
|
|
412
|
+
? listPendingDecisionViews(store, 100).filter((event) => event.session_key === selectedSession.session_key).slice(0, 12)
|
|
380
413
|
: [];
|
|
381
|
-
const pendingCollaborationEventsGlobal =
|
|
414
|
+
const pendingCollaborationEventsGlobal = listPendingDecisionViews(store, 50);
|
|
382
415
|
const selectedMessages = selectedSession?.conversation_id
|
|
383
416
|
? historyManager.listRecent(selectedSession.conversation_id, 12)
|
|
384
417
|
: [];
|
|
@@ -402,18 +435,39 @@ function buildHostState(identityPath, selectedSessionKey = null, historyPageInde
|
|
|
402
435
|
: [];
|
|
403
436
|
const unreadTotal = sessionsWithMeta.reduce((sum, session) => sum + (session.unread_count ?? 0), 0);
|
|
404
437
|
const alertSessions = sessionsWithMeta.filter((session) => !!session.binding_alert).length;
|
|
438
|
+
const sinceLastSeenGlobal = summarizeSinceLastSeen(store, {
|
|
439
|
+
operator_id: 'tui',
|
|
440
|
+
scope_type: 'global',
|
|
441
|
+
});
|
|
442
|
+
const sessionsWithSeen = sessionsWithMeta.map((session) => ({
|
|
443
|
+
...session,
|
|
444
|
+
since_last_seen: summarizeSinceLastSeen(store, {
|
|
445
|
+
operator_id: 'tui',
|
|
446
|
+
scope_type: 'session',
|
|
447
|
+
scope_key: session.session_key,
|
|
448
|
+
}),
|
|
449
|
+
}));
|
|
450
|
+
const selectedDeliveryTimeline = selectedSession
|
|
451
|
+
? buildDeliveryTimeline(store, selectedSession.session_key, 30)
|
|
452
|
+
: [];
|
|
453
|
+
const selectedProjectionPreview = selectedSession
|
|
454
|
+
? buildProjectionPreview(store, selectedSession.session_key, policy.doc.collaboration_projection?.preset || 'balanced', 5)
|
|
455
|
+
: null;
|
|
405
456
|
return {
|
|
406
457
|
identity,
|
|
407
458
|
runtimeMode,
|
|
408
459
|
activeChatSession,
|
|
409
460
|
ingressRuntime,
|
|
461
|
+
transportPreference,
|
|
462
|
+
transportHealth,
|
|
410
463
|
activeChatSessionFile: getActiveSessionFilePath(),
|
|
411
464
|
sessionMapPath: getSessionMapFilePath(),
|
|
412
465
|
sessionBindingAlertsPath: getSessionBindingAlertsFilePath(),
|
|
413
466
|
policyPath: policy.path,
|
|
414
467
|
policyDoc: policy.doc,
|
|
415
468
|
projectionPreset: policy.doc.collaboration_projection?.preset || 'balanced',
|
|
416
|
-
|
|
469
|
+
sinceLastSeenGlobal,
|
|
470
|
+
sessions: sessionsWithSeen,
|
|
417
471
|
tasks: taskManager.listRecent(30).map((task) => ({
|
|
418
472
|
...task,
|
|
419
473
|
handoff: taskHandoffManager.get(task.task_id),
|
|
@@ -426,6 +480,8 @@ function buildHostState(identityPath, selectedSessionKey = null, historyPageInde
|
|
|
426
480
|
selectedAuditEvents,
|
|
427
481
|
selectedCollaborationEvents,
|
|
428
482
|
selectedPendingCollaborationEvents,
|
|
483
|
+
selectedDeliveryTimeline,
|
|
484
|
+
selectedProjectionPreview,
|
|
429
485
|
pendingCollaborationEventsGlobal,
|
|
430
486
|
selectedMessages,
|
|
431
487
|
selectedHistoryPage,
|
|
@@ -450,6 +506,8 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
450
506
|
const pendingCollaborationEvents = hostState.selectedPendingCollaborationEvents || [];
|
|
451
507
|
const pendingCollaborationEventsGlobal = hostState.pendingCollaborationEventsGlobal || [];
|
|
452
508
|
const messages = hostState.selectedMessages || [];
|
|
509
|
+
const deliveryTimeline = hostState.selectedDeliveryTimeline || [];
|
|
510
|
+
const projectionPreview = hostState.selectedProjectionPreview || null;
|
|
453
511
|
const recommendations = hostState.selectedRecommendations || [];
|
|
454
512
|
const openRecommendation = recommendations.find((item) => item.status === 'open') || null;
|
|
455
513
|
const reopenRecommendation = recommendations.find((item) => item.status === 'dismissed' || item.status === 'superseded') || null;
|
|
@@ -469,14 +527,18 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
469
527
|
|| hostState.ingressRuntime.receive_mode === 'polling_degraded'
|
|
470
528
|
|| !!hostState.ingressRuntime.hooks_last_error;
|
|
471
529
|
const ingressLabel = degraded ? 'Degraded' : 'Ready';
|
|
530
|
+
const transportHealth = hostState.transportHealth || { state: 'Ready', transport_mode: 'bridge', preferred_transport_mode: 'bridge', retry_queue_length: 0, consecutive_failures: 0 };
|
|
531
|
+
const sinceLastSeenGlobal = hostState.sinceLastSeenGlobal || {};
|
|
472
532
|
const lines = [
|
|
473
533
|
'PingAgent Host TUI',
|
|
474
534
|
`DID: ${hostState.identity.did}`,
|
|
475
535
|
`status=${formatStatusLine(uiState?.statusLevel || 'info', uiState?.statusMessage || '(ready)')}${statusTs}${statusCountdown}`,
|
|
476
536
|
`runtime_mode=${hostState.runtimeMode} receive_mode=${hostState.ingressRuntime?.receive_mode || 'webhook'} current_openclaw_chat=${hostState.activeChatSession || '(none)'}`,
|
|
477
537
|
`ingress=${ingressLabel}${degraded ? ' action=[f] fix-now' : ''}`,
|
|
538
|
+
`transport=${transportHealth.transport_mode} preferred=${transportHealth.preferred_transport_mode} state=${transportHealth.state} retry_queue=${transportHealth.retry_queue_length} failures=${transportHealth.consecutive_failures}`,
|
|
478
539
|
uiState?.publicLinkUrl ? `public_link=${uiState.publicLinkUrl}` : null,
|
|
479
540
|
`sessions=${sessions.length} unread_total=${hostState.unreadTotal ?? 0} alert_sessions=${hostState.alertSessions ?? 0} view=${view} projection=${hostState.projectionPreset || 'balanced'}`,
|
|
541
|
+
`since_last_seen external=${sinceLastSeenGlobal.new_external_messages ?? 0} conclusions=${sinceLastSeenGlobal.new_conclusions ?? 0} decisions=${sinceLastSeenGlobal.new_decisions ?? 0} failures=${sinceLastSeenGlobal.new_failures ?? 0}`,
|
|
480
542
|
`policy=${hostState.policyPath}`,
|
|
481
543
|
`chat_link_map=${hostState.sessionMapPath}`,
|
|
482
544
|
`chat_link_alerts=${hostState.sessionBindingAlertsPath}`,
|
|
@@ -505,12 +567,14 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
505
567
|
lines.push('- y: dump task detail to stdout (task-detail view, choose json/plain)');
|
|
506
568
|
lines.push('- u: approve the selected collaboration decision');
|
|
507
569
|
lines.push('- U: reject the selected collaboration decision');
|
|
570
|
+
lines.push('- b: switch preferred transport to bridge');
|
|
571
|
+
lines.push('- c: switch preferred transport to channel');
|
|
508
572
|
lines.push('- f: repair OpenClaw hooks config');
|
|
509
573
|
lines.push('- A: apply first open trust recommendation for selected session');
|
|
510
574
|
lines.push('- D: dismiss current open recommendation');
|
|
511
575
|
lines.push('- R: reopen dismissed/superseded recommendation');
|
|
512
|
-
lines.push('-
|
|
513
|
-
lines.push('-
|
|
576
|
+
lines.push('- B: attach selected session to the current OpenClaw chat');
|
|
577
|
+
lines.push('- C: detach the selected chat link');
|
|
514
578
|
lines.push('- q: quit');
|
|
515
579
|
} else if (view === 'history') {
|
|
516
580
|
lines.push('Conversation History');
|
|
@@ -576,7 +640,7 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
576
640
|
lines.push(...(pendingCollaborationEventsGlobal.length
|
|
577
641
|
? pendingCollaborationEventsGlobal.map((event, idx) => {
|
|
578
642
|
const marker = idx === selectedDecisionIndex ? '>' : ' ';
|
|
579
|
-
return `${marker} ${event.id} [${event.severity}] ${truncateLine(event.summary || '(none)', 88)} session=${event.session_key || '(none)'}`;
|
|
643
|
+
return `${marker} ${event.id} [${event.severity}${event.overdue ? ':overdue' : ''}] ${truncateLine(event.summary || '(none)', 88)} session=${event.session_key || '(none)'}`;
|
|
580
644
|
})
|
|
581
645
|
: ['- none']));
|
|
582
646
|
} else if (view === 'tasks') {
|
|
@@ -642,7 +706,12 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
642
706
|
if (pendingCollaborationEvents.length > 0) {
|
|
643
707
|
lines.push(`pending_collaboration_decisions=${pendingCollaborationEvents.length}`);
|
|
644
708
|
lines.push(`next_decision=${truncateLine(pendingCollaborationEvents[0].summary || '(none)', 100)}`);
|
|
709
|
+
if (pendingCollaborationEvents[0].overdue) {
|
|
710
|
+
lines.push(`next_decision_overdue=${Math.ceil((pendingCollaborationEvents[0].overdue_by_ms || 0) / 60000)}m`);
|
|
711
|
+
}
|
|
645
712
|
}
|
|
713
|
+
const sessionSeen = selected.since_last_seen || {};
|
|
714
|
+
lines.push(`since_last_seen external=${sessionSeen.new_external_messages ?? 0} conclusions=${sessionSeen.new_conclusions ?? 0} decisions=${sessionSeen.new_decisions ?? 0} failures=${sessionSeen.new_failures ?? 0}`);
|
|
646
715
|
const actionBar = [
|
|
647
716
|
selected.trust_state === 'pending' ? '[a] approve' : null,
|
|
648
717
|
'[A] apply-rec',
|
|
@@ -656,8 +725,8 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
656
725
|
pendingCollaborationEvents.length ? '[U] reject-decision' : null,
|
|
657
726
|
'[o] history',
|
|
658
727
|
'[t] tasks',
|
|
659
|
-
'[
|
|
660
|
-
'[
|
|
728
|
+
'[B] attach-chat',
|
|
729
|
+
'[C] detach-chat',
|
|
661
730
|
].filter(Boolean).join(' ');
|
|
662
731
|
lines.push(`actions=${actionBar}`);
|
|
663
732
|
lines.push('');
|
|
@@ -688,6 +757,20 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
688
757
|
lines.push(...(collaborationEvents.length
|
|
689
758
|
? collaborationEvents.map((event) => `- ${event.event_type} [${event.severity}${event.approval_required ? `:${event.approval_status}` : ''}] ${truncateLine(event.summary || '', 90)}`)
|
|
690
759
|
: ['- none']));
|
|
760
|
+
if (projectionPreview) {
|
|
761
|
+
lines.push('');
|
|
762
|
+
lines.push(`Projection Preview [preset=${projectionPreview.preset}]`);
|
|
763
|
+
lines.push(...(projectionPreview.recent.length
|
|
764
|
+
? projectionPreview.recent.map((entry) => `- ${entry.event_type} => ${entry.disposition} (${truncateLine(entry.reason, 70)})`)
|
|
765
|
+
: ['- none']));
|
|
766
|
+
}
|
|
767
|
+
if (view === 'detail') {
|
|
768
|
+
lines.push('');
|
|
769
|
+
lines.push('Delivery Timeline');
|
|
770
|
+
lines.push(...(deliveryTimeline.length
|
|
771
|
+
? deliveryTimeline.slice(0, 10).map((entry) => `- ${formatTs(entry.ts_ms, false)} ${entry.kind} ${truncateLine(entry.summary || '', 72)}`)
|
|
772
|
+
: ['- none']));
|
|
773
|
+
}
|
|
691
774
|
lines.push('');
|
|
692
775
|
lines.push('Audit');
|
|
693
776
|
lines.push(...(auditEvents.length
|
|
@@ -699,7 +782,7 @@ function renderHostTuiScreen(hostState, uiState) {
|
|
|
699
782
|
}
|
|
700
783
|
|
|
701
784
|
lines.push('');
|
|
702
|
-
lines.push('Keys: ↑/↓ or j/k select Enter/l open Esc/h back g/G jump r refresh a approve u/U decide A apply-rec D dismiss-rec R reopen-rec d demo m read p reply o history s search t tasks x cancel-task y dump f fix-hooks b attach-chat
|
|
785
|
+
lines.push('Keys: ↑/↓ or j/k select Enter/l open Esc/h back g/G jump r refresh a approve u/U decide A apply-rec D dismiss-rec R reopen-rec d demo m read p reply o history s search t tasks x cancel-task y dump f fix-hooks b transport->bridge c transport->channel B attach-chat C detach-chat ? help q quit');
|
|
703
786
|
return lines.join('\n');
|
|
704
787
|
}
|
|
705
788
|
|
|
@@ -720,6 +803,10 @@ async function runHostTui(identityPath, opts) {
|
|
|
720
803
|
historySearchQuery: '',
|
|
721
804
|
publicLinkUrl: '',
|
|
722
805
|
};
|
|
806
|
+
const seenState = {
|
|
807
|
+
globalView: null,
|
|
808
|
+
sessionKey: null,
|
|
809
|
+
};
|
|
723
810
|
|
|
724
811
|
const render = () => {
|
|
725
812
|
if (uiState.statusExpiresAt && Date.now() >= uiState.statusExpiresAt) {
|
|
@@ -762,7 +849,49 @@ async function runHostTui(identityPath, opts) {
|
|
|
762
849
|
return rendered.hostState;
|
|
763
850
|
};
|
|
764
851
|
|
|
852
|
+
const markSeen = (scopeType, scopeKey = null) => {
|
|
853
|
+
const store = openStore(identityPath);
|
|
854
|
+
try {
|
|
855
|
+
return new OperatorSeenStateManager(store).markSeen({
|
|
856
|
+
operator_id: 'tui',
|
|
857
|
+
scope_type: scopeType,
|
|
858
|
+
scope_key: scopeType === 'session' ? (scopeKey || null) : null,
|
|
859
|
+
last_seen_ts: Date.now(),
|
|
860
|
+
});
|
|
861
|
+
} finally {
|
|
862
|
+
store.close();
|
|
863
|
+
}
|
|
864
|
+
};
|
|
865
|
+
|
|
866
|
+
const refreshSeenMarkers = (hostState, options = {}) => {
|
|
867
|
+
let changed = false;
|
|
868
|
+
const forceGlobal = !!options.forceGlobal;
|
|
869
|
+
const forceSession = !!options.forceSession;
|
|
870
|
+
if (uiState.view === 'overview' || uiState.view === 'decisions') {
|
|
871
|
+
if (forceGlobal || seenState.globalView !== uiState.view) {
|
|
872
|
+
markSeen('global');
|
|
873
|
+
seenState.globalView = uiState.view;
|
|
874
|
+
changed = true;
|
|
875
|
+
}
|
|
876
|
+
if (uiState.view === 'overview') seenState.sessionKey = null;
|
|
877
|
+
} else if (['detail', 'history', 'tasks', 'task-detail'].includes(uiState.view)) {
|
|
878
|
+
const sessionKey = hostState.selectedSession?.session_key || null;
|
|
879
|
+
if (sessionKey && (forceSession || seenState.sessionKey !== sessionKey)) {
|
|
880
|
+
markSeen('session', sessionKey);
|
|
881
|
+
seenState.sessionKey = sessionKey;
|
|
882
|
+
changed = true;
|
|
883
|
+
}
|
|
884
|
+
}
|
|
885
|
+
return changed;
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
const rerenderAfterSeenUpdate = (hostState, options = {}) => {
|
|
889
|
+
if (!refreshSeenMarkers(hostState, options)) return hostState;
|
|
890
|
+
return redraw();
|
|
891
|
+
};
|
|
892
|
+
|
|
765
893
|
let latestState = redraw();
|
|
894
|
+
latestState = rerenderAfterSeenUpdate(latestState, { forceGlobal: true });
|
|
766
895
|
readline.emitKeypressEvents(process.stdin);
|
|
767
896
|
if (process.stdin.setRawMode) process.stdin.setRawMode(true);
|
|
768
897
|
|
|
@@ -779,6 +908,50 @@ async function runHostTui(identityPath, opts) {
|
|
|
779
908
|
uiState.statusAt = Date.now();
|
|
780
909
|
};
|
|
781
910
|
|
|
911
|
+
const switchTransport = async (mode) => {
|
|
912
|
+
const label = mode === 'channel' ? 'channel' : 'bridge';
|
|
913
|
+
const confirmed = await confirmAction(`Switch preferred transport to ${label} and request a managed restart?`);
|
|
914
|
+
if (!confirmed) {
|
|
915
|
+
setStatus(`Transport switch to ${label} cancelled.`, 'warn');
|
|
916
|
+
latestState = redraw();
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
try {
|
|
920
|
+
const result = switchTransportPreference(mode, {
|
|
921
|
+
updated_by: 'tui',
|
|
922
|
+
});
|
|
923
|
+
const store = openStore(identityPath);
|
|
924
|
+
try {
|
|
925
|
+
new CollaborationEventManager(store).record({
|
|
926
|
+
event_type: 'transport_switched',
|
|
927
|
+
severity: result.restarted ? 'notice' : 'warning',
|
|
928
|
+
summary: result.restarted
|
|
929
|
+
? `Preferred transport switched to ${label}. A managed restart was attempted.`
|
|
930
|
+
: `Preferred transport switched to ${label}. Restart is still required.`,
|
|
931
|
+
detail: {
|
|
932
|
+
preferred_mode: result.preferred_mode,
|
|
933
|
+
restart_required: result.restart_required,
|
|
934
|
+
restart_method: result.restart_method ?? null,
|
|
935
|
+
restart_error: result.restart_error ?? null,
|
|
936
|
+
preference_path: result.preference_path,
|
|
937
|
+
},
|
|
938
|
+
});
|
|
939
|
+
} finally {
|
|
940
|
+
store.close();
|
|
941
|
+
}
|
|
942
|
+
setStatus(
|
|
943
|
+
result.restarted
|
|
944
|
+
? `Preferred transport is now ${label}; managed restart attempted via ${result.restart_method || 'unknown method'}.`
|
|
945
|
+
: `Preferred transport saved as ${label}; restart still required.`,
|
|
946
|
+
result.restarted ? 'ok' : 'warn',
|
|
947
|
+
result.restarted ? 7000 : 9000,
|
|
948
|
+
);
|
|
949
|
+
} catch (error) {
|
|
950
|
+
setStatus(`Transport switch failed: ${error?.message || 'unknown error'}`, 'err', 9000);
|
|
951
|
+
}
|
|
952
|
+
latestState = redraw();
|
|
953
|
+
};
|
|
954
|
+
|
|
782
955
|
const applySessionRecommendation = (selected) => {
|
|
783
956
|
if (!selected?.remote_did) return { ok: false, message: 'No remote DID for selected session.' };
|
|
784
957
|
const store = openStore(identityPath);
|
|
@@ -985,6 +1158,10 @@ async function runHostTui(identityPath, opts) {
|
|
|
985
1158
|
uiState.historySearchQuery = '';
|
|
986
1159
|
}
|
|
987
1160
|
latestState = redraw();
|
|
1161
|
+
latestState = rerenderAfterSeenUpdate(latestState, {
|
|
1162
|
+
forceGlobal: uiState.view === 'overview' || uiState.view === 'decisions',
|
|
1163
|
+
forceSession: ['detail', 'history', 'tasks', 'task-detail'].includes(uiState.view),
|
|
1164
|
+
});
|
|
988
1165
|
};
|
|
989
1166
|
|
|
990
1167
|
const jumpSelection = (target) => {
|
|
@@ -1007,6 +1184,10 @@ async function runHostTui(identityPath, opts) {
|
|
|
1007
1184
|
uiState.historySearchQuery = '';
|
|
1008
1185
|
}
|
|
1009
1186
|
latestState = redraw();
|
|
1187
|
+
latestState = rerenderAfterSeenUpdate(latestState, {
|
|
1188
|
+
forceGlobal: uiState.view === 'overview' || uiState.view === 'decisions',
|
|
1189
|
+
forceSession: ['detail', 'history', 'tasks', 'task-detail'].includes(uiState.view),
|
|
1190
|
+
});
|
|
1010
1191
|
};
|
|
1011
1192
|
|
|
1012
1193
|
const stopInterval = () => {
|
|
@@ -1060,6 +1241,7 @@ async function runHostTui(identityPath, opts) {
|
|
|
1060
1241
|
uiState.view = 'detail';
|
|
1061
1242
|
}
|
|
1062
1243
|
latestState = redraw();
|
|
1244
|
+
latestState = rerenderAfterSeenUpdate(latestState, { forceSession: uiState.view !== 'decisions' && uiState.view !== 'overview' });
|
|
1063
1245
|
return;
|
|
1064
1246
|
}
|
|
1065
1247
|
if (key?.name === 'escape' || key?.name === 'h') {
|
|
@@ -1068,6 +1250,7 @@ async function runHostTui(identityPath, opts) {
|
|
|
1068
1250
|
else if (uiState.view === 'decisions') uiState.view = 'overview';
|
|
1069
1251
|
else uiState.view = 'overview';
|
|
1070
1252
|
latestState = redraw();
|
|
1253
|
+
latestState = rerenderAfterSeenUpdate(latestState, { forceGlobal: uiState.view === 'overview' || uiState.view === 'decisions' });
|
|
1071
1254
|
return;
|
|
1072
1255
|
}
|
|
1073
1256
|
if (_str === '?') {
|
|
@@ -1104,6 +1287,7 @@ async function runHostTui(identityPath, opts) {
|
|
|
1104
1287
|
uiState.selectedHistoryPageIndex = 0;
|
|
1105
1288
|
setStatus('Opened task list view.', 'info');
|
|
1106
1289
|
latestState = redraw();
|
|
1290
|
+
latestState = rerenderAfterSeenUpdate(latestState, { forceSession: true });
|
|
1107
1291
|
return;
|
|
1108
1292
|
}
|
|
1109
1293
|
if (key?.name === 'i') {
|
|
@@ -1111,6 +1295,7 @@ async function runHostTui(identityPath, opts) {
|
|
|
1111
1295
|
uiState.selectedDecisionIndex = 0;
|
|
1112
1296
|
setStatus('Opened decision inbox.', 'info');
|
|
1113
1297
|
latestState = redraw();
|
|
1298
|
+
latestState = rerenderAfterSeenUpdate(latestState, { forceGlobal: true });
|
|
1114
1299
|
return;
|
|
1115
1300
|
}
|
|
1116
1301
|
if (key?.name === 'r') {
|
|
@@ -1293,6 +1478,7 @@ async function runHostTui(identityPath, opts) {
|
|
|
1293
1478
|
uiState.historySearchQuery = '';
|
|
1294
1479
|
setStatus('Opened local history view.', 'info');
|
|
1295
1480
|
latestState = redraw();
|
|
1481
|
+
latestState = rerenderAfterSeenUpdate(latestState, { forceSession: true });
|
|
1296
1482
|
return;
|
|
1297
1483
|
}
|
|
1298
1484
|
if ((_str === '/' || key?.name === 's') && uiState.view === 'history') {
|
|
@@ -1305,6 +1491,14 @@ async function runHostTui(identityPath, opts) {
|
|
|
1305
1491
|
return;
|
|
1306
1492
|
}
|
|
1307
1493
|
if (key?.name === 'b') {
|
|
1494
|
+
await switchTransport('bridge');
|
|
1495
|
+
return;
|
|
1496
|
+
}
|
|
1497
|
+
if (key?.name === 'c') {
|
|
1498
|
+
await switchTransport('channel');
|
|
1499
|
+
return;
|
|
1500
|
+
}
|
|
1501
|
+
if (_str === 'B') {
|
|
1308
1502
|
const selected = (latestState.sessions || []).find((session) => session.session_key === uiState.selectedSessionKey);
|
|
1309
1503
|
if (!selected?.conversation_id) return;
|
|
1310
1504
|
const current = latestState.activeChatSession || '(none)';
|
|
@@ -1324,7 +1518,7 @@ async function runHostTui(identityPath, opts) {
|
|
|
1324
1518
|
latestState = redraw();
|
|
1325
1519
|
return;
|
|
1326
1520
|
}
|
|
1327
|
-
if (
|
|
1521
|
+
if (_str === 'C') {
|
|
1328
1522
|
const selected = (latestState.sessions || []).find((session) => session.session_key === uiState.selectedSessionKey);
|
|
1329
1523
|
if (!selected?.conversation_id) return;
|
|
1330
1524
|
removeSessionBinding(selected.conversation_id);
|