Skip to content
Open
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
68 changes: 68 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,71 @@ tsconfig.tsbuildinfo
.trash/*
mcp-superassistant-proxy/bun.lock
# pnpm-lock.yaml

# Cache and temporary files
.cache
**/.cache
**/tmp
**/temp
**/*.log
**/*.log.*
**/.vibesync
**/.vibesync/*

# IDE and editor files
.vscode
.idea
*.swp
*.swo
*~
.project
.settings
.classpath
*.sublime-workspace
*.sublime-project

# Debug files
**/*.debug
**/*.debug.*
**/debug.log
**/npm-debug.log*
**/yarn-debug.log*
**/yarn-error.log*
**/pnpm-debug.log*

# OS generated files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db

# Build artifacts
**/*.tsbuildinfo
**/*.js.map
**/*.d.ts.map
**/.turbo
**/dist
**/build
**/.next
**/.nuxt
**/.output

# Local development
.env.local
.env.development.local
.env.test.local
.env.production.local

# Package manager files
.pnpm-store
.npm
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions
.pnp.*
6 changes: 6 additions & 0 deletions bash-scripts/copy_env.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Check if .env does not exist and .example.env exists
if (!(Test-Path ".env") -and (Test-Path ".example.env")) {
# Copy .example.env to .env
Copy-Item ".example.env" -Destination ".env"
Write-Host ".example.env has been copied to .env"
}
91 changes: 91 additions & 0 deletions bash-scripts/set_global_env.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
# Default values
$CLI_CEB_DEV = $false
$CLI_CEB_FIREFOX = $false
$cli_values = @()

function Validate-IsBoolean {
param (
[string]$value,
[string]$name
)
if ($value -ne "true" -and $value -ne "false") {
Write-Error "Invalid value for <$name>. Please use 'true' or 'false'."
exit 1
}
}

function Validate-Key {
param (
[string]$key,
[bool]$isEditableSection = $false
)
if ($key -and -not $key.StartsWith("#")) {
if ($isEditableSection -and -not $key.StartsWith("CEB_")) {
Write-Error "Invalid key: <$key>. All keys in the editable section must start with 'CEB_'."
exit 1
}
elseif (-not $isEditableSection -and -not $key.StartsWith("CLI_CEB_")) {
Write-Error "Invalid key: <$key>. All CLI keys must start with 'CLI_CEB_'."
exit 1
}
}
}

function Parse-Arguments {
param (
[string[]]$args
)
foreach ($arg in $args) {
$key = $arg.Split('=')[0]
$value = $arg.Split('=')[1]

Validate-Key $key

switch ($key) {
"CLI_CEB_DEV" {
$script:CLI_CEB_DEV = $value
Validate-IsBoolean $CLI_CEB_DEV "CLI_CEB_DEV"
}
"CLI_CEB_FIREFOX" {
$script:CLI_CEB_FIREFOX = $value
Validate-IsBoolean $CLI_CEB_FIREFOX "CLI_CEB_FIREFOX"
}
default {
$script:cli_values += "$key=$value"
}
}
}
}

function Validate-EnvKeys {
$editableSectionStarts = $false
Get-Content .env | ForEach-Object {
$key = $_.Split('=')[0]
if ($key -match "^CLI_CEB_") {
$editableSectionStarts = $true
}
elseif ($editableSectionStarts) {
Validate-Key $key $true
}
}
}

function Create-NewFile {
$tempFile = New-TemporaryFile
@"
# THOSE VALUES ARE EDITABLE ONLY VIA CLI
CLI_CEB_DEV=$CLI_CEB_DEV
CLI_CEB_FIREFOX=$CLI_CEB_FIREFOX
$($cli_values -join "`n")

# THOSE VALUES ARE EDITABLE
$((Get-Content .env | Where-Object { $_ -match '^CEB_' }) -join "`n")
"@ | Set-Content $tempFile -NoNewline

Move-Item $tempFile .env -Force
}

# Main script execution
Parse-Arguments $args
Validate-EnvKeys
Create-NewFile
24 changes: 24 additions & 0 deletions bash-scripts/update_version.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Usage: ./update_version.ps1 <new_version>
# FORMAT IS <0.0.0>

param(
[Parameter(Mandatory=$true)]
[string]$NewVersion
)

if ($NewVersion -match '^\d+\.\d+\.\d+$') {
Get-ChildItem -Path . -Filter 'package.json' -Recurse -File |
Where-Object { $_.FullName -notmatch 'node_modules' } |
ForEach-Object {
$content = Get-Content $_.FullName -Raw
if ($content -match '"version":\s*"([^"]*)"') {
$currentVersion = $matches[1]
$content = $content -replace [regex]::Escape($currentVersion), $NewVersion
Set-Content -Path $_.FullName -Value $content -NoNewline
}
}
Write-Host "Updated versions to $NewVersion"
}
else {
Write-Error "Version format <$NewVersion> isn't correct, proper format is <0.0.0>"
}
10 changes: 10 additions & 0 deletions chrome-extension/manifest.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,11 @@ const manifest = {
'*://*.aistudio.google.com/*',
'*://*.openrouter.ai/*',
'*://*.google-analytics.com/*',

'*://*.agenthustle.ai/*',

'*://*.chat.deepseek.com/*',

],

permissions: ['storage', 'clipboardWrite'],
Expand Down Expand Up @@ -107,9 +111,15 @@ const manifest = {
js: ['content/index.iife.js'],
run_at: 'document_idle',
},

// Specific content script for AgentHustle tool call parsing
{
matches: ['*://*.agenthustle.ai/*'],

// Specific content script for DeepSeek tool call parsing
{
matches: ['*://*.chat.deepseek.com/*'],

js: ['content/index.iife.js'],
run_at: 'document_idle',
},
Expand Down
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@
"lint:fix": "turbo lint:fix --continue -- --fix --cache --cache-location node_modules/.cache/.eslintcache",
"prettier": "turbo prettier --continue -- --cache --cache-location node_modules/.cache/.prettiercache",
"prepare": "husky",
"update-version": "bash bash-scripts/update_version.sh",
"copy_env": "bash bash-scripts/copy_env.sh",
"set-global-env": "bash bash-scripts/set_global_env.sh",
"update-version": "pwsh bash-scripts/update_version.ps1",
"copy_env": "pwsh bash-scripts/copy_env.ps1",
"set-global-env": "pwsh bash-scripts/set_global_env.ps1",
"postinstall": "pnpm build:eslint && pnpm copy_env",
"module-manager": "pnpm -F module-manager start"
},
Expand Down
34 changes: 34 additions & 0 deletions pages/content/src/adapters/adapterRegistry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,18 @@ class AdapterRegistryImpl implements AdapterRegistry {
// Register a new adapter
registerAdapter(adapter: SiteAdapter): void {
const hostnames = Array.isArray(adapter.hostname) ? adapter.hostname : [adapter.hostname];
if (!hostnames.length) {
logMessage('Cannot register adapter: no hostnames provided');
return;
}

for (const hostname of hostnames) {
if (this.adapters.has(hostname)) {
logMessage(`Adapter for hostname ${hostname} already registered, replacing...`);
}

this.adapters.set(hostname, adapter);
logMessage(`Registered adapter for hostname: ${hostname}`);
}

// Clear the cache when a new adapter is registered
Expand Down Expand Up @@ -102,6 +111,31 @@ class AdapterRegistryImpl implements AdapterRegistry {

return undefined;
}

// Get all registered adapters
getAllAdapters(): SiteAdapter[] {
// Use Set to deduplicate adapters that might be registered for multiple hostnames
return Array.from(new Set(this.adapters.values()));
}

// Check if an adapter is registered for a hostname
hasAdapter(hostname: string): boolean {
return this.adapters.has(hostname);
}

// Remove an adapter by hostname
removeAdapter(hostname: string): void {
if (this.adapters.has(hostname)) {
this.adapters.delete(hostname);
logMessage(`Removed adapter for hostname: ${hostname}`);
}
}

// Clear all registered adapters
clearAdapters(): void {
this.adapters.clear();
logMessage('Cleared all registered adapters');
}
}

// Singleton instance of the adapter registry
Expand Down
74 changes: 74 additions & 0 deletions pages/content/src/adapters/adaptercomponents/agenthustle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* AgentHustle Adapter Components
*
* This file contains the AgentHustle-specific adapter components and configuration.
*/

import { logMessage } from '../../utils/helpers';
import type { AdapterConfig } from './common';
import { initializeAdapter } from './common';

// --- DOM Element Finders ---

function findAgentHustleButtonInsertionPoint(): Element | null {
// Find the chat input container to insert the MCP toggle button
const chatInput = document.querySelector('input.flex-1.rounded-lg.border.border-border.bg-card');
if (chatInput) {
return chatInput.parentElement;
}
return null;
}

// --- Event Handlers ---

function onAgentHustleMCPEnabled(adapter: any): void {
logMessage('MCP enabled for AgentHustle');
if (adapter?.sidebarManager?.show) {
adapter.sidebarManager.show();
}
}

function onAgentHustleMCPDisabled(adapter: any): void {
logMessage('MCP disabled for AgentHustle');
if (adapter?.sidebarManager?.hide) {
adapter.sidebarManager.hide();
}
}

function getAgentHustleURLKey(): string {
// Generate a unique key for the current URL state
// This helps track state across different chat sessions
return window.location.pathname;
}

// --- Adapter Configuration ---

const agentHustleAdapterConfig: AdapterConfig = {
adapterName: 'AgentHustle',
storageKeyPrefix: 'mcp-agenthustle-state',
findButtonInsertionPoint: findAgentHustleButtonInsertionPoint,
getStorage: () => localStorage,
getCurrentURLKey: getAgentHustleURLKey,
onMCPEnabled: onAgentHustleMCPEnabled,
onMCPDisabled: onAgentHustleMCPDisabled
};

// --- Initialization ---

export function initAgentHustleComponents(): void {
logMessage('Initializing AgentHustle MCP components');
const stateManager = initializeAdapter(agentHustleAdapterConfig);

// Expose manual injection for debugging
(window as any).injectMCPButtons_AgentHustle = () => {
logMessage('Manual injection for AgentHustle triggered');
const insertFn = (window as any)[`injectMCPButtons_${agentHustleAdapterConfig.adapterName}`];
if (insertFn) {
insertFn();
} else {
logMessage('Manual injection function not found for AgentHustle');
}
};

logMessage('AgentHustle MCP components initialization complete');
}
Loading