[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
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:
2
components/ai/hooks/aiChatStreamingSupport.ts
Normal file
2
components/ai/hooks/aiChatStreamingSupport.ts
Normal file
@@ -0,0 +1,2 @@
|
||||
/** @deprecated Import from `@/infrastructure/ai/aiChatStreamingSupport` instead. */
|
||||
export * from '../../../infrastructure/ai/aiChatStreamingSupport';
|
||||
8
components/ai/hooks/useAIChatStreaming.ts
Normal file
8
components/ai/hooks/useAIChatStreaming.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
/** @deprecated Import from `@/application/state/useAIChatStreaming` instead. */
|
||||
export {
|
||||
useAIChatStreaming,
|
||||
isAIChatSessionStreaming,
|
||||
getNetcattyBridge,
|
||||
type ActiveCompactionUi,
|
||||
type DefaultTargetSessionHint,
|
||||
} from "../../../application/state/useAIChatStreaming";
|
||||
9
components/ai/hooks/useAgentCompactionUi.ts
Normal file
9
components/ai/hooks/useAgentCompactionUi.ts
Normal 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";
|
||||
76
components/ai/hooks/useConversationExport.ts
Normal file
76
components/ai/hooks/useConversationExport.ts
Normal 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,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user