Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
e56435b
Add Vite + Signals foundation for incremental widget migration
Jan 6, 2026
27363d5
Fix executable permissions on all shell scripts
Jan 6, 2026
bdfc8bd
converted room list to use vite signals
Jan 6, 2026
fc34e9b
configs
Jan 6, 2026
5969107
Convert widget CSS to SCSS for Positron migration
Jan 6, 2026
e38a1d0
Enable bundle minification for faster load times
Jan 7, 2026
9a0282c
fix tab performance issue
Jan 7, 2026
3630adb
signal based widgets
Jan 7, 2026
edb728a
significant widget speed improvements
Jan 7, 2026
fbd4ab9
significant log improvement
Jan 7, 2026
117d5e6
Remove TypeScript fallback from vector search - Rust only
Jan 7, 2026
74db478
Bundle CLI for 4x faster startup (0.6s vs 2.6s CPU time)
Jan 7, 2026
0ca051a
Eliminate redundant command discovery on CLI connect
Jan 7, 2026
67c9482
less logging
Jan 7, 2026
a65e29f
cleanup of warnings, bad types
Jan 7, 2026
9995156
reduced logging
Jan 7, 2026
bccedb3
much reduced logging
Jan 7, 2026
d0306e0
lots of warnings
Jan 7, 2026
6df28d9
faster
Jan 7, 2026
fed6eaa
substantially faster
Jan 7, 2026
ab9739c
fixes for speed
Jan 7, 2026
9a4662f
shared entity stuff
Jan 7, 2026
a13644f
room list widget seems ok
Jan 8, 2026
a3cc7a7
fix infinite loop issue
Jan 8, 2026
edeb394
user list works
Jan 8, 2026
c8b0086
sql count issues
Jan 8, 2026
c6acf31
cleaning up event emission bs
Jan 8, 2026
b4f0f93
fixing memory issues
Jan 8, 2026
4bafee5
Fix chat memory leaks + restore avatar animation
Jan 8, 2026
ede29be
dynamic widget sidebar ok
Jan 8, 2026
db4f5f3
fix all widgets
Jan 8, 2026
d37ee50
scroller updates
Jan 8, 2026
b9e0f09
remove synchronous write
Jan 8, 2026
cf8be24
more async stuff
Jan 8, 2026
f6e7d6f
Move AsyncStorage.ts from widgets/ to system/ - fix layering violation
Jan 8, 2026
27b65ba
lora docs
Jan 8, 2026
02f2368
fix tab naming
Jan 8, 2026
5ecbb4f
tab naming
Jan 8, 2026
d5accc0
Migrate all localStorage to non-blocking asyncStorage
Jan 9, 2026
748b3ee
Convert SettingsWidget from BaseWidget to ReactiveWidget
Jan 9, 2026
c9e7883
Conversion of outer containers to reactive elements plan
Jan 9, 2026
720da4b
Convert RightPanelWidget and PersonaBrainWidget to ReactiveWidget
Jan 9, 2026
07e34e7
Add PersonaBrainWidget caching + Convert ContentTabsWidget to Reactiv…
Jan 9, 2026
eef98d5
Convert 5 more widgets to ReactiveWidget pattern
Jan 10, 2026
fdae6c3
Convert CognitionHistogram + Enhance Metrics with 2x2 grid
Jan 10, 2026
bf0f2ae
Fix ContinuumMetricsWidget sparkline rendering and add smart time range
Jan 10, 2026
551c848
Remove orphaned cognition-histogram widget and unused templates
Jan 10, 2026
0bc67d5
Fix performance and sidebar layout issues
Jan 10, 2026
82545c0
Give rooms less flex priority than users & agents
Jan 10, 2026
506d7bc
Add reactive scroll-to-selected for room list
Jan 10, 2026
617ae1e
Add shouldAddEntity filtering to ReactiveListWidget base class
Jan 10, 2026
a542437
Replace user list search with filter chips
Jan 10, 2026
3083b5b
Improve filter chip organization and hover labels
Jan 10, 2026
56223dc
Fix filter chip active state and label visibility
Jan 10, 2026
76a8184
Fix filter chips to actually filter the user list
Jan 10, 2026
4c91d64
Add widget technical debt documentation and PR description
Jan 10, 2026
a567543
Refactor ChatWidget to use DOM APIs instead of innerHTML
Jan 10, 2026
f97dead
soething fixed
Jan 10, 2026
6557ef8
Fix BaseWidget to render instantly with loading state (React pattern)
Jan 10, 2026
66c80c9
Add optimistic updates for opening new content tabs
Jan 10, 2026
61a03fb
Add optimistic tab creation for room selection
Jan 10, 2026
5781267
Revert sidebar optimistic tab creation - was breaking content sync
Jan 10, 2026
308c9ab
Fix RoomListWidget selection not updating on tab switch
Jan 10, 2026
7a8c77d
Fix URL not updating on tab switch - use uniqueId for URLs
Jan 10, 2026
c8d342b
Fix URL not updating on tab click - add URL updates to ContentTabsWidget
Jan 10, 2026
890941f
Centralize content/tab/URL logic and fix event message persistence
Jan 10, 2026
4f23f46
Add EntityCacheService as single source of truth for entity data
Jan 10, 2026
1a07588
Add recipe awareness and cache-first routing (Phases 4-5)
Jan 10, 2026
31e325a
Fix instant tab creation and prevent tab flickering
Jan 10, 2026
e1202d5
Add circuit breaker and instant hydration for responsive UI
Jan 11, 2026
07480fe
Fix stale chat when switching back to same room
Jan 11, 2026
ad6d20b
Add useCollection/useEntity data hooks to ReactiveWidget
Jan 11, 2026
7b0e89e
Fix widget-loading centering by adding :host styles
Jan 11, 2026
2a12481
Add humanMessage priority scoring to ai/should-respond-fast
Jan 11, 2026
c53082b
Update generated schema with senderType parameter
Jan 11, 2026
d3e0460
Remove dead code ChatMessageCache.ts
Jan 11, 2026
cafea0b
Address Copilot review feedback
Jan 11, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
Empty file modified src/debug/jtag/.continuum/genome/python/bootstrap.sh
100644 → 100755
Empty file.
Empty file modified src/debug/jtag/.continuum/genome/python/train-wrapper.sh
100644 → 100755
Empty file.
Empty file modified src/debug/jtag/backups/backup-legacy-continuum.sh
100644 → 100755
Empty file.
Empty file modified src/debug/jtag/backups/cleanup-legacy-continuum.sh
100644 → 100755
Empty file.
Empty file modified src/debug/jtag/backups/migrate-persona-logs.sh
100644 → 100755
Empty file.
28 changes: 10 additions & 18 deletions src/debug/jtag/browser-index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,49 +26,37 @@ import { WidgetDiscovery } from './system/core/browser/utils/WidgetIntrospection
export const jtag = {
// Widget debugging utilities
widgets: WidgetUtils,

// Universal client interface - always returns connection result with client property
async connect(): Promise<ReturnType<typeof JTAGClientBrowser.connectLocal>> {
// Reduce log spam
// console.debug('🔌 Browser: Connecting via JTAGClientBrowser (local connection)');

// Connect client FIRST
// Connect client FIRST - widgets need it for resource loading
const connectionResult = await JTAGClientBrowser.connectLocal();
const client = connectionResult.client;

// Set up global window.jtag for widgets and tests
(globalThis as any).jtag = client;

// Expose WidgetDiscovery for universal selector support (used by GlobalUtils.safeQuerySelector)
// Expose WidgetDiscovery for universal selector support
(globalThis as any).WidgetDiscovery = WidgetDiscovery;

// Register client in static registry for sharedInstance access
JTAGClient.registerClient('default', client);

// NOW register widgets - after client is available for sharedInstance
// console.debug(`🎭 Registering ${BROWSER_WIDGETS.length} widgets...`);
// NOW register widgets - after client is available for resource loading
BROWSER_WIDGETS.forEach(widget => {
if (!customElements.get(widget.tagName)) {
try {
customElements.define(widget.tagName, widget.widgetClass);
// console.debug(`✅ Registered widget: ${widget.tagName} (${widget.className})`);
} catch (error) {
console.warn(`⚠️ Failed to register widget ${widget.tagName}: ${error}`);
console.warn(`⚠️ This usually means the constructor has already been used with this registry`);
console.warn(`⚠️ Skipping registration for ${widget.tagName}`);
}
} else {
console.warn(`⚠️ Widget ${widget.tagName} already registered, skipping`);
}
});

// Enhance client with organized services - no globals needed
// Enhance client with organized services
const services = createJTAGClientServices(client);
Object.assign(client, services);




return { ...connectionResult, client };
},

Expand All @@ -81,4 +69,8 @@ export const jtag = {
// Direct export for advanced usage
export { JTAGSystemBrowser };
export * from './system/core/types/JTAGTypes';
export * from './commands/interface/screenshot/shared/browser-utils/BrowserElementUtils';
export * from './commands/interface/screenshot/shared/browser-utils/BrowserElementUtils';

// Set jtag on globalThis immediately for non-module scripts
// This allows inline scripts to call jtag.connect() without waiting for imports
(globalThis as any).jtag = jtag;
9 changes: 1 addition & 8 deletions src/debug/jtag/browser/generated.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/**
* Browser Structure Registry - Auto-generated
*
* Contains 11 daemons and 139 commands and 2 adapters and 26 widgets.
* Contains 11 daemons and 139 commands and 2 adapters and 25 widgets.
* Generated by scripts/generate-structure.ts - DO NOT EDIT MANUALLY
*/

Expand Down Expand Up @@ -167,7 +167,6 @@ import { WebSocketTransportClientBrowser } from './../system/transports/websocke
import { ChatWidget } from './../widgets/chat/chat-widget/ChatWidget';
import { RoomListWidget } from './../widgets/chat/room-list/RoomListWidget';
import { UserListWidget } from './../widgets/chat/user-list/UserListWidget';
import { CognitionHistogramWidget } from './../widgets/cognition-histogram/CognitionHistogramWidget';
import { ContentTabsWidget } from './../widgets/content-tabs/ContentTabsWidget';
import { ContinuumEmoterWidget } from './../widgets/continuum-emoter/ContinuumEmoterWidget';
import { ContinuumMetricsWidget } from './../widgets/continuum-metrics/ContinuumMetricsWidget';
Expand Down Expand Up @@ -994,12 +993,6 @@ export const BROWSER_WIDGETS: WidgetEntry[] = [
widgetClass: UserListWidget,
tagName: 'UserList'.replace(/([A-Z])/g, (match, p1, offset) => offset > 0 ? '-' + p1.toLowerCase() : p1.toLowerCase()) + '-widget'
},
{
name: 'CognitionHistogram',
className: 'CognitionHistogramWidget',
widgetClass: CognitionHistogramWidget,
tagName: 'CognitionHistogram'.replace(/([A-Z])/g, (match, p1, offset) => offset > 0 ? '-' + p1.toLowerCase() : p1.toLowerCase()) + '-widget'
},
{
name: 'ContentTabs',
className: 'ContentTabsWidget',
Expand Down
4 changes: 2 additions & 2 deletions src/debug/jtag/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import * as path from 'path';

// Check for verbose flag EARLY to control module initialization logging
if (process.argv.includes('--verbose')) {
process.env.JTAG_VERBOSE = 'true';
process.env.JTAG_VERBOSE = '1';
}

// CRITICAL: Initialize SecretManager to load config.env into process.env SYNCHRONOUSLY
Expand Down Expand Up @@ -269,7 +269,7 @@ async function main() {

// Set environment variable for modules to check verbose mode
if (behavior.logLevel === 'verbose') {
process.env.JTAG_VERBOSE = 'true';
process.env.JTAG_VERBOSE = '1';
}

// Suppress ALL output unless verbose mode
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export class AdapterTestServerCommand extends CommandBase<AdapterTestParams, Asy
};

// Save to database using data/create command
const createResult = await Commands.execute<DataCreateParams<TestExecutionEntity>, DataCreateResult>(DATA_COMMANDS.CREATE, {
const createResult = await Commands.execute<DataCreateParams, DataCreateResult>(DATA_COMMANDS.CREATE, {
collection: TestExecutionEntity.collection,
data: execution,
id: testId,
Expand Down Expand Up @@ -160,7 +160,7 @@ export class AdapterTestServerCommand extends CommandBase<AdapterTestParams, Asy
* Helper to update test status in database
*/
private async updateTestStatus(testId: string, updates: Partial<TestExecutionEntity>): Promise<void> {
await Commands.execute<DataUpdateParams<TestExecutionEntity>, CommandResult>(DATA_COMMANDS.UPDATE, {
await Commands.execute<DataUpdateParams, CommandResult>(DATA_COMMANDS.UPDATE, {
collection: TestExecutionEntity.collection,
id: testId,
data: {
Expand Down
4 changes: 2 additions & 2 deletions src/debug/jtag/commands/ai/cost/server/AICostServerCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ export class AICostServerCommand extends AICostCommand {
}

// Query AIGenerationEntity from database using data/list - let SQL do the filtering
const listParams = createDataListParams<AIGenerationEntity>(
const listParams = createDataListParams(
params.context,
params.sessionId,
{
Expand All @@ -52,7 +52,7 @@ export class AICostServerCommand extends AICostCommand {
}
);

const listResult = await Commands.execute<DataListParams<AIGenerationEntity>, DataListResult<AIGenerationEntity>>(
const listResult = await Commands.execute<DataListParams, DataListResult<AIGenerationEntity>>(
DATA_COMMANDS.LIST,
listParams
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export class DatasetCreateServerCommand {
};

// Save to database
const createResult = await Commands.execute<DataCreateParams<DatasetExecutionEntity>, DataCreateResultType>(DATA_COMMANDS.CREATE, {
const createResult = await Commands.execute<DataCreateParams, DataCreateResultType>(DATA_COMMANDS.CREATE, {
collection: DatasetExecutionEntity.collection,
data: execution,
id: jobId,
Expand Down Expand Up @@ -193,7 +193,7 @@ export class DatasetCreateServerCommand {
* Update job status in database
*/
private async updateJobStatus(jobId: string, updates: Partial<DatasetExecutionEntity>): Promise<void> {
await Commands.execute<DataUpdateParams<DatasetExecutionEntity>, any>(DATA_COMMANDS.UPDATE, {
await Commands.execute<DataUpdateParams, any>(DATA_COMMANDS.UPDATE, {
collection: DatasetExecutionEntity.collection,
id: jobId,
data: updates,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export class AiDetectSemanticLoopServerCommand extends CommandBase<AiDetectSeman

let recentMessages: RawChatMessage[];
try {
const result = await Commands.execute<DataListParams<BaseEntity>, DataListResult<BaseEntity>>('data/list', {
const result = await Commands.execute<DataListParams, DataListResult<BaseEntity>>('data/list', {
collection: 'chat_messages',
filter,
limit: lookbackCount,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ export class DecisionReportServerCommand extends CommandBase<DecisionReportParam
console.log(`🔍 SERVER: Querying decisions with filter:`, filter);

// Execute data/list command
const listResult = await Commands.execute<DataListParams<CoordinationDecisionEntity>, DataListResult<CoordinationDecisionEntity>>(
const listResult = await Commands.execute<DataListParams, DataListResult<CoordinationDecisionEntity>>(
DATA_COMMANDS.LIST,
{
collection: COLLECTIONS.COORDINATION_DECISIONS,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,15 @@ export class ShouldRespondFastBrowserCommand extends ShouldRespondFastCommand {
conversationContext: 0,
isQuestion: 0,
unansweredQuestion: 0,
roomActivity: 0
roomActivity: 0,
humanMessage: 0
},
signals: {
wasMentioned: false,
matchedKeywords: [],
isQuestion: false,
recentlyActive: false
recentlyActive: false,
isHumanMessage: false
},
reasoning: 'Command not available in browser'
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -95,13 +95,15 @@ export class ShouldRespondFastServerCommand extends ShouldRespondFastCommand {
conversationContext: 0,
isQuestion: 0,
unansweredQuestion: 0,
roomActivity: 0
roomActivity: 0,
humanMessage: 0
},
signals: {
wasMentioned: false,
matchedKeywords: [],
isQuestion: false,
recentlyActive: false
recentlyActive: false,
isHumanMessage: false
},
reasoning: 'Error occurred during evaluation'
};
Expand Down Expand Up @@ -149,14 +151,16 @@ export class ShouldRespondFastServerCommand extends ShouldRespondFastCommand {
conversationContext: 0,
isQuestion: 0,
unansweredQuestion: 0,
roomActivity: 0
roomActivity: 0,
humanMessage: 0
};

const signals = {
wasMentioned: false,
matchedKeywords: [] as string[],
isQuestion: false,
recentlyActive: false
recentlyActive: false,
isHumanMessage: false
};

// 1. Direct mention detection
Expand Down Expand Up @@ -209,14 +213,25 @@ export class ShouldRespondFastServerCommand extends ShouldRespondFastCommand {
console.log(`📈 High room activity: ${roomActivity} messages in 5min`);
}

// 6. Human message detection - humans deserve responses!
// senderType passed from caller OR detected from senderId lookup
const isHumanMessage = params.senderType === 'human' ||
(!params.senderType && await this.isHumanSender(params.senderId));
if (isHumanMessage) {
scoreBreakdown.humanMessage = config.weights.humanMessage;
signals.isHumanMessage = true;
console.log(`👤 Message is from HUMAN - priority boost!`);
}

// Calculate total score
const score =
scoreBreakdown.directMention +
scoreBreakdown.domainKeywords +
scoreBreakdown.conversationContext +
scoreBreakdown.isQuestion +
scoreBreakdown.unansweredQuestion +
scoreBreakdown.roomActivity;
scoreBreakdown.roomActivity +
scoreBreakdown.humanMessage;

return { score, scoreBreakdown, signals };
}
Expand Down Expand Up @@ -316,6 +331,35 @@ export class ShouldRespondFastServerCommand extends ShouldRespondFastCommand {
}
}

/**
* Check if sender is a human (not AI persona, agent, or system)
*/
private async isHumanSender(senderId: string): Promise<boolean> {
if (!senderId) return false;

try {
const result = await Commands.execute<DataListParams, DataListResult<any>>(DATA_COMMANDS.LIST, {
collection: 'users',
filter: { id: senderId },
limit: 1
});

if (result.success && result.items && result.items.length > 0) {
const user = result.items[0];
const userType = user.userType || user.type || '';
// Human types: 'human', 'owner', 'admin', 'user' (or empty - default is human)
const isHuman = ['human', 'owner', 'admin', 'user', ''].includes(userType.toLowerCase());
return isHuman;
}

// If can't find user, assume not human (safer for AI response filtering)
return false;
} catch (error) {
console.warn('⚠️ Failed to check sender type:', error);
return false;
}
}

/**
* Build result object
*/
Expand All @@ -341,13 +385,15 @@ export class ShouldRespondFastServerCommand extends ShouldRespondFastCommand {
conversationContext: 0,
isQuestion: 0,
unansweredQuestion: 0,
roomActivity: 0
roomActivity: 0,
humanMessage: 0
},
signals: extra.signals ?? {
wasMentioned: false,
matchedKeywords: [],
isQuestion: false,
recentlyActive: false
recentlyActive: false,
isHumanMessage: false
},
reasoning: extra.reasoning
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ export interface ResponseScoringWeights {

/** High activity in room recently (deprecated, default: 0) */
readonly roomActivity: number;

/** Message from human (not AI) - humans should get responses (default: 25) */
readonly humanMessage: number;
}

/**
Expand Down Expand Up @@ -74,6 +77,7 @@ export interface ShouldRespondFastParams extends CommandParams {
/** Sender information */
readonly senderId: UUID;
readonly senderName: string;
readonly senderType?: 'human' | 'persona' | 'agent' | 'system';

/** Optional: Override default config */
readonly config?: Partial<PersonaResponseConfig>;
Expand All @@ -100,6 +104,7 @@ export interface ShouldRespondFastResult extends CommandResult {
isQuestion: number;
unansweredQuestion: number;
roomActivity: number;
humanMessage: number;
};

/** Detected signals */
Expand All @@ -108,6 +113,7 @@ export interface ShouldRespondFastResult extends CommandResult {
matchedKeywords: string[];
isQuestion: boolean;
recentlyActive: boolean;
isHumanMessage: boolean;
};

/** Why this decision was made */
Expand All @@ -129,17 +135,19 @@ export const DEFAULT_SCORING_WEIGHTS: ResponseScoringWeights = {
conversationContext: 20, // Reduced from 30 - thread continuation
isQuestion: 10, // Reduced from 20 - question signal
unansweredQuestion: 5, // New: someone should answer, but who?
roomActivity: 0 // Disabled: was 5, caused noise
roomActivity: 0, // Disabled: was 5, caused noise
humanMessage: 25 // NEW: Humans deserve responses! AI-to-AI can be lower priority
};

/**
* Default response threshold
*
* With new weights:
* - Direct mention: 100 → Always respond
* - Human question: 25 + 10 + 5 = 40 → Respond (humans deserve attention!)
* - Domain + context: 25 + 20 = 45 → Respond (engaged expert)
* - Domain + question: 25 + 10 = 35 → Maybe respond (borderline)
* - Just question: 10 → Don't respond (let experts handle it)
* - AI question: 10 + 5 = 15 → Don't respond (let others handle AI chatter)
* - Random message: 0 → Never respond
*/
export const DEFAULT_RESPONSE_THRESHOLD = 35;
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class CanvasStrokeAddServerCommand extends CommandBase<CanvasStrokeAddPar
private async notifyCanvasRoom(stroke: CanvasStrokeEntity, params: CanvasStrokeAddParams): Promise<void> {
try {
// Find the canvas room
const roomResult = await Commands.execute<DataListParams<RoomEntity>, DataListResult<RoomEntity>>(
const roomResult = await Commands.execute<DataListParams, DataListResult<RoomEntity>>(
DATA_COMMANDS.LIST,
{
collection: RoomEntity.collection,
Expand Down Expand Up @@ -169,7 +169,7 @@ export class CanvasStrokeAddServerCommand extends CommandBase<CanvasStrokeAddPar
};

// Store message
await Commands.execute<DataCreateParams<ChatMessageEntity>, DataCreateResult<ChatMessageEntity>>(
await Commands.execute<DataCreateParams, DataCreateResult<ChatMessageEntity>>(
DATA_COMMANDS.CREATE,
{
collection: ChatMessageEntity.collection,
Expand Down
Loading
Loading