Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 0 additions & 47 deletions .replit

This file was deleted.

Binary file added Assets/Ala-Alab Lettering.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/Ala-Alab Logo.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/Team Logo Clean.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added Assets/Team Logo Worded.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions DEV_PLAN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
- [x] Step 0: Connectivity check complete
- [x] Step 1: /docs subfolders created
- [x] Step 2: Folders moved (or references fixed) into /docs
- [x] Step 3: /docs/README.md written
- [ ] Step 4: root README.md updated
- [ ] Step 5: local smoke test run
33 changes: 33 additions & 0 deletions Google Studio Output 2/LinkManager.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
@import url('https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500;600&display=swap');
@import "tailwindcss";

@theme {
--font-sans: "Plus Jakarta Sans", ui-sans-serif, system-ui, sans-serif;
--font-mono: "JetBrains Mono", ui-monospace, SFMono-Regular, monospace;
}

body {
font-family: var(--font-sans);
background-color: #fafafa;
color: #171717;
overflow-x: hidden;
}

/* Custom scrollbar styling for a cleaner look */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}

::-webkit-scrollbar-track {
background: transparent;
}

::-webkit-scrollbar-thumb {
background: #e5e5e5;
border-radius: 3px;
}

::-webkit-scrollbar-thumb:hover {
background: #d4d4d4;
}
1 change: 1 addition & 0 deletions Google Studio Output 2/PromptBuilder.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
*

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🔴 Critical | ⚡ Quick win

Empty/corrupted component file — content is a single * character.

This isn't valid TypeScript/JSX. Any import of PromptBuilder from elsewhere in the app will fail to compile/parse. Per the stack outline this looks like a stray marker file that landed in the wrong location; the actual PromptBuilder UI (compile/copy/beam) needs to be restored here.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@Google` Studio Output 2/PromptBuilder.tsx at line 1, The PromptBuilder
component file is corrupted and currently contains only a stray marker, so it
cannot be parsed or imported. Restore the full valid TypeScript/JSX
implementation for PromptBuilder, including the compile/copy/beam UI and any
required exports, so references to PromptBuilder resolve correctly. Use the
existing PromptBuilder component name and related UI symbols to replace the
placeholder content with the intended component code.

20 changes: 20 additions & 0 deletions Google Studio Output 2/README (1).md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div align="center">
<img width="1200" height="475" alt="GHBanner" src="https://ai.google.dev/static/site-assets/images/share-ais-513315318.png" />
</div>

# Run and deploy your AI Studio app

This contains everything you need to run your app locally.

View your app in AI Studio: https://ai.studio/apps/bfff2907-a29c-4f47-bbda-75ec49933072

## Run Locally

**Prerequisites:** Node.js


1. Install dependencies:
`npm install`
2. Set the `GEMINI_API_KEY` in [.env.local](.env.local) to your Gemini API key
3. Run the app:
`npm run dev`
240 changes: 240 additions & 0 deletions Google Studio Output 2/SyncedPacketReceiver.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,240 @@
import React, { useState } from 'react';
import { useTabBridge } from './hooks/useTabBridge';
import TabConnector from './components/TabConnector';
import TranscriptParser from './components/TranscriptParser';
import PromptBuilder from './components/PromptBuilder';
import SyncedPacketReceiver from './components/SyncedPacketReceiver';
import SyncHistoryPanel from './components/SyncHistoryPanel';
import LinkManager from './components/LinkManager';
import { ChatSession, SyncPacket } from './types';
import { compilePortablePrompt } from './utils/templates';
import { Sparkles, ArrowRightLeft, HelpCircle, BookOpen, AlertCircle, Laptop, Settings, ArrowRight, Clipboard } from 'lucide-react';

export default function App() {
const {
tabId,
tabName,
setTabName,
tabRole,
setTabRole,
connectedTabs,
incomingPacket,
setIncomingPacket,
beamSession,
sentHistory,
receivedHistory,
clearHistory,
triggerDiscovery,
} = useTabBridge();

const [currentSession, setCurrentSession] = useState<ChatSession | null>(null);
const [showHowTo, setShowHowTo] = useState(true);

// Handle accepting a beamed packet
const handleAcceptPacket = (packet: SyncPacket) => {
setCurrentSession(packet.session);
setIncomingPacket(null);
};

// Handle selecting a history packet
const handleSelectHistoryPacket = (packet: SyncPacket) => {
setCurrentSession(packet.session);
};

return (
<div className="min-h-screen bg-neutral-50/50 flex flex-col selection:bg-neutral-800 selection:text-white">
{/* Header */}
<header className="bg-white border-b border-neutral-100 shrink-0 sticky top-0 z-40 shadow-xs">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-4 flex flex-wrap items-center justify-between gap-4">
<div className="flex items-center gap-3">
<div className="w-10 h-10 rounded-xl bg-neutral-900 flex items-center justify-center text-white font-black tracking-tighter text-lg shadow-sm">
</div>
<div>
<h1 className="text-lg font-black text-neutral-900 tracking-tight flex items-center gap-2">
LLM Chat Bridge
<span className="text-[10px] font-bold bg-neutral-100 text-neutral-600 px-2 py-0.5 rounded-full font-mono uppercase tracking-wider">
v1.2 client-only
</span>
</h1>
<p className="text-xs text-neutral-400 font-medium">
Seamless prompt portability and zero-API cross-tab synchronizer
</p>
</div>
</div>

{/* Network Banner */}
<div className="flex items-center gap-3">
<div className="bg-neutral-50 rounded-lg px-3 py-1.5 border border-neutral-200/60 flex items-center gap-2 text-xs font-semibold text-neutral-600">
<Laptop className="w-4 h-4 text-neutral-400" />
<span>
Tabs Connected:{' '}
<b className="text-neutral-900 font-bold">{connectedTabs.length + 1}</b>
</span>
</div>
</div>
</div>
</header>

{/* Main Workspace Grid */}
<main className="flex-1 max-w-7xl w-full mx-auto px-4 sm:px-6 lg:px-8 py-6 space-y-6">
{/* Onboarding walkthrough */}
{showHowTo && (
<div className="bg-white border border-neutral-200/80 rounded-2xl p-6 shadow-sm relative overflow-hidden">
<div className="absolute top-4 right-4">
<button
onClick={() => setShowHowTo(false)}
className="text-xs text-neutral-400 hover:text-neutral-600 font-semibold cursor-pointer"
>
Dismiss Guide
</button>
</div>
<div className="flex gap-4 items-start max-w-3xl">
<div className="w-10 h-10 rounded-xl bg-indigo-50 flex items-center justify-center shrink-0">
<BookOpen className="w-5 h-5 text-indigo-600" />
</div>
<div className="space-y-2">
<h3 className="font-bold text-neutral-800 text-sm tracking-tight">
Seamless Conversational Portability
</h3>
<p className="text-xs text-neutral-500 leading-relaxed">
Have you ever started a deep conversation in Gemini, only to reach its context limit, and want to continue it directly in Claude (or vice versa) without copy-pasting individual messages manually?
</p>

{/* Visual Steps */}
<div className="grid grid-cols-1 md:grid-cols-3 gap-4 pt-3 text-xs">
<div className="space-y-1">
<p className="font-bold text-neutral-700 flex items-center gap-1">
<span className="w-4 h-4 rounded-full bg-neutral-900 text-white text-[9px] font-mono flex items-center justify-center">1</span>
Copy & Extract
</p>
<p className="text-neutral-400 leading-normal text-[11px]">
Press <kbd className="px-1.5 py-0.5 bg-neutral-100 border border-neutral-200 rounded text-[9px] font-mono">Ctrl+A</kbd> then <kbd className="px-1.5 py-0.5 bg-neutral-100 border border-neutral-200 rounded text-[9px] font-mono">Ctrl+C</kbd> on your Gemini page and paste it into the <b>Parser</b>. We'll strip out all the UI fluff, buttons, and ratings automatically!
</p>
</div>
<div className="space-y-1">
<p className="font-bold text-neutral-700 flex items-center gap-1">
<span className="w-4 h-4 rounded-full bg-neutral-900 text-white text-[9px] font-mono flex items-center justify-center">2</span>
Arrange Tabs
</p>
<p className="text-neutral-400 leading-normal text-[11px]">
Click <b>"Open Second Tab"</b> and position the two tabs side-by-side. Make one the <b>Gemini Companion</b> and the other the <b>Claude Companion</b>.
</p>
</div>
<div className="space-y-1">
<p className="font-bold text-neutral-700 flex items-center gap-1">
<span className="w-4 h-4 rounded-full bg-neutral-900 text-white text-[9px] font-mono flex items-center justify-center">3</span>
Beam Context
</p>
<p className="text-neutral-400 leading-normal text-[11px]">
Press <b>"Beam"</b> on Tab A. Your formatted, ready-to-paste context flies instantly over to Tab B. One-click copy, paste it in Claude, and pick up right where you left off!
</p>
</div>
</div>
</div>
</div>
</div>
)}

<div className="grid grid-cols-1 lg:grid-cols-12 gap-6 items-start">
{/* Left Column: Network & History Settings (3 cols) */}
<div className="lg:col-span-4 space-y-6">
<TabConnector
currentTabId={tabId}
tabName={tabName}
setTabName={setTabName}
tabRole={tabRole}
setTabRole={setTabRole}
connectedTabs={connectedTabs}
triggerDiscovery={triggerDiscovery}
/>

<LinkManager
currentSession={currentSession}
onSessionParsed={(session) => {
setCurrentSession(session);
}}
onCopyPrompt={(templateId = 'continuity') => {
if (!currentSession) return;
const compiled = compilePortablePrompt(
currentSession.messages,
currentSession.source,
templateId
);
navigator.clipboard.writeText(compiled);
}}
/>

<SyncHistoryPanel
sentHistory={sentHistory}
receivedHistory={receivedHistory}
onSelectPacket={handleSelectHistoryPacket}
onClearHistory={clearHistory}
/>

{/* Zero API Architecture Guide */}
<div className="bg-neutral-50/50 rounded-2xl border border-neutral-200/50 p-5 space-y-3">
<h4 className="text-[11px] font-bold text-neutral-400 uppercase tracking-wider flex items-center gap-1.5">
<Settings className="w-3.5 h-3.5" />
Security & Specs
</h4>
<p className="text-[11px] text-neutral-500 leading-relaxed">
This utility operates entirely on <b>client-side sandbox protocols</b> using the HTML5 <b>BroadcastChannel API</b>.
</p>
<ul className="text-[10px] text-neutral-400 space-y-1.5 list-disc list-inside leading-normal">
<li>No server-side data collection or storage</li>
<li>No docker orchestrators, API keys, or databases needed</li>
<li>Your raw prompts and conversations remain completely local</li>
<li>Works offline under standard browser origins</li>
</ul>
</div>
</div>

{/* Right Columns: Parser & Prompt Compiler Workspace (8 cols) */}
<div className="lg:col-span-8 grid grid-cols-1 md:grid-cols-2 gap-6">
{/* Step 1: Parser */}
<div className="md:col-span-1 h-full">
<TranscriptParser
onSessionParsed={setCurrentSession}
currentSession={currentSession}
setCurrentSession={setCurrentSession}
/>
</div>

{/* Step 2: Customizer & Beamer */}
<div className="md:col-span-1 h-full">
<PromptBuilder
session={currentSession}
beamSession={beamSession}
connectedCount={connectedTabs.length}
/>
</div>
</div>
</div>
</main>

{/* Floating Synced packet handler */}
<SyncedPacketReceiver
packet={incomingPacket}
onAccept={handleAcceptPacket}
onDismiss={() => setIncomingPacket(null)}
/>

{/* Footer */}
<footer className="bg-white border-t border-neutral-100 py-6 mt-auto shrink-0">
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 flex flex-col sm:flex-row items-center justify-between gap-4 text-xs font-semibold text-neutral-400">
<p>© 2026 LLM Chat Bridge. Made securely with zero external APIs.</p>
<div className="flex gap-4">
<button
onClick={() => setShowHowTo(true)}
className="hover:text-neutral-600 flex items-center gap-1 cursor-pointer"
>
<HelpCircle className="w-3.5 h-3.5" /> Instructions
</button>
</div>
</div>
</footer>
</div>
);
}

Loading
Loading