neko-harness 0.3.1 → 0.3.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.
@@ -9,8 +9,8 @@
9
9
  href="data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 100 100'%3E%3Crect width='100' height='100' rx='26' fill='%23ffb7c5'/%3E%3Ctext x='50' y='70' font-size='58' text-anchor='middle' fill='%23ffffff' font-family='sans-serif' font-weight='bold'%3En%3C/text%3E%3C/svg%3E"
10
10
  />
11
11
  <title>neko harness</title>
12
- <script type="module" crossorigin src="/assets/index-O88LHrzD.js"></script>
13
- <link rel="stylesheet" crossorigin href="/assets/index-BTHbU-2p.css">
12
+ <script type="module" crossorigin src="/assets/index-Dz-jYu0K.js"></script>
13
+ <link rel="stylesheet" crossorigin href="/assets/index-DhW2urBC.css">
14
14
  </head>
15
15
  <body>
16
16
  <div id="root"></div>
package/dist/gateway.js CHANGED
@@ -560,6 +560,53 @@ function toolResultText(content) {
560
560
  return content.filter((block) => block.type === "text" && typeof block.text === "string").map((block) => block.text ?? "").join(`
561
561
  `);
562
562
  }
563
+ var WRITE_DIFF_MAX_LINES = 2000;
564
+ var WRITE_DIFF_MAX_BYTES = 64 * 1024;
565
+ function countDiffLines(diff) {
566
+ let added = 0;
567
+ let removed = 0;
568
+ for (const line of diff.split(`
569
+ `)) {
570
+ if (line.startsWith("+") && !line.startsWith("+++"))
571
+ added++;
572
+ else if (line.startsWith("-") && !line.startsWith("---"))
573
+ removed++;
574
+ }
575
+ return { added, removed };
576
+ }
577
+ function editResultDiff(details) {
578
+ if (typeof details !== "object" || details === null)
579
+ return null;
580
+ const diff = details.diff;
581
+ return typeof diff === "string" ? diff : null;
582
+ }
583
+ function synthesizedWriteDiff(args) {
584
+ const record = args ?? {};
585
+ if (typeof record.content !== "string")
586
+ return null;
587
+ const content = record.content;
588
+ const shown = [];
589
+ let offset = 0;
590
+ let bytes = 0;
591
+ while (offset < content.length && shown.length < WRITE_DIFF_MAX_LINES) {
592
+ const newline = content.indexOf(`
593
+ `, offset);
594
+ const end = newline === -1 ? content.length : newline;
595
+ const overhead = shown.length === 0 ? 2 : 3;
596
+ const remaining = WRITE_DIFF_MAX_BYTES - bytes - overhead;
597
+ if (end - offset > remaining)
598
+ break;
599
+ const line = content.slice(offset, end);
600
+ const lineBytes = Buffer.byteLength(line, "utf8");
601
+ if (lineBytes > remaining)
602
+ break;
603
+ shown.push(`+ ${line}`);
604
+ bytes += lineBytes + overhead;
605
+ offset = newline === -1 ? content.length : end + 1;
606
+ }
607
+ return { diff: shown.join(`
608
+ `), added: shown.length, removed: 0, truncated: offset < content.length };
609
+ }
563
610
  function totalUsage(state) {
564
611
  const total = {
565
612
  input: 0,
@@ -592,6 +639,8 @@ function projectChatView(view, modelLabel, options = {}) {
592
639
  if (message.role !== "toolResult")
593
640
  continue;
594
641
  const diagnostics = entry.data?.diagnostics ?? [];
642
+ const diff = message.toolName === "edit" ? editResultDiff(message.details) : null;
643
+ const counts = diff === null ? null : countDiffLines(diff);
595
644
  results.set(message.toolCallId, {
596
645
  type: "tool",
597
646
  key: `t${message.toolCallId}`,
@@ -608,7 +657,10 @@ function projectChatView(view, modelLabel, options = {}) {
608
657
  ].filter(Boolean).join(`
609
658
  `),
610
659
  durationMs: message.durationMs ?? null,
611
- note: null
660
+ note: null,
661
+ diff,
662
+ diffAdded: counts?.added ?? null,
663
+ diffRemoved: counts?.removed ?? null
612
664
  });
613
665
  }
614
666
  }
@@ -666,6 +718,7 @@ function projectChatView(view, modelLabel, options = {}) {
666
718
  } else {
667
719
  const summary = summarizeToolCall(block.name, block.arguments);
668
720
  const slot = live.tools?.find((s) => s.callId === block.id);
721
+ const synthesized = block.name === "write" ? synthesizedWriteDiff(block.arguments) : null;
669
722
  items.push({
670
723
  type: "tool",
671
724
  key: `t${block.id}`,
@@ -678,7 +731,11 @@ function projectChatView(view, modelLabel, options = {}) {
678
731
  output: slot?.output ?? null,
679
732
  result: null,
680
733
  durationMs: null,
681
- note: ran ? null : "Not run: response interrupted."
734
+ note: ran ? null : "Not run: response interrupted.",
735
+ diff: synthesized?.diff ?? null,
736
+ diffAdded: synthesized?.added ?? null,
737
+ diffRemoved: synthesized?.removed ?? null,
738
+ diffTruncated: synthesized?.truncated ?? false
682
739
  });
683
740
  }
684
741
  }
@@ -726,7 +783,17 @@ function projectChatView(view, modelLabel, options = {}) {
726
783
  }
727
784
  function withArgs(item, name, args) {
728
785
  const summary = summarizeToolCall(name, args);
729
- return { ...item, name, summary: summary.args, detail: summary.detail ?? null };
786
+ const synthesized = name === "write" ? synthesizedWriteDiff(args) : null;
787
+ return {
788
+ ...item,
789
+ name,
790
+ summary: summary.args,
791
+ detail: summary.detail ?? null,
792
+ diff: synthesized?.diff ?? item.diff,
793
+ diffAdded: synthesized?.added ?? item.diffAdded,
794
+ diffRemoved: synthesized?.removed ?? item.diffRemoved,
795
+ diffTruncated: synthesized?.truncated ?? false
796
+ };
730
797
  }
731
798
  function assistantItem(message, id) {
732
799
  let thinking = "";
@@ -779,13 +846,18 @@ ${block.text}`;
779
846
  if (block.type === "toolCall") {
780
847
  const slot = live.tools?.find((candidate) => candidate.callId === block.id);
781
848
  const summary = summarizeToolCall(block.name, block.arguments);
849
+ const synthesized = block.name === "write" ? synthesizedWriteDiff(block.arguments) : null;
782
850
  toolCalls.push({
783
851
  callId: block.id,
784
852
  name: block.name,
785
853
  summary: summary.args,
786
854
  detail: summary.detail ?? null,
787
855
  phase: slot === undefined || slot.status === "pending" ? "pending" : slot.status,
788
- output: slot?.status === "running" ? slot.output ?? null : null
856
+ output: slot?.status === "running" ? slot.output ?? null : null,
857
+ diff: synthesized?.diff ?? null,
858
+ diffAdded: synthesized?.added ?? null,
859
+ diffRemoved: synthesized?.removed ?? null,
860
+ diffTruncated: synthesized?.truncated ?? false
789
861
  });
790
862
  }
791
863
  }
@@ -3687,7 +3759,7 @@ import { dirname as dirname5, join as join7 } from "path";
3687
3759
  import { fileURLToPath as fileURLToPath2 } from "url";
3688
3760
 
3689
3761
  // packages/core/src/application-version.ts
3690
- var RUNNING_VERSION = "0.3.1";
3762
+ var RUNNING_VERSION = "0.3.2";
3691
3763
  var APPLICATION_PROTOCOL = 4;
3692
3764
  function stableVersion(value) {
3693
3765
  return typeof value === "string" && /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.test(value) && value.split(".").every((n) => Number.isSafeInteger(Number(n)));
@@ -3881,7 +3953,11 @@ var call = Type4.Object({
3881
3953
  summary: str,
3882
3954
  detail: nullableString,
3883
3955
  phase,
3884
- output: nullableString
3956
+ output: nullableString,
3957
+ diff: nullableString,
3958
+ diffAdded: Type4.Union([num, nil]),
3959
+ diffRemoved: Type4.Union([num, nil]),
3960
+ diffTruncated: Type4.Optional(bool)
3885
3961
  });
3886
3962
  var DelegationSchema = Type4.Object({
3887
3963
  parentId: integer,
@@ -3989,7 +4065,11 @@ var ChatViewSchema = Type4.Object({
3989
4065
  output: nullableString,
3990
4066
  result: nullableString,
3991
4067
  durationMs: Type4.Union([num, nil]),
3992
- note: nullableString
4068
+ note: nullableString,
4069
+ diff: nullableString,
4070
+ diffAdded: Type4.Union([num, nil]),
4071
+ diffRemoved: Type4.Union([num, nil]),
4072
+ diffTruncated: Type4.Optional(bool)
3993
4073
  }),
3994
4074
  Type4.Object({ type: Type4.Literal("system"), order: Type4.Optional(num), key: str, id: integer, text: str })
3995
4075
  ])),