feat: Add intelligent auto-router and enhanced integrations

- Add intelligent-router.sh hook for automatic agent routing
- Add AUTO-TRIGGER-SUMMARY.md documentation
- Add FINAL-INTEGRATION-SUMMARY.md documentation
- Complete Prometheus integration (6 commands + 4 tools)
- Complete Dexto integration (12 commands + 5 tools)
- Enhanced Ralph with access to all agents
- Fix /clawd command (removed disable-model-invocation)
- Update hooks.json to v5 with intelligent routing
- 291 total skills now available
- All 21 commands with automatic routing

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
admin
2026-01-28 00:27:56 +04:00
Unverified
parent 3b128ba3bd
commit b52318eeae
1724 changed files with 351216 additions and 0 deletions

View File

@@ -0,0 +1,186 @@
# @dexto/client-sdk
## 1.5.6
### Patch Changes
- 042f4f0: ### CLI Improvements
- Add `/export` command to export conversations as Markdown or JSON
- Add `Ctrl+T` toggle for task list visibility during processing
- Improve task list UI with collapsible view near the processing message
- Fix race condition causing duplicate rendering (mainly visible with explore tool)
- Don't truncate `pattern` and `question` args in tool output display
### Bug Fixes
- Fix build script to preserve `.dexto` storage (conversations, logs) during clean builds
- Fix `@dexto/tools-todo` versioning - add to fixed version group in changeset config
### Configuration Changes
- Remove approval timeout defaults - now waits indefinitely (better UX for CLI)
- Add package versioning guidelines to AGENTS.md
## 1.5.5
## 1.5.4
## 1.5.3
## 1.5.2
## 1.5.1
## 1.5.0
### Minor Changes
- e7722e5: Minor version bump for new release with bundler, custom tool pkgs, etc.
## 1.4.0
## 1.3.0
### Minor Changes
- eb266af: Migrate WebUI from next-js to vite. Fix any typing in web UI. Improve types in core. minor renames in event schemas
## 1.2.6
## 1.2.5
### Patch Changes
- 8f373cc: Migrate server API to Hono framework with feature flag
- Migrated Express server to Hono with OpenAPI schema generation
- Added DEXTO_USE_HONO environment variable flag (default: false for backward compatibility)
- Fixed WebSocket test isolation by adding sessionId filtering
- Fixed logger context to pass structured objects instead of stringified JSON
- Fixed CI workflow for OpenAPI docs synchronization
- Updated documentation links and fixed broken API references
- f28ad7e: Migrate webUI to use client-sdk, add agents.md file to webui,improve types in apis for consumption
- a35a256: Migrate from WebSocket to Server-Sent Events (SSE) for real-time streaming
- Replace WebSocket with SSE for message streaming via new `/api/message-stream` endpoint
- Refactor approval system from event-based providers to simpler handler pattern
- Add new APIs for session approval
- Move session title generation to a separate API
- Add `ApprovalCoordinator` for multi-client SSE routing with sessionId mapping
- Add stream and generate methods to DextoAgent and integ tests for itq=
- 5a26bdf: Update hono server to chain apis to keep type info, update client sdk to be fully typed
- ac649fd: Fix error handling and UI bugs, add gpt-5.1, gemini-3
## 1.2.4
### Patch Changes
- cd706e7: bump up version after fixing node-machine-id
- Updated dependencies [cd706e7]
- @dexto/core@1.2.4
## 1.2.3
### Patch Changes
- 5d6ae73: Bump up version to fix bugs
- Updated dependencies [5d6ae73]
- @dexto/core@1.2.3
## 1.2.2
### Patch Changes
- @dexto/core@1.2.2
## 1.2.1
### Patch Changes
- @dexto/core@1.2.1
## 1.2.0
### Patch Changes
- Updated dependencies [b51e4d9]
- Updated dependencies [a27ddf0]
- Updated dependencies [155813c]
- Updated dependencies [1e25f91]
- Updated dependencies [3a65cde]
- Updated dependencies [5ba5d38]
- Updated dependencies [930a4ca]
- Updated dependencies [ecad345]
- Updated dependencies [930d75a]
- @dexto/core@1.2.0
## 1.1.11
### Patch Changes
- 01167a2: Refactors
- Updated dependencies [c40b675]
- Updated dependencies [015100c]
- Updated dependencies [0760f8a]
- Updated dependencies [5cc6933]
- Updated dependencies [40f89f5]
- Updated dependencies [3a24d08]
- Updated dependencies [01167a2]
- Updated dependencies [a53b87a]
- Updated dependencies [24e5093]
- Updated dependencies [c695e57]
- Updated dependencies [0700f6f]
- Updated dependencies [0a5636c]
- Updated dependencies [35d48c5]
- @dexto/core@1.1.11
## 1.1.10
### Patch Changes
- @dexto/core@1.1.10
## 1.1.9
### Patch Changes
- Updated dependencies [27778ba]
- @dexto/core@1.1.9
## 1.1.8
### Patch Changes
- Updated dependencies [d79d358]
- @dexto/core@1.1.8
## 1.1.7
### Patch Changes
- @dexto/core@1.1.7
## 1.1.6
### Patch Changes
- @dexto/core@1.1.6
## 1.1.5
### Patch Changes
- 795c7f1: feat: Add @dexto/client-sdk package
- New lightweight cross-environment client SDK
- HTTP + optional WebSocket support for messaging
- Streaming and non-streaming message support
- Session management, LLM config/catalog access
- MCP tools integration and search functionality
- Real-time events support
- Comprehensive TypeScript types and validation
- Unit tests and documentation included
- 09b8e33: Fix minor comments
- Updated dependencies [e2bd0ce]
- Updated dependencies [11cbec0]
- Updated dependencies [795c7f1]
- Updated dependencies [9d7541c]
- @dexto/core@1.1.5

View File

@@ -0,0 +1,107 @@
# Dexto Client SDK
An ultra-lightweight, zero-dependency HTTP client SDK for the Dexto API.
## Features
- 🚀 **Ultra-lightweight**: Only 80KB bundle size
- 🔌 **Zero dependencies**: No external libraries
- 🌐 **Universal**: Works in Node.js, browsers, and React Native
- 📡 **HTTP + SSE**: Full REST API and real-time SSE streaming support
- 🛡️ **TypeScript**: Full type safety
- 🔄 **Auto-retry**: Built-in retry logic with exponential backoff
-**Fast**: Server-side validation, client-side pass-through
## Installation
```bash
npm install @dexto/client-sdk
```
## Quick Start
```typescript
import { DextoClient } from '@dexto/client-sdk';
const client = new DextoClient({
baseUrl: 'https://your-dexto-server.com',
apiKey: 'optional-api-key'
});
// Connect to Dexto server
await client.connect();
// Send a message
const response = await client.sendMessage({
content: 'Hello, how can you help me?'
});
console.log(response.response);
```
## Configuration
```typescript
const client = new DextoClient({
baseUrl: 'https://your-dexto-server.com', // Required: Dexto API base URL
apiKey: 'your-api-key', // Optional: API key for auth
timeout: 30000, // Optional: Request timeout (ms)
retries: 3, // Optional: Retry attempts
}, {
reconnect: true, // Optional: Auto-reconnect
reconnectInterval: 5000, // Optional: Reconnect delay (ms)
debug: false // Optional: Debug logging
});
```
## API Methods
### Connection Management
- `connect()` - Establish connection to Dexto server
- `disconnect()` - Close connection
- `isConnected` - Check connection status
### Messaging
- `sendMessage(input)` - Send message (HTTP)
- SSE streaming available via `/api/message-stream` endpoint
### Session Management
- `listSessions()` - List all sessions
- `createSession(id?)` - Create new session
- `getSession(id)` - Get session details
- `deleteSession(id)` - Delete session
### Real-time Events
- `on(eventType, handler)` - Subscribe to Dexto events
- `onConnectionState(handler)` - Connection state changes
## Error Handling
```typescript
try {
await client.sendMessage({ content: 'Hello' });
} catch (error) {
if (error.name === 'ConnectionError') {
console.log('Failed to connect to Dexto server');
} else if (error.name === 'HttpError') {
console.log(`HTTP ${error.status}: ${error.statusText}`);
}
}
```
## Philosophy
This SDK follows the **thin client** philosophy:
-**Pass-through**: Data goes directly to Dexto server
-**Server validation**: Let the Dexto server handle all validation
-**Simple errors**: Return server errors as-is
-**Type safety**: Full TypeScript support
-**Fast**: Minimal client-side processing
## Bundle Size
- **Total**: ~80KB
- **Main bundle**: ~25KB
- **Type definitions**: ~10KB
- **Zero external dependencies**

View File

@@ -0,0 +1,44 @@
{
"name": "@dexto/client-sdk",
"version": "1.5.6",
"private": false,
"type": "module",
"main": "./dist/index.cjs",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js",
"require": "./dist/index.cjs",
"default": "./dist/index.js"
},
"./package.json": "./package.json"
},
"dependencies": {
"hono": "^4.6.14"
},
"devDependencies": {
"@dexto/core": "workspace:*",
"@dexto/server": "workspace:*",
"tsup": "^8.0.2",
"typescript": "^5.4.2",
"vitest": "^1.3.1"
},
"scripts": {
"build": "tsup && tsc -p tsconfig.json --emitDeclarationOnly",
"dev": "tsup --watch",
"typecheck": "tsc -p tsconfig.typecheck.json --noEmit",
"lint": "eslint . --ext .ts,.tsx",
"test": "vitest run",
"test:watch": "vitest watch"
},
"files": [
"dist",
"README.md"
],
"publishConfig": {
"access": "public"
},
"sideEffects": false
}

View File

@@ -0,0 +1,99 @@
import { hc } from 'hono/client';
import type { AppType } from '@dexto/server';
import type { ClientConfig } from './types.js';
/**
* Create a type-safe Dexto client using Hono's typed client
*
* @example
* ```typescript
* import { createDextoClient } from '@dexto/client-sdk';
*
* const client = createDextoClient({
* baseUrl: 'http://localhost:3001',
* apiKey: 'optional-api-key'
* });
*
* // Create a session
* const session = await client.api.sessions.$post({
* json: { sessionId: 'my-session' }
* });
*
* // Send a synchronous message
* const response = await client.api['message-sync'].$post({
* json: { message: 'Hello!', sessionId: 'my-session' }
* });
* const { response: text } = await response.json();
*
* // Search messages
* const searchResults = await client.api.search.messages.$get({
* query: { q: 'hello', limit: 10 }
* });
*
* // Streaming responses with SSE
* import { createMessageStream } from '@dexto/client-sdk';
*
* const streamPromise = client.api['message-stream'].$post({
* json: { message: 'Tell me a story', sessionId: 'my-session' }
* });
*
* // Parse SSE events using createMessageStream
* const stream = createMessageStream(streamPromise);
* for await (const event of stream) {
* if (event.name === 'llm:chunk') {
* process.stdout.write(event.content);
* }
* }
* ```
*/
export function createDextoClient(config: ClientConfig) {
const options: { headers?: Record<string, string> } = {};
if (config.apiKey) {
options.headers = {
Authorization: `Bearer ${config.apiKey}`,
};
}
return hc<AppType>(config.baseUrl, options);
}
export * from './streaming.js';
// AGENTS DO NOT DELETE THE BELOW COMMENTS
// Uncomment for testing autofill in IDE
// const client1 = hc<AppType>('http://localhost:3001');
// let response1 = await client1.api.search.sessions.$get({
// query: {
// q: "poop"
// }
// })
// const client2 = createDextoClient({
// baseUrl: 'http://localhost:3001',
// apiKey: 'optional-api-key'
// })
// let response2 = await client2.api.sessions.$post({
// json: {
// sessionId: 'session-123'
// }
// })
// const body2 = await response2.json();
// console.log(body2.session.id);
// let response3 = await client2.health.$get();
// console.log(response3.ok);
// import { createMessageStream } from './streaming.js';
// let response4 = client2.api['message-stream'].$post({
// json: {
// message: 'Tell me a story',
// sessionId: 'my-session'
// }
// });
// const stream = createMessageStream(response4);
// for await (const event of stream) {
// if (event.type === 'llm:chunk') {
// process.stdout.write(event.content);
// }
// }

View File

@@ -0,0 +1,17 @@
/**
* Dexto Client SDK
* Lightweight type-safe client for Dexto API built on Hono's typed client
*/
// Core client
export { createDextoClient } from './client.js';
// SSE streaming
export { stream, createStream, createMessageStream, SSEError } from './streaming.js';
export type { SSEEvent, MessageStreamEvent } from './streaming.js';
// Client configuration
export type { ClientConfig } from './types.js';
// Server types for advanced usage
export type { AppType } from '@dexto/server';

View File

@@ -0,0 +1,197 @@
import type { StreamingEvent } from '@dexto/core';
/**
* SSE (Server-Sent Events) streaming utilities for client SDK
* Adapted from @dexto/webui EventStreamClient
*/
export type MessageStreamEvent = StreamingEvent;
export interface SSEEvent<T = string> {
event?: string;
data?: T;
id?: string;
retry?: number;
}
export class SSEError extends Error {
constructor(
public status: number,
public body: any
) {
super(`SSE Error: ${status}`);
this.name = 'SSEError';
}
}
/**
* Creates an async generator that yields SSE events from a Response object.
*
* @param response The fetch Response object containing the SSE stream
* @param options Optional configuration including AbortSignal
*/
export async function* stream<T = string>(
response: Response,
options?: { signal?: AbortSignal }
): AsyncGenerator<SSEEvent<T>> {
if (!response.ok) {
const contentType = response.headers.get('content-type');
let errorBody;
try {
if (contentType && contentType.includes('application/json')) {
errorBody = await response.json();
} else {
errorBody = await response.text();
}
} catch {
errorBody = 'Unknown error';
}
throw new SSEError(response.status, errorBody);
}
const reader = response.body?.getReader();
if (!reader) {
throw new Error('Response body is null');
}
const decoder = new globalThis.TextDecoder();
let buffer = '';
const signal = options?.signal;
// Handle abort signal
let aborted = false;
const abortHandler = () => {
aborted = true;
reader.cancel().catch(() => {
// Ignore errors during cancel
});
};
if (signal) {
if (signal.aborted) {
reader.cancel().catch(() => {});
return;
}
signal.addEventListener('abort', abortHandler);
}
try {
while (true) {
if (aborted || signal?.aborted) {
return;
}
// Check if we have a double newline in buffer
const parts = buffer.split('\n\n');
if (parts.length > 1) {
const eventString = parts.shift()!;
buffer = parts.join('\n\n');
const event = parseSSE(eventString);
if (event) {
yield event as SSEEvent<T>;
}
continue;
}
// Need more data
const { done, value } = await reader.read();
if (done) {
if (buffer.trim()) {
const event = parseSSE(buffer);
if (event) {
yield event as SSEEvent<T>;
}
}
return;
}
// Normalize CRLF to LF for spec-compliance
buffer += decoder.decode(value, { stream: true }).replace(/\r\n/g, '\n');
}
} finally {
if (signal) {
signal.removeEventListener('abort', abortHandler);
}
reader.cancel().catch(() => {});
}
}
/**
* Helper to create a stream from a promise that resolves to a Response.
* Useful for chaining with Hono client requests.
*
* @example
* ```typescript
* const stream = createStream(client.api.chat.$post({ json: { message: 'hi' } }));
* for await (const event of stream) { ... }
* ```
*/
export async function* createStream<T = string>(
responsePromise: Promise<Response>,
options?: { signal?: AbortSignal }
): AsyncGenerator<SSEEvent<T>> {
const response = await responsePromise;
yield* stream<T>(response, options);
}
/**
* Helper to create a typed message stream from a promise that resolves to a Response.
* Automatically parses JSON data and yields typed MessageStreamEvent objects.
*
* @example
* ```typescript
* const stream = createMessageStream(client.api['message-stream'].$post({ ... }));
* for await (const event of stream) {
* if (event.name === 'llm:chunk') {
* console.log(event.content);
* }
* }
* ```
*/
export async function* createMessageStream(
responsePromise: Promise<Response>,
options?: { signal?: AbortSignal }
): AsyncGenerator<MessageStreamEvent> {
const sseStream = createStream(responsePromise, options);
for await (const event of sseStream) {
if (event.data) {
try {
const parsed = JSON.parse(event.data);
// SSE event name becomes the 'name' discriminant for StreamingEvent
// Using 'name' (not 'type') to avoid collision with payload fields
if (event.event) {
parsed.name = event.event;
}
yield parsed as MessageStreamEvent;
} catch {
// Ignore parse errors for non-JSON data
}
}
}
}
function parseSSE(raw: string): SSEEvent<string> | null {
const lines = raw.split('\n').map((line) => line.replace(/\r$/, ''));
const event: SSEEvent<string> = {};
let hasData = false;
for (const line of lines) {
if (line.startsWith(':')) continue; // Comment
if (line.startsWith('data: ')) {
const data = line.slice(6);
event.data = event.data ? event.data + '\n' + data : data;
hasData = true;
} else if (line.startsWith('event: ')) {
event.event = line.slice(7);
} else if (line.startsWith('id: ')) {
event.id = line.slice(4);
} else if (line.startsWith('retry: ')) {
event.retry = parseInt(line.slice(7), 10);
}
}
if (!hasData && !event.event && !event.id) return null;
return event;
}

View File

@@ -0,0 +1,9 @@
/**
* Client configuration for Dexto SDK
*/
export interface ClientConfig {
/** Base URL of the Dexto server */
baseUrl: string;
/** Optional API key for authentication */
apiKey?: string;
}

View File

@@ -0,0 +1,22 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"baseUrl": ".",
"rootDir": "src",
"outDir": "dist",
"noEmit": false,
"declaration": true,
"declarationMap": true,
"emitDeclarationOnly": false
},
"include": [
"src/**/*"
],
"exclude": [
"**/*.test.ts",
"**/*.spec.ts",
"**/*.integration.test.ts",
"dist",
"node_modules"
]
}

View File

@@ -0,0 +1,4 @@
{
"extends": "./tsconfig.json",
"exclude": ["dist", "node_modules"]
}

View File

@@ -0,0 +1,17 @@
import { defineConfig } from 'tsup';
export default defineConfig({
entry: ['src/index.ts'],
format: ['cjs', 'esm'],
outDir: 'dist',
dts: false, // Disable DTS generation in tsup to avoid worker memory issues
shims: true,
bundle: true,
platform: 'neutral',
target: 'es2018',
minify: false,
splitting: false,
treeshake: false,
clean: true,
sourcemap: false,
});

View File

@@ -0,0 +1,7 @@
import { defineConfig } from 'vitest/config';
export default defineConfig({
test: {
environment: 'node',
},
});