@xfxstudio/claworld 2026.5.6-testing.1 → 2026.5.11-testing.1

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.
@@ -6,18 +6,9 @@
6
6
  "skills": [
7
7
  "./skills"
8
8
  ],
9
- "contracts": {
10
- "tools": [
11
- "claworld_manage_account",
12
- "claworld_search",
13
- "claworld_get_public_profile",
14
- "claworld_manage_worlds",
15
- "claworld_manage_conversations"
16
- ]
17
- },
18
9
  "name": "Claworld Persona Relay",
19
10
  "description": "Claworld relay world channel plugin for OpenClaw.",
20
- "version": "2026.5.6-testing.1",
11
+ "version": "2026.5.11-testing.1",
21
12
  "configSchema": {
22
13
  "type": "object",
23
14
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfxstudio/claworld",
3
- "version": "2026.5.6-testing.1",
3
+ "version": "2026.5.11-testing.1",
4
4
  "description": "Claworld channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from 'node:crypto';
2
+ import path from 'node:path';
2
3
 
3
4
  import {
4
5
  applyRuntimeIdentity,
@@ -32,6 +33,10 @@ import { createInboundSessionRouter } from '../runtime/inbound-session-router.js
32
33
  import { createOutboundSessionBridge } from '../runtime/outbound-session-bridge.js';
33
34
  import { createCanonicalResultBuilder } from '../runtime/canonical-result-builder.js';
34
35
  import { createDemoSessionBootstrap } from '../runtime/demo-session-bootstrap.js';
36
+ import {
37
+ appendClaworldJournalEvent,
38
+ buildClaworldRuntimeMaintenanceEvent,
39
+ } from '../runtime/working-memory.js';
35
40
  import {
36
41
  broadcastModeratedWorld,
37
42
  createModeratedWorld,
@@ -62,6 +67,7 @@ import {
62
67
  resolveWorldSelectionFlow,
63
68
  } from '../runtime/product-shell-helper.js';
64
69
  import { extractBackendErrorContext } from '../runtime/backend-error-context.js';
70
+ import { resolveOpenClawWorkspaceRoot } from '../runtime/workspace-resolver.js';
65
71
  import { getClaworldRuntime } from './runtime.js';
66
72
  import {
67
73
  CLAWORLD_PLUGIN_CURRENT_VERSION,
@@ -582,17 +588,19 @@ async function deliverRelayMessage({ runtimeConfig, to, text, fetchImpl, logger,
582
588
 
583
589
  if (!result.ok) {
584
590
  logger.error?.('[claworld:outbound] message delivery failed', { status: result.status, body: result.body });
585
- createRelayRouteError({
586
- result,
587
- runtimeConfig,
591
+ throw createRuntimeBoundaryError({
588
592
  code: 'relay_message_delivery_failed',
589
- publicMessage: 'claworld outbound message delivery failed',
593
+ category: 'transport',
594
+ status: result.status >= 500 ? 502 : result.status,
590
595
  message: `claworld outbound failed: ${result.status}`,
596
+ publicMessage: 'claworld outbound message delivery failed',
597
+ recoverable: true,
591
598
  context: {
599
+ accountId: runtimeConfig.accountId || null,
592
600
  fromAgentId,
593
601
  targetAgentId,
602
+ status: result.status,
594
603
  },
595
- passThroughBackendConflict: true,
596
604
  });
597
605
  }
598
606
 
@@ -628,23 +636,13 @@ function createRelayRouteError({
628
636
  publicMessage,
629
637
  message,
630
638
  context = {},
631
- passThroughBackendConflict = false,
632
639
  }) {
633
- const backendCode = resolveNormalizedText(result?.body?.error, null);
634
- const backendMessage = resolveNormalizedText(result?.body?.message, null);
635
- const shouldPassThroughConflict = passThroughBackendConflict === true
636
- && Number(result?.status) === 409
637
- && backendCode;
638
640
  throw createRuntimeBoundaryError({
639
- code: shouldPassThroughConflict ? backendCode : code,
640
- category: shouldPassThroughConflict ? 'conflict' : 'transport',
641
+ code,
642
+ category: 'transport',
641
643
  status: result?.status >= 500 ? 502 : result?.status || 502,
642
- message: shouldPassThroughConflict
643
- ? (backendMessage || message || publicMessage)
644
- : (message || publicMessage),
645
- publicMessage: shouldPassThroughConflict
646
- ? (backendMessage || publicMessage)
647
- : publicMessage,
644
+ message: message || publicMessage,
645
+ publicMessage,
648
646
  recoverable: true,
649
647
  context: {
650
648
  accountId: runtimeConfig.accountId || null,
@@ -735,7 +733,6 @@ async function createChatRequest({
735
733
  displayName: normalizedDisplayName,
736
734
  agentCode: normalizedAgentCode,
737
735
  },
738
- passThroughBackendConflict: true,
739
736
  });
740
737
  }
741
738
  return result.body || {};
@@ -818,7 +815,6 @@ async function acceptChatRequest({
818
815
  code: 'chat_request_accept_failed',
819
816
  publicMessage: 'failed to accept chat request',
820
817
  context: { actorAgentId, chatRequestId },
821
- passThroughBackendConflict: true,
822
818
  });
823
819
  }
824
820
  return normalizeChatInboxPayloadSessionKeys(result.body || {}, { localAgentId });
@@ -847,7 +843,6 @@ async function rejectChatRequest({
847
843
  code: 'chat_request_reject_failed',
848
844
  publicMessage: 'failed to reject chat request',
849
845
  context: { actorAgentId, chatRequestId },
850
- passThroughBackendConflict: true,
851
846
  });
852
847
  }
853
848
  return result.body || {};
@@ -1852,6 +1847,297 @@ function buildDeliveryInboundEnvelope({
1852
1847
  };
1853
1848
  }
1854
1849
 
1850
+ function normalizeSessionStoreKey(value) {
1851
+ return resolveNormalizedText(value, '').toLowerCase();
1852
+ }
1853
+
1854
+ function resolveSessionStoreEntry(store = null, sessionKey = null) {
1855
+ if (!store || typeof store !== 'object' || Array.isArray(store)) return null;
1856
+ const normalizedSessionKey = resolveNormalizedText(sessionKey, null);
1857
+ if (!normalizedSessionKey) return null;
1858
+ if (store[normalizedSessionKey] && typeof store[normalizedSessionKey] === 'object') {
1859
+ return store[normalizedSessionKey];
1860
+ }
1861
+ const lowerSessionKey = normalizeSessionStoreKey(normalizedSessionKey);
1862
+ if (store[lowerSessionKey] && typeof store[lowerSessionKey] === 'object') {
1863
+ return store[lowerSessionKey];
1864
+ }
1865
+ const match = Object.entries(store).find(([key, value]) => (
1866
+ normalizeSessionStoreKey(key) === lowerSessionKey
1867
+ && value
1868
+ && typeof value === 'object'
1869
+ && !Array.isArray(value)
1870
+ ));
1871
+ return match ? match[1] : null;
1872
+ }
1873
+
1874
+ function readRuntimeSessionStoreEntry({ runtime = null, sessionStorePath = null, sessionKey = null } = {}) {
1875
+ if (!runtime?.agent?.session?.loadSessionStore || !sessionStorePath || !sessionKey) return null;
1876
+ try {
1877
+ return resolveSessionStoreEntry(
1878
+ runtime.agent.session.loadSessionStore(sessionStorePath),
1879
+ sessionKey,
1880
+ );
1881
+ } catch {
1882
+ return null;
1883
+ }
1884
+ }
1885
+
1886
+ function resolveSessionFilePathFromRuntime({
1887
+ runtime = null,
1888
+ sessionId = null,
1889
+ record = {},
1890
+ sessionStorePath = null,
1891
+ localAgentId = null,
1892
+ } = {}) {
1893
+ const normalizedSessionId = resolveNormalizedText(sessionId, null);
1894
+ if (!normalizedSessionId) return null;
1895
+
1896
+ const sessionsDir = sessionStorePath
1897
+ ? path.dirname(path.resolve(sessionStorePath))
1898
+ : null;
1899
+ if (typeof runtime?.agent?.session?.resolveSessionFilePath === 'function') {
1900
+ try {
1901
+ const resolved = runtime.agent.session.resolveSessionFilePath(
1902
+ normalizedSessionId,
1903
+ record,
1904
+ {
1905
+ ...(sessionsDir ? { sessionsDir } : {}),
1906
+ ...(localAgentId ? { agentId: localAgentId } : {}),
1907
+ },
1908
+ );
1909
+ const normalized = resolveNormalizedText(resolved, null);
1910
+ if (normalized) return normalized;
1911
+ } catch {
1912
+ // Fall through to the local derivation below.
1913
+ }
1914
+ }
1915
+
1916
+ const candidate = resolveNormalizedText(record?.sessionFile, null);
1917
+ if (candidate) {
1918
+ if (path.isAbsolute(candidate) || !sessionsDir) return candidate;
1919
+ return path.resolve(sessionsDir, candidate);
1920
+ }
1921
+
1922
+ if (sessionsDir) {
1923
+ return path.join(sessionsDir, `${normalizedSessionId}.jsonl`);
1924
+ }
1925
+ return null;
1926
+ }
1927
+
1928
+ function resolveSessionRecordArtifacts(record = null, fallbackStorePath = null, options = {}) {
1929
+ const normalizedRecord = record && typeof record === 'object' && !Array.isArray(record) ? record : {};
1930
+ const nestedSession = normalizedRecord.session && typeof normalizedRecord.session === 'object' && !Array.isArray(normalizedRecord.session)
1931
+ ? normalizedRecord.session
1932
+ : {};
1933
+ const sessionId = resolveNormalizedText(
1934
+ normalizedRecord.sessionId,
1935
+ resolveNormalizedText(nestedSession.sessionId, resolveNormalizedText(normalizedRecord.id, null)),
1936
+ );
1937
+ const sessionStorePath = resolveNormalizedText(
1938
+ normalizedRecord.storePath,
1939
+ resolveNormalizedText(normalizedRecord.sessionStorePath, fallbackStorePath),
1940
+ );
1941
+ const directSessionFile = resolveNormalizedText(
1942
+ normalizedRecord.sessionFile,
1943
+ resolveNormalizedText(
1944
+ normalizedRecord.sessionPath,
1945
+ resolveNormalizedText(
1946
+ normalizedRecord.filePath,
1947
+ resolveNormalizedText(normalizedRecord.path, resolveNormalizedText(nestedSession.filePath, null)),
1948
+ ),
1949
+ ),
1950
+ );
1951
+ const sessionFile = directSessionFile || resolveSessionFilePathFromRuntime({
1952
+ runtime: options.runtime,
1953
+ sessionId,
1954
+ record: normalizedRecord,
1955
+ sessionStorePath,
1956
+ localAgentId: options.localAgentId,
1957
+ });
1958
+ const transcriptPath = resolveNormalizedText(
1959
+ normalizedRecord.transcriptPath,
1960
+ resolveNormalizedText(nestedSession.transcriptPath, sessionFile),
1961
+ );
1962
+ return {
1963
+ sessionId,
1964
+ sessionFile,
1965
+ sessionStorePath,
1966
+ transcriptPath,
1967
+ };
1968
+ }
1969
+
1970
+ async function recordRuntimeInboundSessionArtifacts({
1971
+ runtime = null,
1972
+ currentCfg = {},
1973
+ localAgentId = null,
1974
+ sessionKey = null,
1975
+ ctx = {},
1976
+ logger = console,
1977
+ runtimeAccountId = null,
1978
+ logLabel = 'inbound',
1979
+ logContext = {},
1980
+ } = {}) {
1981
+ let sessionStorePath = null;
1982
+ let sessionRecord = null;
1983
+ const sessionApi = runtime?.channel?.session || {};
1984
+ const localSessionKey = resolveNormalizedText(ctx?.SessionKey, sessionKey);
1985
+
1986
+ if (sessionApi.resolveStorePath && localAgentId) {
1987
+ sessionStorePath = sessionApi.resolveStorePath(currentCfg.session?.store, {
1988
+ agentId: localAgentId,
1989
+ });
1990
+ const onRecordError = (error) => {
1991
+ logger.error?.(`[claworld:${runtimeAccountId}] failed to record ${logLabel} inbound session`, {
1992
+ ...logContext,
1993
+ sessionKey,
1994
+ localSessionKey,
1995
+ localAgentId,
1996
+ error: error?.message || String(error),
1997
+ });
1998
+ };
1999
+ try {
2000
+ if (typeof sessionApi.recordSessionMetaFromInbound === 'function') {
2001
+ sessionRecord = await sessionApi.recordSessionMetaFromInbound({
2002
+ storePath: sessionStorePath,
2003
+ sessionKey: localSessionKey,
2004
+ ctx,
2005
+ });
2006
+ } else if (typeof sessionApi.recordInboundSession === 'function') {
2007
+ sessionRecord = await sessionApi.recordInboundSession({
2008
+ storePath: sessionStorePath,
2009
+ sessionKey: localSessionKey,
2010
+ ctx,
2011
+ onRecordError,
2012
+ });
2013
+ }
2014
+ } catch (error) {
2015
+ onRecordError(error);
2016
+ }
2017
+ if (!sessionRecord) {
2018
+ sessionRecord = readRuntimeSessionStoreEntry({
2019
+ runtime,
2020
+ sessionStorePath,
2021
+ sessionKey: localSessionKey,
2022
+ });
2023
+ }
2024
+ }
2025
+
2026
+ return {
2027
+ sessionStorePath,
2028
+ sessionRecord,
2029
+ sessionArtifacts: resolveSessionRecordArtifacts(sessionRecord, sessionStorePath, {
2030
+ runtime,
2031
+ localAgentId,
2032
+ }),
2033
+ };
2034
+ }
2035
+
2036
+ function buildInboundRuntimeMaintenanceEvent({
2037
+ delivery = {},
2038
+ metadata = {},
2039
+ payload = {},
2040
+ messageId = null,
2041
+ eventType = 'delivery',
2042
+ sessionKind = null,
2043
+ localSessionKey = null,
2044
+ localAgentId = null,
2045
+ sessionArtifacts = {},
2046
+ workspaceRoot = null,
2047
+ } = {}) {
2048
+ const normalizedEventType = resolveNormalizedText(eventType, 'delivery');
2049
+ const isRelayDelivery = normalizedEventType === 'delivery';
2050
+ const sessionKey = resolveNormalizedText(delivery.sessionKey, null);
2051
+ const requestId = resolveNormalizedText(
2052
+ metadata.kickoffRequestId,
2053
+ resolveNormalizedText(metadata.requestId, resolveNormalizedText(metadata.chatRequestId, null)),
2054
+ );
2055
+ const worldId = resolveNormalizedText(
2056
+ metadata.worldId,
2057
+ resolveNormalizedText(delivery.worldId, resolveNormalizedText(payload.worldId, null)),
2058
+ );
2059
+ const conversationKey = resolveNormalizedText(
2060
+ metadata.conversationKey,
2061
+ resolveNormalizedText(delivery.conversationKey, resolveNormalizedText(payload.conversationKey, null)),
2062
+ );
2063
+ const fromAgentId = resolveNormalizedText(metadata.fromAgentId, null);
2064
+ const targetAgentId = resolveNormalizedText(
2065
+ delivery.targetAgentId,
2066
+ resolveNormalizedText(payload.targetAgentId, resolveNormalizedText(metadata.targetAgentId, null)),
2067
+ );
2068
+ const notificationId = resolveNormalizedText(
2069
+ metadata.notificationId,
2070
+ resolveNormalizedText(payload.notificationId, null),
2071
+ );
2072
+ const inboxItemId = resolveNormalizedText(
2073
+ metadata.inboxItemId,
2074
+ resolveNormalizedText(payload.inboxItemId, null),
2075
+ );
2076
+ const scope = sessionKind === 'management' ? 'management' : 'conversation';
2077
+ const summary = [
2078
+ isRelayDelivery
2079
+ ? 'Inbound Claworld delivery joined local session'
2080
+ : 'Inbound Claworld runtime input joined local session',
2081
+ requestId ? `for request ${requestId}` : null,
2082
+ fromAgentId ? `from ${fromAgentId}` : null,
2083
+ ].filter(Boolean).join(' ');
2084
+ return buildClaworldRuntimeMaintenanceEvent({
2085
+ id: messageId ? `runtime:${normalizedEventType}:${messageId}` : null,
2086
+ timestamp: delivery.createdAt || metadata.createdAt || payload.createdAt || null,
2087
+ kind: isRelayDelivery
2088
+ ? (metadata.deliveryType ? `delivery.${metadata.deliveryType}` : 'delivery')
2089
+ : 'runtime_event',
2090
+ eventType: normalizedEventType,
2091
+ scope,
2092
+ summary,
2093
+ excerpt: isRelayDelivery
2094
+ ? (
2095
+ payload.contextText
2096
+ ? 'Inbound delivery included contextText; raw dialogue is kept in the OpenClaw session transcript.'
2097
+ : 'Inbound delivery routed into an OpenClaw session after backend session resolution.'
2098
+ )
2099
+ : 'Inbound runtime input routed into an OpenClaw session after backend session resolution.',
2100
+ refs: {
2101
+ deliveryId: isRelayDelivery ? messageId : null,
2102
+ eventId: messageId,
2103
+ requestId,
2104
+ chatRequestId: requestId,
2105
+ worldId,
2106
+ conversationKey,
2107
+ fromAgentId,
2108
+ targetAgentId,
2109
+ notificationId,
2110
+ inboxItemId,
2111
+ sessionKey: localSessionKey || sessionKey,
2112
+ relaySessionKey: sessionKey,
2113
+ },
2114
+ relations: {
2115
+ deliveryId: isRelayDelivery ? messageId : null,
2116
+ eventId: messageId,
2117
+ requestId,
2118
+ chatRequestId: requestId,
2119
+ worldId,
2120
+ conversationKey,
2121
+ fromAgentId,
2122
+ targetAgentId,
2123
+ notificationId,
2124
+ inboxItemId,
2125
+ localAgentId,
2126
+ localSessionKey,
2127
+ relaySessionKey: sessionKey,
2128
+ sessionKey: localSessionKey || sessionKey,
2129
+ sessionId: sessionArtifacts.sessionId,
2130
+ sessionFile: sessionArtifacts.sessionFile,
2131
+ sessionStorePath: sessionArtifacts.sessionStorePath,
2132
+ transcriptPath: sessionArtifacts.transcriptPath,
2133
+ },
2134
+ artifacts: {
2135
+ workspaceRoot,
2136
+ ...sessionArtifacts,
2137
+ },
2138
+ });
2139
+ }
2140
+
1855
2141
  function createDeliveryReplyDispatcher({
1856
2142
  runtime,
1857
2143
  currentCfg,
@@ -2243,18 +2529,14 @@ async function maybeBridgeRuntimeInboundEvent({
2243
2529
  const contextText = resolveNormalizedText(payload.contextText, null);
2244
2530
  const incomingText = resolveNormalizedText(
2245
2531
  payload.commandText,
2246
- contextText ? null : resolveNormalizedText(payload.text, resolveNormalizedText(payload.body, null)),
2532
+ contextText
2533
+ ? null
2534
+ : resolveNormalizedText(payload.text, resolveNormalizedText(payload.body, null)),
2247
2535
  );
2248
2536
  const commandText = resolveNormalizedText(payload.commandText, incomingText);
2249
2537
  const fromAgentId = resolveNormalizedText(metadata.fromAgentId, null);
2250
- const routeSessionKind = resolveNormalizedText(
2251
- event?.route?.sessionKind,
2252
- resolveNormalizedText(delivery.sessionKind, resolveNormalizedText(payload.sessionKind, null)),
2253
- );
2254
2538
  const isRelayDelivery = eventType === 'delivery';
2255
2539
  const allowReply = metadata.allowReply === true || (isRelayDelivery && metadata.allowReply !== false);
2256
- const remoteIdentity = fromAgentId
2257
- || resolveNormalizedText(metadata.source, routeSessionKind === 'management' ? 'claworld-management' : 'unknown-peer');
2258
2540
 
2259
2541
  if (
2260
2542
  !runtime?.channel?.reply?.finalizeInboundContext
@@ -2301,6 +2583,12 @@ async function maybeBridgeRuntimeInboundEvent({
2301
2583
  sessionTarget: runtimeConfig.routing?.sessionTarget,
2302
2584
  fallbackTarget: runtimeConfig.routing?.fallbackTarget,
2303
2585
  }) || null;
2586
+ const routeSessionKind = resolveNormalizedText(
2587
+ event?.route?.sessionKind,
2588
+ resolveNormalizedText(routed?.sessionKind, null),
2589
+ );
2590
+ const remoteIdentity = fromAgentId
2591
+ || resolveNormalizedText(metadata.source, routeSessionKind === 'management' ? 'claworld-management' : 'unknown-peer');
2304
2592
  const worldId = resolveDeliveryWorldId(delivery);
2305
2593
  const commandAuthorized = isRelayDelivery && shouldAuthorizeBridgedCommand({
2306
2594
  runtimeConfig,
@@ -2342,6 +2630,9 @@ async function maybeBridgeRuntimeInboundEvent({
2342
2630
  OriginatingFrom: remoteIdentity,
2343
2631
  OriginatingTo: remoteIdentity,
2344
2632
  ChatType: isManagementSession ? 'management' : 'direct',
2633
+ SessionType: isManagementSession ? 'management' : 'direct',
2634
+ sessionType: isManagementSession ? 'management' : 'direct',
2635
+ sessionKind: isManagementSession ? 'management' : 'conversation',
2345
2636
  SenderName: senderName,
2346
2637
  SenderId: remoteIdentity,
2347
2638
  MessageId: deliveryId,
@@ -2357,26 +2648,21 @@ async function maybeBridgeRuntimeInboundEvent({
2357
2648
  UntrustedContext,
2358
2649
  });
2359
2650
 
2360
- if (runtime?.channel?.session?.recordInboundSession && runtime?.channel?.session?.resolveStorePath && localAgentId) {
2361
- const storePath = runtime.channel.session.resolveStorePath(currentCfg.session?.store, {
2362
- agentId: localAgentId,
2363
- });
2364
- await runtime.channel.session.recordInboundSession({
2365
- storePath,
2366
- sessionKey: inboundCtx.SessionKey || sessionKey,
2367
- ctx: inboundCtx,
2368
- onRecordError: (error) => {
2369
- logger.error?.(`[claworld:${runtimeAccountId}] failed to record inbound session`, {
2370
- eventType,
2371
- deliveryId,
2372
- sessionKey,
2373
- localSessionKey,
2374
- localAgentId,
2375
- error: error?.message || String(error),
2376
- });
2377
- },
2378
- });
2379
- }
2651
+ const {
2652
+ sessionArtifacts,
2653
+ } = await recordRuntimeInboundSessionArtifacts({
2654
+ runtime,
2655
+ currentCfg,
2656
+ localAgentId,
2657
+ sessionKey,
2658
+ ctx: inboundCtx,
2659
+ logger,
2660
+ runtimeAccountId,
2661
+ logContext: {
2662
+ eventType,
2663
+ deliveryId,
2664
+ },
2665
+ });
2380
2666
 
2381
2667
  logger.info?.(`[claworld:${runtimeAccountId}] ${isRelayDelivery ? 'routing delivery into runtime session' : 'routing inbound event into runtime session'}`, {
2382
2668
  eventType,
@@ -2478,16 +2764,54 @@ async function maybeBridgeRuntimeInboundEvent({
2478
2764
  }));
2479
2765
  }
2480
2766
 
2767
+ let journalResult = null;
2768
+ const workspaceRoot = resolveOpenClawWorkspaceRoot({
2769
+ sources: [
2770
+ { agentId: localAgentId, localAgentId },
2771
+ currentCfg,
2772
+ runtimeConfig,
2773
+ ],
2774
+ config: currentCfg,
2775
+ agentId: localAgentId,
2776
+ });
2777
+ if (workspaceRoot) {
2778
+ try {
2779
+ const maintenanceEvent = buildInboundRuntimeMaintenanceEvent({
2780
+ delivery,
2781
+ metadata,
2782
+ payload,
2783
+ messageId: deliveryId,
2784
+ eventType,
2785
+ sessionKind: routeSessionKind,
2786
+ localSessionKey,
2787
+ localAgentId,
2788
+ sessionArtifacts,
2789
+ workspaceRoot,
2790
+ });
2791
+ journalResult = await appendClaworldJournalEvent(workspaceRoot, maintenanceEvent);
2792
+ } catch (error) {
2793
+ logger.warn?.(`[claworld:${runtimeAccountId}] inbound journal append failed`, {
2794
+ eventType,
2795
+ deliveryId,
2796
+ sessionKey,
2797
+ error: error?.message || String(error),
2798
+ });
2799
+ }
2800
+ }
2801
+
2481
2802
  logger.info?.(`[claworld:${runtimeAccountId}] ${isRelayDelivery ? 'delivery bridge completed' : 'inbound bridge completed'}`, {
2482
2803
  eventType,
2483
2804
  deliveryId,
2484
2805
  sessionKey,
2485
2806
  localSessionKey,
2807
+ sessionId: sessionArtifacts.sessionId || null,
2808
+ sessionFile: sessionArtifacts.sessionFile || null,
2486
2809
  queuedFinal: Boolean(dispatchResult?.queuedFinal),
2487
2810
  replied,
2488
2811
  keptSilent,
2489
2812
  routeStatus: routed?.status || null,
2490
2813
  runtimeOutputSummary,
2814
+ journal: journalResult?.ok === true,
2491
2815
  });
2492
2816
 
2493
2817
  return {