muuuuse 3.3.6 → 3.3.8

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/package.json +1 -1
  2. package/src/agents.js +78 -18
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "muuuuse",
3
- "version": "3.3.6",
3
+ "version": "3.3.8",
4
4
  "description": "🔌Muuuuse arms regular terminals and relays assistant output across signed terminal links.",
5
5
  "type": "commonjs",
6
6
  "bin": {
package/src/agents.js CHANGED
@@ -716,10 +716,20 @@ function readGeminiCandidate(filePath) {
716
716
  }
717
717
  }
718
718
 
719
- function selectGeminiSessionFile(currentPath, processStartedAtMs, options = {}) {
719
+ function rankGeminiCandidates(candidates) {
720
+ return candidates
721
+ .slice()
722
+ .sort((left, right) => (
723
+ (right.lastUpdatedMs || right.mtimeMs || 0) - (left.lastUpdatedMs || left.mtimeMs || 0) ||
724
+ (right.mtimeMs || 0) - (left.mtimeMs || 0) ||
725
+ (right.startedAtMs || 0) - (left.startedAtMs || 0) ||
726
+ left.path.localeCompare(right.path)
727
+ ));
728
+ }
729
+
730
+ function selectGeminiSessionFileFromRoots(currentPath, processStartedAtMs, roots, options = {}, fallbackMode = "strict") {
720
731
  const projectHash = createHash("sha256").update(currentPath).digest("hex");
721
- const geminiRoots = getGeminiRoots(currentPath, options);
722
- const liveCandidates = geminiRoots
732
+ const liveCandidates = roots
723
733
  .flatMap((rootPath) => readOpenSessionCandidates(options.pids ?? options.pid, rootPath, readGeminiCandidate))
724
734
  .filter((candidate) => candidate.projectHash === projectHash);
725
735
  const livePath = selectLiveSessionCandidatePath(liveCandidates, projectHash, options.captureSinceMs);
@@ -727,41 +737,91 @@ function selectGeminiSessionFile(currentPath, processStartedAtMs, options = {})
727
737
  return livePath;
728
738
  }
729
739
 
730
- const candidates = geminiRoots
740
+ const candidates = roots
731
741
  .flatMap((rootPath) => walkFiles(rootPath, (filePath) => filePath.endsWith(".json")))
732
742
  .map((filePath) => readGeminiCandidate(filePath))
733
743
  .filter((candidate) => candidate !== null && candidate.projectHash === projectHash);
734
744
 
745
+ if (fallbackMode === "latest") {
746
+ return rankGeminiCandidates(candidates)[0]?.path || null;
747
+ }
748
+
735
749
  return selectSessionCandidatePath(candidates, projectHash, processStartedAtMs);
736
750
  }
737
751
 
738
- function readGeminiAnswers(filePath, lastMessageId = null, sinceMs = null) {
752
+ function selectGeminiSessionFile(currentPath, processStartedAtMs, options = {}) {
753
+ const geminiRoots = getGeminiRoots(currentPath, options);
754
+ const seatId = Number.parseInt(String(options.seatId || "").trim(), 10);
755
+
756
+ if (Number.isInteger(seatId) && seatId > 0 && geminiRoots.length > 0) {
757
+ const seatLocalPath = selectGeminiSessionFileFromRoots(
758
+ currentPath,
759
+ processStartedAtMs,
760
+ [geminiRoots[0]],
761
+ options,
762
+ "latest"
763
+ );
764
+ if (seatLocalPath) {
765
+ return seatLocalPath;
766
+ }
767
+ }
768
+
769
+ const fallbackRoots = Number.isInteger(seatId) && seatId > 0
770
+ ? geminiRoots.slice(1)
771
+ : geminiRoots;
772
+ return selectGeminiSessionFileFromRoots(currentPath, processStartedAtMs, fallbackRoots, options);
773
+ }
774
+
775
+ function parseGeminiMessage(message, options = {}) {
776
+ const flowMode = options.flowMode === true;
777
+ if (!message || message.type !== "gemini" || typeof message.content !== "string") {
778
+ return null;
779
+ }
780
+
781
+ const text = sanitizeRelayText(message.content);
782
+ if (!text) {
783
+ return null;
784
+ }
785
+
786
+ const toolCalls = Array.isArray(message.toolCalls) ? message.toolCalls : [];
787
+ const phase = toolCalls.length > 0 ? "commentary" : "final_answer";
788
+ if (phase === "commentary" && !flowMode) {
789
+ return null;
790
+ }
791
+
792
+ return {
793
+ id: message.id || hashText(JSON.stringify(message)),
794
+ text,
795
+ phase,
796
+ timestamp: message.timestamp || new Date().toISOString(),
797
+ };
798
+ }
799
+
800
+ function readGeminiAnswers(filePath, lastMessageId = null, sinceMs = null, options = {}) {
739
801
  try {
740
802
  const entry = JSON.parse(fs.readFileSync(filePath, "utf8"));
741
803
  const messages = Array.isArray(entry.messages) ? entry.messages : [];
742
- const finalMessages = messages.filter((message) => {
743
- const toolCalls = Array.isArray(message.toolCalls) ? message.toolCalls : [];
744
- return message.type === "gemini" && typeof message.content === "string" && message.content.trim() && toolCalls.length === 0;
745
- });
746
804
 
747
805
  let startIndex = 0;
748
806
  if (lastMessageId) {
749
- const previousIndex = finalMessages.findIndex((message) => message.id === lastMessageId);
750
- startIndex = previousIndex === -1 ? finalMessages.length : previousIndex + 1;
807
+ const previousIndex = messages.findIndex((message) => message?.id === lastMessageId);
808
+ startIndex = previousIndex === -1 ? 0 : previousIndex + 1;
751
809
  }
752
810
 
753
- const answers = finalMessages.slice(startIndex).map((message) => ({
754
- id: message.id || hashText(JSON.stringify(message)),
755
- text: sanitizeRelayText(message.content),
756
- phase: "final_answer",
757
- timestamp: message.timestamp || entry.lastUpdated || new Date().toISOString(),
758
- }));
811
+ const answers = messages
812
+ .slice(startIndex)
813
+ .map((message) => parseGeminiMessage(message, options))
814
+ .filter((answer) => answer !== null);
815
+
816
+ const lastSeenMessage = [...messages]
817
+ .reverse()
818
+ .find((message) => typeof message?.id === "string" && message.id.trim());
759
819
 
760
820
  return {
761
821
  answers: answers
762
822
  .filter((answer) => answer.text.length > 0)
763
823
  .filter((answer) => isAnswerNewEnough(answer, sinceMs)),
764
- lastMessageId: finalMessages.length > 0 ? finalMessages[finalMessages.length - 1].id : lastMessageId,
824
+ lastMessageId: lastSeenMessage?.id || lastMessageId,
765
825
  fileSize: getFileSize(filePath),
766
826
  };
767
827
  } catch {