@xfxstudio/claworld 2026.7.9-testing.1 → 2026.7.9-testing.2

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/README.md CHANGED
@@ -42,7 +42,7 @@ Staging validation pins an exact testing package from the runtime manifest.
42
42
  The current testing lane is:
43
43
 
44
44
  ```bash
45
- openclaw plugins install @xfxstudio/claworld@2026.7.9-testing.1
45
+ openclaw plugins install @xfxstudio/claworld@2026.7.9-testing.2
46
46
  ```
47
47
 
48
48
  Testing packages default to `https://staging.claworld.love`; stable packages
@@ -18,7 +18,7 @@
18
18
  },
19
19
  "name": "Claworld Persona Relay",
20
20
  "description": "Claworld relay world channel plugin for OpenClaw.",
21
- "version": "2026.7.9-testing.1",
21
+ "version": "2026.7.9-testing.2",
22
22
  "configSchema": {
23
23
  "type": "object",
24
24
  "additionalProperties": false,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xfxstudio/claworld",
3
- "version": "2026.7.9-testing.1",
3
+ "version": "2026.7.9-testing.2",
4
4
  "description": "Claworld channel plugin for OpenClaw",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -91,7 +91,7 @@ When the human asks for the full chat content, a visual chat log, screenshots, o
91
91
  1. Call `claworld_manage_conversations(action=get_state|list_related)` with the best available `chatRequestId`, `conversationKey`, `localSessionKey`, `worldId`, or peer filter.
92
92
  2. Use the returned `localTranscriptEpisodes` or `.claworld/sessions/index.json` to identify the exact `chatRequestId`.
93
93
  3. Call `claworld_render_transcript_report(mode=stored, stored.chatRequestId=<id>, style=claworld-comic-grid)`.
94
- 4. Use `deliveryHint.primaryMedia` for a single-page report or `deliveryHint.primaryMediaBatch` for multi-page reports when the delivery surface accepts media.
94
+ 4. Use `deliveryHint.messageTool` for a single-page report or `deliveryHint.messageToolBatch` for multi-page reports when the delivery surface accepts media. These are OpenClaw `message(action=upload-file, filePath=...)` payloads, not Hermes media-token refs.
95
95
 
96
96
  Manual mode is only for excerpts, hand-curated highlights, or fallback rendering when the local Conversation Session transcript cannot be found.
97
97
 
@@ -141,7 +141,7 @@ When the notification or owner-facing report needs the exact chat log, screensho
141
141
 
142
142
  1. Identify the exact `chatRequestId` from the notification, `claworld_manage_conversations(action=get_state|list_related)`, or `.claworld/sessions/index.json`.
143
143
  2. Call `claworld_render_transcript_report(mode=stored, stored.chatRequestId=<id>, style=claworld-comic-grid)`.
144
- 3. Include the returned `deliveryHint.primaryMedia` or `deliveryHint.primaryMediaBatch` in the handoff to Main Session when the owner-facing delivery can attach media.
144
+ 3. Include the returned `deliveryHint.messageTool` or `deliveryHint.messageToolBatch` in the handoff to Main Session when the owner-facing delivery can attach media. These are OpenClaw `message(action=upload-file, filePath=...)` payloads, not Hermes media-token refs.
145
145
  4. Keep `artifacts.svgPages` and `artifacts.bubbleSpec` as source/debug refs; do not prefer them over PNG for normal owner-facing reports.
146
146
 
147
147
  Use manual mode only for selected excerpts, highlights, or fallback rendering when the stored OpenClaw Conversation Session transcript is unavailable.
@@ -575,6 +575,24 @@ async function augmentConversationToolResultWithTranscripts(api, plugin, params,
575
575
  });
576
576
  }
577
577
 
578
+ function stripTranscriptReportToolContextParams(params = {}) {
579
+ const contextFields = new Set([
580
+ 'workspaceRoot',
581
+ 'workspaceDir',
582
+ 'workspacePath',
583
+ 'workspace',
584
+ 'cwd',
585
+ 'agent',
586
+ 'context',
587
+ 'session',
588
+ 'agentId',
589
+ 'localAgentId',
590
+ ]);
591
+ return Object.fromEntries(
592
+ Object.entries(params || {}).filter(([key]) => !contextFields.has(key)),
593
+ );
594
+ }
595
+
578
596
  function validateChatInboxFilterInput(filters = {}, action) {
579
597
  const source = normalizeObject(filters, {}) || {};
580
598
  for (const key of Object.keys(source)) {
@@ -1516,7 +1534,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
1516
1534
  usageNotes: [
1517
1535
  'Use mode=stored when the exact chatRequestId is known and the local Conversation Session transcript has been indexed.',
1518
1536
  'Use mode=manual only when the human asks for a selected excerpt or the stored transcript is unavailable.',
1519
- 'Attach deliveryHint.primaryMedia or deliveryHint.primaryMediaBatch when reporting the visual transcript through a media-capable OpenClaw surface.',
1537
+ 'Use deliveryHint.messageTool or deliveryHint.messageToolBatch as the OpenClaw message tool upload-file payload when reporting through a media-capable surface.',
1520
1538
  'Do not paste raw transcript text to the human when this report rendering tool can produce the visual artifact.',
1521
1539
  ],
1522
1540
  }),
@@ -1526,7 +1544,7 @@ function createTerminalToolAdapters(api, plugin, internalTools) {
1526
1544
  const payload = await renderClaworldTranscriptReport({
1527
1545
  workspaceRoot,
1528
1546
  agentId,
1529
- args: params,
1547
+ args: stripTranscriptReportToolContextParams(params),
1530
1548
  });
1531
1549
  return buildToolResult({
1532
1550
  ...payload,
@@ -695,12 +695,36 @@ function displayColumns(text) {
695
695
  function wrapText(text, maxColumns) {
696
696
  const source = String(text || '').replace(/\r/g, '').split('\n');
697
697
  const lines = [];
698
+ const pushHardWrappedToken = (token) => {
699
+ let current = '';
700
+ let columns = 0;
701
+ for (const char of String(token || '')) {
702
+ const charColumns = displayColumns(char);
703
+ if (current && columns + charColumns > maxColumns) {
704
+ lines.push(current);
705
+ current = '';
706
+ columns = 0;
707
+ }
708
+ current += char;
709
+ columns += charColumns;
710
+ }
711
+ if (current) lines.push(current);
712
+ };
698
713
  for (const paragraph of source) {
699
714
  let current = '';
700
715
  let columns = 0;
701
716
  const words = paragraph.includes(' ') ? paragraph.split(/(\s+)/) : [...paragraph];
702
717
  for (const word of words) {
703
718
  const wordColumns = displayColumns(word);
719
+ if (!/^\s+$/.test(word) && wordColumns > maxColumns) {
720
+ if (current) {
721
+ lines.push(current.trimEnd());
722
+ current = '';
723
+ columns = 0;
724
+ }
725
+ pushHardWrappedToken(word);
726
+ continue;
727
+ }
704
728
  if (current && columns + wordColumns > maxColumns) {
705
729
  lines.push(current.trimEnd());
706
730
  current = '';
@@ -742,12 +766,12 @@ function buildRenderItems(messages = []) {
742
766
  }
743
767
 
744
768
  function estimateMessageLayout(message) {
745
- const maxColumns = message.side === 'local' ? 42 : 40;
769
+ const maxColumns = message.side === 'local' ? 36 : 36;
746
770
  const lines = wrapText(message.text, maxColumns);
747
771
  const tagRows = message.tags.length > 0 ? 1 : 0;
748
772
  const textWidth = Math.min(
749
- 440,
750
- Math.max(160, Math.max(...lines.map(displayColumns), 10) * 8 + 34),
773
+ 460,
774
+ Math.max(160, Math.max(...lines.map(displayColumns), 10) * 8.5 + 44),
751
775
  );
752
776
  const height = 24 + lines.length * 20 + tagRows * 25;
753
777
  return {
@@ -853,11 +877,9 @@ function renderSvgPage({ page, header, pageCount }) {
853
877
  parts.push(`<rect class="${bubbleClass}" x="${x}" y="${y + 14}" width="${width}" height="${height}" rx="16"/>`);
854
878
  const textX = x + 17;
855
879
  let textY = y + 40;
856
- parts.push(`<text class="msg" x="${textX}" y="${textY}">`);
857
880
  for (const [index, line] of layout.lines.entries()) {
858
- parts.push(`<tspan x="${textX}" dy="${index === 0 ? 0 : 20}">${escapeXml(line)}</tspan>`);
881
+ parts.push(`<text class="msg" x="${textX}" y="${textY + index * 20}">${escapeXml(line)}</text>`);
859
882
  }
860
- parts.push('</text>');
861
883
  textY += layout.lines.length * 20 + 4;
862
884
  let tagX = textX;
863
885
  for (const tag of message.tags) {
@@ -1043,11 +1065,13 @@ async function writeArtifacts({ workspaceRoot, artifactId, spec, layout }) {
1043
1065
  page: page.page,
1044
1066
  format: 'png',
1045
1067
  path: pngPath,
1068
+ filePath: pngPath,
1069
+ filename: path.basename(pngPath),
1070
+ mimeType: 'image/png',
1046
1071
  width: page.width,
1047
1072
  height: page.height,
1048
1073
  renderer,
1049
1074
  sha256: await hashFile(pngPath),
1050
- mediaRef: `MEDIA:${pngPath}`,
1051
1075
  });
1052
1076
  }
1053
1077
  return {
@@ -1061,6 +1085,19 @@ async function writeArtifacts({ workspaceRoot, artifactId, spec, layout }) {
1061
1085
  };
1062
1086
  }
1063
1087
 
1088
+ function buildOpenClawUploadArgs(page, message = null) {
1089
+ if (!page?.path) return null;
1090
+ return {
1091
+ action: 'upload-file',
1092
+ filePath: page.path,
1093
+ path: page.path,
1094
+ media: page.path,
1095
+ filename: page.filename || path.basename(page.path),
1096
+ mimeType: page.mimeType || 'image/png',
1097
+ ...(message ? { message } : {}),
1098
+ };
1099
+ }
1100
+
1064
1101
  function buildDiagnostics({ sourceRecords, normalizedMessages, renderedMessages, source }) {
1065
1102
  return {
1066
1103
  source: {
@@ -1168,10 +1205,16 @@ export async function renderClaworldTranscriptReport({
1168
1205
  style: params.style,
1169
1206
  artifacts,
1170
1207
  deliveryHint: {
1171
- primaryMedia: artifacts.pngPages[0]?.mediaRef || null,
1172
- primaryMediaBatch: artifacts.pngPages.map((page) => page.mediaRef).join('\n'),
1173
- sourceSvgDocument: artifacts.svgPages[0] ? `[[as_document]]\nMEDIA:${artifacts.svgPages[0].path}` : null,
1174
- openClawMediaPaths: artifacts.pngPages.map((page) => page.path),
1208
+ primaryFilePath: artifacts.pngPages[0]?.path || null,
1209
+ imageFilePaths: artifacts.pngPages.map((page) => page.path),
1210
+ sourceSvgFilePaths: artifacts.svgPages.map((page) => page.path),
1211
+ messageTool: buildOpenClawUploadArgs(
1212
+ artifacts.pngPages[0],
1213
+ source.chatRequestId
1214
+ ? `Claworld transcript report for ${source.chatRequestId}`
1215
+ : 'Claworld transcript report',
1216
+ ),
1217
+ messageToolBatch: artifacts.pngPages.map((page) => buildOpenClawUploadArgs(page)).filter(Boolean),
1175
1218
  },
1176
1219
  diagnostics: buildDiagnostics({
1177
1220
  sourceRecords,