[Init] Initial commit - NetMesh terminal manager
Some checks failed
build-packages / resolve bundled mosh-client (push) Has been cancelled
build-packages / resolve bundled et-client (push) Has been cancelled
build-packages / build-macos (push) Has been cancelled
build-packages / build-windows (push) Has been cancelled
build-packages / build-linux-x64 (push) Has been cancelled
build-packages / build-linux-arm64 (push) Has been cancelled
build-packages / release (push) Has been cancelled
build-packages / update Nix release metadata (push) Has been cancelled
build-packages / bump homebrew tap (push) Has been cancelled
test / lint-and-test (push) Has been cancelled
AI automation / Route event (push) Has been cancelled
AI automation / Hand reopened issue to maintainers (push) Has been cancelled
AI automation / Clean source issue state (push) Has been cancelled
AI automation / Reconcile handoffs (push) Has been cancelled
AI automation / Classify issue (push) Has been cancelled
AI automation / Claude Code smoke (push) Has been cancelled
AI automation / Review issue follow-up (push) Has been cancelled
AI automation / Publish issue follow-up (push) Has been cancelled
AI automation / Implement with Claude Code (push) Has been cancelled
AI automation / Publish implement PR (push) Has been cancelled
AI automation / Continue queued issue comments (push) Has been cancelled
AI automation / Codex review loop (push) Has been cancelled
AI automation / Publish Codex fix (push) Has been cancelled
AI automation / Clear Codex dispatch marker (push) Has been cancelled
AI automation / Own PR re-request Codex (push) Has been cancelled
AI automation / External PR re-request Codex (push) Has been cancelled
AI automation / Poll Codex reaction / retry (push) Has been cancelled
build-et-binaries / build-linux-x64 (push) Has been cancelled
build-et-binaries / build-linux-arm64 (push) Has been cancelled
build-et-binaries / build-macos-universal (push) Has been cancelled
build-et-binaries / build-windows-x64 (push) Has been cancelled
build-et-binaries / release (push) Has been cancelled

This commit is contained in:
2026-09-13 18:24:01 +08:00
commit 3c72efcb7f
3255 changed files with 907009 additions and 0 deletions

View File

@@ -0,0 +1,2 @@
/** @deprecated Import from `@/infrastructure/ai/aiChatStreamingSupport` instead. */
export * from '../../../infrastructure/ai/aiChatStreamingSupport';

View File

@@ -0,0 +1,8 @@
/** @deprecated Import from `@/application/state/useAIChatStreaming` instead. */
export {
useAIChatStreaming,
isAIChatSessionStreaming,
getNetcattyBridge,
type ActiveCompactionUi,
type DefaultTargetSessionHint,
} from "../../../application/state/useAIChatStreaming";

View File

@@ -0,0 +1,9 @@
/** @deprecated Import from `@/application/state/useAgentCompactionUi` instead. */
export {
useAgentCompactionUi,
useAgentContextUsage,
compactionStatusText,
resolveCompactionStatusText,
type ActiveCompactionUi,
type AgentContextUsage,
} from "../../../application/state/useAgentCompactionUi";

View File

@@ -0,0 +1,76 @@
/**
* useConversationExport — Encapsulates conversation export logic for the AI chat panel.
*
* Handles:
* - Export in markdown, JSON, and plain text formats
* - Object URL lifecycle management (creation, revocation, cleanup on unmount)
*/
import React, { useCallback, useEffect, useRef } from 'react';
import type { AISession } from '../../../infrastructure/ai/types';
import { exportAsMarkdown, exportAsJSON, exportAsPlainText, getExportFilename } from '../../../infrastructure/ai/conversationExport';
// -------------------------------------------------------------------
// Hook return type
// -------------------------------------------------------------------
export interface UseConversationExportReturn {
/** Trigger a download of the active session in the given format. */
handleExport: (format: 'md' | 'json' | 'txt') => void;
/** Ref to active object URLs for cleanup on unmount (exposed for the parent cleanup effect). */
activeObjectUrlsRef: React.MutableRefObject<Set<string>>;
}
// -------------------------------------------------------------------
// Hook implementation
// -------------------------------------------------------------------
export function useConversationExport(
activeSession: AISession | null,
): UseConversationExportReturn {
// Ref to track active object URLs for cleanup on unmount (Issue #19)
const activeObjectUrlsRef = useRef<Set<string>>(new Set());
// Clean up object URLs on unmount
useEffect(() => {
const urls = activeObjectUrlsRef.current;
return () => {
urls.forEach(url => URL.revokeObjectURL(url));
urls.clear();
};
}, []);
const handleExport = useCallback((format: 'md' | 'json' | 'txt') => {
if (!activeSession) return;
let content: string;
switch (format) {
case 'md': content = exportAsMarkdown(activeSession); break;
case 'json': content = exportAsJSON(activeSession); break;
case 'txt': content = exportAsPlainText(activeSession); break;
}
const filename = getExportFilename(activeSession, format);
// Create a download blob
const blob = new Blob([content], { type: 'text/plain;charset=utf-8' });
const url = URL.createObjectURL(blob);
// Track URL for cleanup on unmount (Issue #19)
activeObjectUrlsRef.current.add(url);
const a = document.createElement('a');
a.href = url;
a.download = filename;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
// Revoke after a generous delay to ensure download completes, then remove from tracking set
const revokeTimeout = setTimeout(() => {
URL.revokeObjectURL(url);
activeObjectUrlsRef.current.delete(url);
}, 60_000); // 60 seconds to be safe for large files
// If component unmounts before timeout, cleanup effect will revoke it
void revokeTimeout; // suppress unused warning
}, [activeSession]);
return {
handleExport,
activeObjectUrlsRef,
};
}