carmoji 0.3.8 → 0.3.9

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.
Files changed (2) hide show
  1. package/carmoji.js +50 -4
  2. package/package.json +1 -1
package/carmoji.js CHANGED
@@ -611,9 +611,50 @@ function sessionTokens(payload) {
611
611
  return state.total;
612
612
  }
613
613
 
614
+ /**
615
+ * The agent's final say for the turn. Hooks never carry assistant text,
616
+ * but Stop hands over transcript_path, and the JSONL's tail holds the
617
+ * reply — Claude records {type:"assistant", message:{content:[{type:
618
+ * "text",text}]}}, Codex rollouts {payload:{type:"agent_message",message}}.
619
+ */
620
+ function lastAssistantText(payload) {
621
+ try {
622
+ const transcript = payload.transcript_path;
623
+ if (!transcript) return undefined;
624
+ const size = statSync(transcript).size;
625
+ const window = Math.min(size, 256 * 1024);
626
+ if (window === 0) return undefined;
627
+ const fd = openSync(transcript, 'r');
628
+ const buffer = Buffer.alloc(window);
629
+ const bytesRead = readSync(fd, buffer, 0, window, size - window);
630
+ closeSync(fd);
631
+ const lines = buffer.subarray(0, bytesRead).toString('utf8').split('\n');
632
+ for (let i = lines.length - 1; i >= 0; i -= 1) {
633
+ const line = lines[i];
634
+ if (!line.includes('"assistant"') && !line.includes('agent_message')) continue;
635
+ try {
636
+ const record = JSON.parse(line);
637
+ if (record.type === 'assistant') {
638
+ const texts = (record.message?.content ?? [])
639
+ .filter((block) => block.type === 'text' && block.text)
640
+ .map((block) => block.text);
641
+ if (texts.length) return texts.join(' ');
642
+ }
643
+ if (record.payload?.type === 'agent_message' && record.payload.message) {
644
+ return String(record.payload.message);
645
+ }
646
+ } catch { /* the window's first line may be cut mid-record */ }
647
+ }
648
+ } catch { /* no transcript, no say */ }
649
+ return undefined;
650
+ }
651
+
614
652
  const TEST_EVENTS = {
615
653
  start: { event: 'session_start' },
616
- prompt: { event: 'prompt' },
654
+ prompt: { event: 'prompt', detail: 'Fix the corner release bug' },
655
+ say: { event: 'turn_done',
656
+ detail: 'Done — corners now release on yaw alone with an 8s cap, '
657
+ + 'and cornerEnded bypasses every gate so the lean never sticks.' },
617
658
  edit: { event: 'tool_start', tool: 'Edit' },
618
659
  read: { event: 'tool_start', tool: 'Read' },
619
660
  run: { event: 'tool_start', tool: 'Bash' },
@@ -1385,15 +1426,20 @@ async function main() {
1385
1426
  // project directory, so fall back to that.
1386
1427
  const cwd = payload.cwd || process.cwd();
1387
1428
  if (cwd) message.project = basename(cwd);
1388
- // A snippet of human-readable context for the phone to show.
1429
+ // A snippet of human-readable context for the phone to show. The
1430
+ // turn's reply gets more room than a toast line — it feeds the
1431
+ // reviewable chat history, not just a caption.
1389
1432
  const detail = event.event === 'prompt'
1390
1433
  ? firstString(payload.prompt, payload.user_prompt, payload.userPrompt,
1391
1434
  payload.message, payload.input, payload.text)
1392
1435
  : event.event === 'permission'
1393
1436
  ? firstString(payload.message, payload.detail,
1394
1437
  payload.tool_input ? summarizeToolInput(payload) : undefined)
1395
- : undefined;
1396
- if (detail) message.detail = String(detail).replace(/\s+/g, ' ').slice(0, 140);
1438
+ : event.event === 'turn_done'
1439
+ ? lastAssistantText(payload)
1440
+ : undefined;
1441
+ const detailCap = event.event === 'turn_done' ? 400 : 140;
1442
+ if (detail) message.detail = String(detail).replace(/\s+/g, ' ').slice(0, detailCap);
1397
1443
  // Plan-window usage comes from Claude Code's local transcripts;
1398
1444
  // recompute only at turn boundaries.
1399
1445
  if (source === 'claude') {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "carmoji",
3
- "version": "0.3.8",
3
+ "version": "0.3.9",
4
4
  "description": "Bring your CarMoji pet to life from Claude Code / Codex — a LAN bridge that streams coding events to the CarMoji iOS app",
5
5
  "type": "module",
6
6
  "bin": {