Documentation
¶
Overview ¶
Package command provides built-in command definitions for the remote control bot.
PairingManager and related types live in imbot/security so that any imbot application can reuse the TOFU pairing mechanism independently of the remote-control service. The aliases below keep existing code in this package unchanged.
Index ¶
- Constants
- Variables
- func BuildBindConfirmPrompt(proposedPath string) string
- func BuildCustomPathPrompt() string
- func BuildFooter(agentType, projectPath string) string
- func EnsureContext(t testing.TB) context.Context
- func ExpandPath(path string) (string, error)
- func GetAgentDisplayName(agentType string) string
- func GetAgentIcon(agentType string) string
- func RegisterBuiltinCommands(registry *imbot.CommandRegistry, botHandler BotHandlerAdapter) error
- func ShortenID(id string, maxLen int) string
- func ShortenPath(path string) string
- func ValidateProjectPath(path string) error
- type AgentExecutor
- type AgentRouter
- func (r *AgentRouter) Execute(ctx context.Context, agentType agentboot.AgentType, req ExecutionRequest) (*ExecutionResult, error)
- func (r *AgentRouter) GetExecutor(agentType agentboot.AgentType) (AgentExecutor, bool)
- func (r *AgentRouter) ListExecutors() []agentboot.AgentType
- func (r *AgentRouter) RegisterExecutor(executor AgentExecutor)
- type BotHandler
- func (h *BotHandler) GetCommandRegistry() *imbot.CommandRegistry
- func (h *BotHandler) GetVerbose(chatID string) bool
- func (h *BotHandler) HandleCommandViaRegistry(hCtx HandlerContext, cmdName string, args []string) error
- func (h *BotHandler) HandleMessage(msg imbot.Message, platform imbot.Platform, botUUID string)
- func (h *BotHandler) InitCommandRegistry() error
- func (h *BotHandler) RequestConfirmation(ctx context.Context, hCtx HandlerContext, message, requestID string) (bool, error)
- func (h *BotHandler) RequestInteraction(ctx context.Context, hCtx HandlerContext, req imbot.InteractionRequest) (*imbot.InteractionResponse, error)
- func (h *BotHandler) RequestOptionSelection(ctx context.Context, hCtx HandlerContext, message, requestID string, ...) (int, *imbot.Interaction, error)
- func (h *BotHandler) SendFile(ctx context.Context, hCtx HandlerContext, filePath, caption string) error
- func (h *BotHandler) SendText(hCtx HandlerContext, text string)
- func (h *BotHandler) SetVerbose(chatID string, verbose bool)
- func (h *BotHandler) VerifyAndPair(botUUID, chatID, senderID, platform, code string) error
- type BotHandlerAdapter
- type BotSetting
- type Chat
- type ChatStoreInterface
- type ChatStoreJSON
- func (s *ChatStoreJSON) AddToWhitelist(chatID, platform, addedBy string) error
- func (s *ChatStoreJSON) BindProject(chatID, platform, projectPath, ownerID string) error
- func (s *ChatStoreJSON) ClearPaired(chatID string) error
- func (s *ChatStoreJSON) Close() error
- func (s *ChatStoreJSON) GetAgentState(chatID string) ([]byte, error)
- func (s *ChatStoreJSON) GetBashCwd(chatID string) (string, bool, error)
- func (s *ChatStoreJSON) GetChat(chatID string) (*Chat, error)
- func (s *ChatStoreJSON) GetCurrentAgent(chatID string) (string, error)
- func (s *ChatStoreJSON) GetOrCreateChat(chatID, platform string) (*Chat, error)
- func (s *ChatStoreJSON) GetProjectPath(chatID string) (string, bool, error)
- func (s *ChatStoreJSON) IsChatPaired(chatID, botUUID string) bool
- func (s *ChatStoreJSON) IsWhitelisted(chatID string) bool
- func (s *ChatStoreJSON) ListChatsByOwner(ownerID, platform string) ([]*Chat, error)
- func (s *ChatStoreJSON) ListWhitelistedGroups() ([]struct{ ... }, error)
- func (s *ChatStoreJSON) RemoveFromWhitelist(chatID string) error
- func (s *ChatStoreJSON) SetAgentState(chatID string, state []byte) error
- func (s *ChatStoreJSON) SetBashCwd(chatID, cwd string) error
- func (s *ChatStoreJSON) SetCurrentAgent(chatID, platform, agentType string) error
- func (s *ChatStoreJSON) SetPaired(chatID, platform, botUUID, senderID string) error
- func (s *ChatStoreJSON) UpdateChat(chatID string, fn func(*Chat)) error
- func (s *ChatStoreJSON) UpsertChat(chat *Chat) error
- type ClaudeCodeExecutor
- type ExecutionRequest
- type ExecutionResult
- type ExecutorDependencies
- type FileStore
- func (s *FileStore) DownloadFile(ctx context.Context, projectPath, url, mimeType string) (*StoredFile, error)
- func (s *FileStore) GetDownloadDir(projectPath string) string
- func (s *FileStore) IsAllowedSize(mimeType string, size int64) bool
- func (s *FileStore) IsAllowedType(mimeType string) bool
- func (s *FileStore) SetTelegramToken(token string)
- func (s *FileStore) StoreFile(ctx context.Context, projectPath string, reader io.Reader, ...) (*StoredFile, error)
- type HandlerContext
- type Lifecycle
- type Manager
- func (m *Manager) AuditLogger() *audit.Logger
- func (m *Manager) ChatStore() (ChatStoreInterface, error)
- func (m *Manager) IsRunning(uuid string) bool
- func (m *Manager) PairingManager() *PairingManager
- func (m *Manager) SetChannelRegistry(reg *channel.Registry)
- func (m *Manager) SetDataPath(dataPath string)
- func (m *Manager) SetTBClient(tbClient tbclient.TBClient)
- func (m *Manager) Start(parentCtx context.Context, uuid string) error
- func (m *Manager) StartEnabled(ctx context.Context) error
- func (m *Manager) StartEnabledStopDisabled(ctx context.Context) error
- func (m *Manager) Stop(uuid string)
- func (m *Manager) StopAll()
- func (m *Manager) Sync(ctx context.Context) error
- func (m *Manager) WaitForStop(uuid string, timeout time.Duration) bool
- type OutputBehavior
- type PairingManager
- type PairingManagerOption
- type PendingBind
- type PreparedRequest
- type ResponseMeta
- type SessionInfo
- type SessionManager
- type SettingsStore
- type SmartGuideCompletionCallback
- type SmartGuideExecutor
- type SmartGuideSessionStore
- type StoredFile
- type TBClient
- type TelegramFile
- type TestBootOptions
- type TestHarness
Constants ¶
const ( DefaultMaxImageSize = 25 * 1024 * 1024 // 25MB DefaultMaxDocSize = 50 * 1024 * 1024 // 50MB )
const ( // Icons IconProject = "📁" // Project/folder IconChat = "💬" // Chat/conversation IconUser = "👤" // User IconSession = "🔄" // Session IconAgentTB = "🎯" // Tingly-Box agent (@tb) IconAgentCC = "💬" // Claude Code agent (@cc) IconDone = "✅" // Task completed IconError = "❌" // Error IconWarning = "⚠️" // Warning IconStop = "🛑" // Stopped IconProcess = "⏳" // Processing IconMock = "🧪" // Mock agent )
Output format constants for bot messages Centralized for easy customization and i18n support
const ( AgentNameTB = "@tb" // Tingly-Box short name AgentNameCC = "@cc" // Claude Code short name AgentNameTinglyBox = "tingly-box" AgentNameClaude = "claude" )
Agent display names
const ( SeparatorLine = "───────────────" SeparatorFull = "━━━━━━━━━━━━━━━━━━━━" )
Separator line for message formatting
const ( MsgProcessing = "Processing..." MsgTaskDone = "Task done" MsgTaskStopped = "Task stopped" MsgContinueOrHelp = "Continue or /help." MsgNoRunningTask = "No running task to stop." )
Status messages
const ( // Status line formats FormatProjectLine = "%s %s\n" // icon + path FormatAgentLine = "%s %s\n" // icon + agent name FormatDebugLine = "%s %s\n" // icon + id value FormatFooter = "\n%s\n%s %s\n📁 %s" // separator + icon + agent + path )
Format templates (use with fmt.Sprintf)
Variables ¶
var ( ErrStoreNotInitialized = errors.New("chat store not initialized") ErrChatNotFound = errors.New("chat not found") )
Error definitions
var ( ErrPairCodeMissing = security.ErrPairCodeMissing ErrPairCodeExpired = security.ErrPairCodeExpired ErrPairCodeMismatch = security.ErrPairCodeMismatch ErrPairLocked = security.ErrPairLocked )
Error sentinels forwarded from imbot/security.
var ( NewPairingManager = security.NewPairingManager WithPairingTTL = security.WithPairingTTL WithPairingCodeLen = security.WithPairingCodeLength WithPairingMaxFails = security.WithPairingMaxFails WithPairingLockout = security.WithPairingLockout WithPairingRand = security.WithPairingRand WithPairingClock = security.WithPairingClock )
Constructor and option helpers forwarded from imbot/security.
var AllowedMIMETypes = map[string]string{
"image/jpeg": "image",
"image/png": "image",
"image/gif": "image",
"image/webp": "image",
"application/pdf": "document",
"text/plain": "document",
"text/markdown": "document",
"text/csv": "document",
"application/msword": "document",
"application/vnd.openxmlformats-officedocument.wordprocessingml.document": "document",
"application/vnd.ms-excel": "document",
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": "document",
}
AllowedMIMETypes lists supported file types
Functions ¶
func BuildBindConfirmPrompt ¶
BuildBindConfirmPrompt returns the text for bind confirmation prompt
func BuildCustomPathPrompt ¶
func BuildCustomPathPrompt() string
BuildCustomPathPrompt returns the text for custom path input prompt
func BuildFooter ¶
BuildFooter creates a compact footer line with agent and path info Format: separator + "📁 path · icon agent" Path is always present (defaults are resolved before calling this)
func EnsureContext ¶ added in v0.260507.1
EnsureContext provides a context that propagates either through t.Context() (Go 1.24+) or a fresh background context.
func ExpandPath ¶
ExpandPath expands ~ and environment variables in a path
func GetAgentDisplayName ¶
GetAgentDisplayName returns the short display name for an agent type
func GetAgentIcon ¶
GetAgentIcon returns the icon for an agent type
func RegisterBuiltinCommands ¶
func RegisterBuiltinCommands(registry *imbot.CommandRegistry, botHandler BotHandlerAdapter) error
RegisterBuiltinCommands registers all built-in commands to the registry.
func ShortenID ¶
ShortenID truncates an ID to a readable length e.g., "a1b2c3d4e5f6g7h8" -> "a1b2c3d4"
func ValidateProjectPath ¶
ValidateProjectPath validates that a path is a valid project directory
Types ¶
type AgentExecutor ¶
type AgentExecutor interface {
// Execute processes a prepared request and returns the result.
Execute(ctx context.Context, req PreparedRequest) (*ExecutionResult, error)
// GetAgentType returns the agent type identifier
GetAgentType() agentboot.AgentType
}
AgentExecutor defines the interface for executing agent requests. Each agent type (Claude Code, Smart Guide, Mock) implements this interface.
type AgentRouter ¶
type AgentRouter struct {
// contains filtered or unexported fields
}
AgentRouter routes execution requests to the appropriate agent executor. It resolves common concerns (project path, session, meta, cancel context) once, then delegates to the specific executor.
func NewAgentRouter ¶
func NewAgentRouter(deps *ExecutorDependencies) *AgentRouter
NewAgentRouter creates a new agent router with the given dependencies
func (*AgentRouter) Execute ¶
func (r *AgentRouter) Execute(ctx context.Context, agentType agentboot.AgentType, req ExecutionRequest) (*ExecutionResult, error)
Execute routes the execution request to the appropriate agent executor. It resolves project path, session, and builds shared *ResponseMeta before delegating.
func (*AgentRouter) GetExecutor ¶
func (r *AgentRouter) GetExecutor(agentType agentboot.AgentType) (AgentExecutor, bool)
GetExecutor returns the executor for a given agent type
func (*AgentRouter) ListExecutors ¶
func (r *AgentRouter) ListExecutors() []agentboot.AgentType
ListExecutors returns all registered agent types
func (*AgentRouter) RegisterExecutor ¶
func (r *AgentRouter) RegisterExecutor(executor AgentExecutor)
RegisterExecutor registers an agent executor
type BotHandler ¶
type BotHandler struct {
// contains filtered or unexported fields
}
BotHandler encapsulates all bot message handling logic and dependencies
func NewBotHandler ¶
func NewBotHandler( ctx context.Context, botSetting BotSetting, chatStore ChatStoreInterface, sessionMgr *session.Manager, agentBoot *agentboot.AgentBoot, directoryBrowser *feature.DirectoryBrowser, manager *imbot.Manager, tbClient tbclient.TBClient, pairing *PairingManager, auditLog *audit.Logger, store SettingsStore, ) *BotHandler
func (*BotHandler) GetCommandRegistry ¶
func (h *BotHandler) GetCommandRegistry() *imbot.CommandRegistry
GetCommandRegistry returns the command registry.
func (*BotHandler) GetVerbose ¶
func (h *BotHandler) GetVerbose(chatID string) bool
func (*BotHandler) HandleCommandViaRegistry ¶
func (h *BotHandler) HandleCommandViaRegistry(hCtx HandlerContext, cmdName string, args []string) error
HandleCommandViaRegistry handles a command using the new command registry.
func (*BotHandler) HandleMessage ¶
func (*BotHandler) InitCommandRegistry ¶
func (h *BotHandler) InitCommandRegistry() error
InitCommandRegistry initializes the command registry with built-in commands.
func (*BotHandler) RequestConfirmation ¶
func (h *BotHandler) RequestConfirmation(ctx context.Context, hCtx HandlerContext, message, requestID string) (bool, error)
RequestConfirmation requests a yes/no confirmation from the user Uses the new interaction system with platform-agnostic UI
func (*BotHandler) RequestInteraction ¶
func (h *BotHandler) RequestInteraction(ctx context.Context, hCtx HandlerContext, req imbot.InteractionRequest) (*imbot.InteractionResponse, error)
RequestInteraction sends an interaction request using the new interaction system This is a convenience method for BotHandler to request platform-agnostic interactions
func (*BotHandler) RequestOptionSelection ¶
func (h *BotHandler) RequestOptionSelection(ctx context.Context, hCtx HandlerContext, message, requestID string, options []imbot.Option) (int, *imbot.Interaction, error)
RequestOptionSelection requests the user to select from a list of options Uses the new interaction system with platform-agnostic UI
func (*BotHandler) SendFile ¶ added in v0.260414.2000
func (h *BotHandler) SendFile(ctx context.Context, hCtx HandlerContext, filePath, caption string) error
SendFile sends a local file to the user via the IM bot. The file is read from disk and sent as a MediaAttachment. caption may be empty.
func (*BotHandler) SendText ¶
func (h *BotHandler) SendText(hCtx HandlerContext, text string)
func (*BotHandler) SetVerbose ¶
func (h *BotHandler) SetVerbose(chatID string, verbose bool)
SetVerbose sets the verbose mode for a chat
func (*BotHandler) VerifyAndPair ¶ added in v0.260507.1
func (h *BotHandler) VerifyAndPair(botUUID, chatID, senderID, platform, code string) error
VerifyAndPair runs the pairing-code check and, on success, persists the binding in the chat store. It is invoked by the /bind command handler.
type BotHandlerAdapter ¶
type BotHandlerAdapter interface {
// SendText sends a text message to a chat
SendText(chatID, text string) error
// GetProjectPath gets the current project path for a chat
GetProjectPath(chatID string) (string, error)
// SetProjectPath sets the project path for a chat
SetProjectPath(chatID, path string) error
// GetProjectPathForGroup gets project path with group fallback
GetProjectPathForGroup(chatID, platform string) (string, bool)
// GetSession gets session info
GetSession(chatID, agentType, projectPath string) (*SessionInfo, error)
// FindOrCreateSession finds an existing session or creates a new one
FindOrCreateSession(chatID, agentType, projectPath string) (*SessionInfo, error)
// UpdatePermissionMode updates the permission mode for a session
UpdatePermissionMode(sessionID, mode string) error
// ClearSession clears a session
ClearSession(chatID, agentType string) error
// StopExecution cancels a running execution, returns true if one was running
StopExecution(chatID string) bool
// GetCurrentAgent gets the current agent for a chat
GetCurrentAgent(chatID string) (string, error)
// SetVerbose sets verbose mode for a chat
SetVerbose(chatID string, enabled bool)
// GetVerbose gets verbose mode for a chat
GetVerbose(chatID string) bool
// IsWhitelisted checks if a group is whitelisted
IsWhitelisted(groupID string) bool
// AddToWhitelist adds a group to whitelist
AddToWhitelist(groupID, platform, userID string) error
// GetBashCwd gets the bash working directory
GetBashCwd(chatID string) (string, error)
// SetBashCwd sets the bash working directory
SetBashCwd(chatID, path string) error
// ResolveChatID resolves a chat ID (for Telegram join command)
ResolveChatID(input string) (string, error)
// GetDefaultProjectPath returns the default project path
GetDefaultProjectPath() string
// GetBashAllowlist returns the configured bash allowlist
GetBashAllowlist() map[string]struct{}
// ListProjectPaths lists all project paths for a user
ListProjectPaths(ownerID, platform string) ([]string, error)
// VerifyAndPair verifies a one-time pairing code and, on success, records
// the chat as paired with the bot. Implementations should also emit the
// matching audit events (success / failure).
VerifyAndPair(botUUID, chatID, senderID, platform, code string) error
}
BotHandlerAdapter provides methods needed by command handlers. This allows commands to interact with the bot without direct coupling.
func NewBotHandlerAdapter ¶
func NewBotHandlerAdapter(handler *BotHandler) BotHandlerAdapter
NewBotHandlerAdapter creates a new adapter for the given handler.
type BotSetting ¶
type BotSetting struct {
UUID string `json:"uuid,omitempty"` // UUID for bot identification
Name string `json:"name,omitempty"` // User-defined name for the bot
Token string `json:"token,omitempty"` // Legacy: for backward compatibility
Platform string `json:"platform"` // Platform identifier
AuthType string `json:"auth_type"` // Auth type: token, oauth, qr
Auth map[string]string `json:"auth"` // Dynamic auth fields based on platform
ProxyURL string `json:"proxy_url,omitempty"` // Optional proxy URL
ChatIDLock string `json:"chat_id,omitempty"` // Optional chat ID lock
BashAllowlist []string `json:"bash_allowlist,omitempty"` // Optional bash command allowlist
DefaultCwd string `json:"default_cwd,omitempty"` // Default working directory if no project bound
Enabled bool `json:"enabled"` // Whether this bot is enabled
// Output behavior settings
Verbose *bool `json:"verbose,omitempty"` // Send intermediate messages (nil = true default)
// SmartGuide model configuration (required for @tb agent)
SmartGuideProvider string `json:"smartguide_provider,omitempty"` // Provider UUID
SmartGuideModel string `json:"smartguide_model,omitempty"` // Model identifier
// RequirePairing enforces a TOFU pairing-code handshake before any DM is
// processed. Nil is treated as false so legacy bots keep working until the
// operator opts in. New bots created via the wizard set this to true.
RequirePairing *bool `json:"require_pairing,omitempty"`
CreatedAt string `json:"created_at,omitempty"`
UpdatedAt string `json:"updated_at,omitempty"`
}
BotSetting represents bot configuration with platform-specific auth
func (BotSetting) GetOutputBehavior ¶
func (s BotSetting) GetOutputBehavior() OutputBehavior
GetOutputBehavior extracts output behavior from bot setting
func (BotSetting) IsRequirePairing ¶ added in v0.260507.1
func (b BotSetting) IsRequirePairing() bool
IsRequirePairing reports whether this bot requires per-chat pairing.
type Chat ¶
type Chat struct {
ChatID string `json:"chat_id"`
Platform string `json:"platform"`
ProjectPath string `json:"project_path,omitempty"`
OwnerID string `json:"owner_id,omitempty"`
// Pairing (TOFU) — applies to direct messages only. Group chats continue
// to use the IsWhitelisted gate, but the operator who whitelisted the
// group must themselves be paired in DM with the same bot.
IsPaired bool `json:"is_paired,omitempty"`
PairedBotUUID string `json:"paired_bot_uuid,omitempty"`
PairedSenderID string `json:"paired_sender_id,omitempty"`
PairedAt time.Time `json:"paired_at,omitempty"`
// Group-specific
IsWhitelisted bool `json:"is_whitelisted"`
WhitelistedBy string `json:"whitelisted_by,omitempty"`
// Bash state
BashCwd string `json:"bash_cwd,omitempty"`
// Agent state (for smart guide handoff)
CurrentAgent string `json:"current_agent,omitempty"` // "tingly-box" or "claude"
AgentState []byte `json:"agent_state,omitempty"` // JSON-encoded agent-specific state
// Chat-level settings
Verbose *bool `json:"verbose,omitempty"` // Verbose mode: nil=use bot default, true=verbose, false=quiet
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
Chat represents all state associated with a chat (direct or group)
type ChatStoreInterface ¶
type ChatStoreInterface interface {
// Close ensures data is persisted before closing
Close() error
// GetChat retrieves a chat by ID
GetChat(chatID string) (*Chat, error)
// GetOrCreateChat gets a chat or creates it if not exists
GetOrCreateChat(chatID, platform string) (*Chat, error)
// UpsertChat creates or updates a chat
UpsertChat(chat *Chat) error
// UpdateChat updates specific fields of a chat
UpdateChat(chatID string, fn func(*Chat)) error
// BindProject binds a project to a chat
BindProject(chatID, platform, projectPath, ownerID string) error
// GetProjectPath retrieves the project path for a chat
GetProjectPath(chatID string) (string, bool, error)
// ListChatsByOwner lists all chats owned by a user
ListChatsByOwner(ownerID, platform string) ([]*Chat, error)
// AddToWhitelist adds a chat to the whitelist
AddToWhitelist(chatID, platform, addedBy string) error
// RemoveFromWhitelist removes a chat from the whitelist
RemoveFromWhitelist(chatID string) error
// IsWhitelisted checks if a chat is whitelisted
IsWhitelisted(chatID string) bool
// SetBashCwd sets the bash working directory for a chat
SetBashCwd(chatID, cwd string) error
// GetBashCwd retrieves the bash working directory for a chat
GetBashCwd(chatID string) (string, bool, error)
// SetCurrentAgent sets the current agent for a chat. Creates the chat
// row if it doesn't yet exist so that @cc/@tb handoff state persists
// even on fresh chats that haven't been bound (/cd) or paired (/bind)
// yet. Pass an empty platform when the caller doesn't have one — the
// field will be filled in later by BindProject/SetPaired.
SetCurrentAgent(chatID, platform, agentType string) error
// GetCurrentAgent retrieves the current agent for a chat
GetCurrentAgent(chatID string) (string, error)
// SetAgentState sets the agent-specific state for a chat
SetAgentState(chatID string, state []byte) error
// GetAgentState retrieves the agent-specific state for a chat
GetAgentState(chatID string) ([]byte, error)
// ListWhitelistedGroups returns all whitelisted groups
ListWhitelistedGroups() ([]struct {
GroupID string
Platform string
AddedBy string
CreatedAt string
}, error)
// SetPaired marks a chat as paired with a specific bot UUID and sender.
// The chat is created if it does not yet exist.
SetPaired(chatID, platform, botUUID, senderID string) error
// ClearPaired removes the pairing on a chat. Other state on the chat is
// preserved.
ClearPaired(chatID string) error
// IsChatPaired reports whether the chat is paired with the given bot UUID.
IsChatPaired(chatID, botUUID string) bool
}
ChatStoreInterface defines the interface for chat persistence This allows both SQLite-based ChatStore and JSON-based ChatStoreJSON to be used interchangeably
type ChatStoreJSON ¶
type ChatStoreJSON struct {
// contains filtered or unexported fields
}
ChatStoreJSON handles unified chat persistence using JSON file storage
func NewChatStoreJSON ¶
func NewChatStoreJSON(filePath string) (*ChatStoreJSON, error)
NewChatStoreJSON creates a new JSON-based chat store
func (*ChatStoreJSON) AddToWhitelist ¶
func (s *ChatStoreJSON) AddToWhitelist(chatID, platform, addedBy string) error
AddToWhitelist adds a chat to the whitelist
func (*ChatStoreJSON) BindProject ¶
func (s *ChatStoreJSON) BindProject(chatID, platform, projectPath, ownerID string) error
BindProject binds a project to a chat (creates chat if not exists)
func (*ChatStoreJSON) ClearPaired ¶ added in v0.260507.1
func (s *ChatStoreJSON) ClearPaired(chatID string) error
ClearPaired removes any pairing recorded on the chat.
func (*ChatStoreJSON) Close ¶
func (s *ChatStoreJSON) Close() error
Close ensures data is persisted before closing
func (*ChatStoreJSON) GetAgentState ¶
func (s *ChatStoreJSON) GetAgentState(chatID string) ([]byte, error)
GetAgentState retrieves the agent-specific state for a chat
func (*ChatStoreJSON) GetBashCwd ¶
func (s *ChatStoreJSON) GetBashCwd(chatID string) (string, bool, error)
GetBashCwd retrieves the bash working directory for a chat
func (*ChatStoreJSON) GetChat ¶
func (s *ChatStoreJSON) GetChat(chatID string) (*Chat, error)
GetChat retrieves a chat by ID
func (*ChatStoreJSON) GetCurrentAgent ¶
func (s *ChatStoreJSON) GetCurrentAgent(chatID string) (string, error)
GetCurrentAgent retrieves the current agent for a chat Returns "tingly-box" as default (Smart Guide is the entry point)
func (*ChatStoreJSON) GetOrCreateChat ¶
func (s *ChatStoreJSON) GetOrCreateChat(chatID, platform string) (*Chat, error)
GetOrCreateChat gets a chat or creates it if not exists
func (*ChatStoreJSON) GetProjectPath ¶
func (s *ChatStoreJSON) GetProjectPath(chatID string) (string, bool, error)
GetProjectPath retrieves the project path for a chat
func (*ChatStoreJSON) IsChatPaired ¶ added in v0.260507.1
func (s *ChatStoreJSON) IsChatPaired(chatID, botUUID string) bool
IsChatPaired reports whether the chat is paired with the given bot UUID.
func (*ChatStoreJSON) IsWhitelisted ¶
func (s *ChatStoreJSON) IsWhitelisted(chatID string) bool
IsWhitelisted checks if a chat is whitelisted
func (*ChatStoreJSON) ListChatsByOwner ¶
func (s *ChatStoreJSON) ListChatsByOwner(ownerID, platform string) ([]*Chat, error)
ListChatsByOwner lists all chats owned by a user
func (*ChatStoreJSON) ListWhitelistedGroups ¶
func (s *ChatStoreJSON) ListWhitelistedGroups() ([]struct { GroupID string Platform string AddedBy string CreatedAt string }, error)
ListWhitelistedGroups returns all whitelisted groups
func (*ChatStoreJSON) RemoveFromWhitelist ¶
func (s *ChatStoreJSON) RemoveFromWhitelist(chatID string) error
RemoveFromWhitelist removes a chat from the whitelist
func (*ChatStoreJSON) SetAgentState ¶
func (s *ChatStoreJSON) SetAgentState(chatID string, state []byte) error
SetAgentState sets the agent-specific state for a chat
func (*ChatStoreJSON) SetBashCwd ¶
func (s *ChatStoreJSON) SetBashCwd(chatID, cwd string) error
SetBashCwd sets the bash working directory for a chat
func (*ChatStoreJSON) SetCurrentAgent ¶
func (s *ChatStoreJSON) SetCurrentAgent(chatID, platform, agentType string) error
SetCurrentAgent sets the current agent for a chat, creating the chat row if it doesn't yet exist. Without the auto-create, UpdateChat silently no-ops on a missing chat, which silently dropped handoff persistence for any chat that hadn't been pre-bound or pre-paired.
func (*ChatStoreJSON) SetPaired ¶ added in v0.260507.1
func (s *ChatStoreJSON) SetPaired(chatID, platform, botUUID, senderID string) error
SetPaired marks the given chat as paired with botUUID/senderID.
func (*ChatStoreJSON) UpdateChat ¶
func (s *ChatStoreJSON) UpdateChat(chatID string, fn func(*Chat)) error
UpdateChat updates specific fields of a chat
func (*ChatStoreJSON) UpsertChat ¶
func (s *ChatStoreJSON) UpsertChat(chat *Chat) error
UpsertChat creates or updates a chat
type ClaudeCodeExecutor ¶
type ClaudeCodeExecutor struct {
// contains filtered or unexported fields
}
ClaudeCodeExecutor executes messages through the Claude Code agent.
It consumes the agentboot.ExecutionHandle returned by Agent.Execute directly, dispatching MessageEvents to the streaming chat writer and routing ApprovalRequestEvent / AskRequestEvent to IMPrompter.
func NewClaudeCodeExecutor ¶
func NewClaudeCodeExecutor(deps *ExecutorDependencies) *ClaudeCodeExecutor
NewClaudeCodeExecutor creates a new Claude Code executor.
func (*ClaudeCodeExecutor) Execute ¶
func (e *ClaudeCodeExecutor) Execute(ctx context.Context, req PreparedRequest) (*ExecutionResult, error)
Execute processes a user message through Claude Code.
func (*ClaudeCodeExecutor) GetAgentType ¶
func (e *ClaudeCodeExecutor) GetAgentType() agentboot.AgentType
GetAgentType returns the agent type identifier.
type ExecutionRequest ¶
type ExecutionRequest struct {
HCtx HandlerContext
Text string
ProjectPath string // optional override
ReplyToMessageID string
}
ExecutionRequest contains caller-provided parameters (from bot handler layer).
type ExecutionResult ¶
type ExecutionResult struct {
Response string
SessionID string
Success bool
Error error
Meta *ResponseMeta
IsNewSession bool
Duration time.Duration
}
ExecutionResult contains the outcome of agent execution
type ExecutorDependencies ¶
type ExecutorDependencies struct {
// GetBotSetting dynamically retrieves the current bot settings from the store.
// This ensures that any configuration changes (provider, model, etc.) are reflected
// immediately without requiring a bot restart.
GetBotSetting func() (BotSetting, error)
ChatStore ChatStoreInterface
SessionMgr *SessionManager
AgentBoot *agentboot.AgentBoot
IMPrompter *imchannel.IMPrompter
FileStore *FileStore
TBClient TBClient
TBSessionStore *SmartGuideSessionStore
HandoffManager *smart_guide.HandoffManager
RunningCancel map[string]context.CancelFunc
RunningCancelMu *sync.RWMutex
GetVerbose func(chatID string) bool
FormatResponse func(meta ResponseMeta, response string, showMeta bool) string
SendText func(hCtx HandlerContext, text string)
SendTextWithReply func(hCtx HandlerContext, text string, replyTo string)
SendTextWithActionKeyboard func(hCtx HandlerContext, text string, replyTo string)
SendFile func(hCtx HandlerContext, filePath, caption string) error
NewStreamingMessageHandler func(hCtx HandlerContext, meta *ResponseMeta) *streamingMessageHandler
}
ExecutorDependencies holds shared dependencies for agent executors and router.
func (*ExecutorDependencies) GetBotSettingOrCache ¶ added in v0.260507.1
func (d *ExecutorDependencies) GetBotSettingOrCache() BotSetting
GetBotSettingOrCache returns the current bot setting. If dynamic lookup fails, returns an empty setting.
func (*ExecutorDependencies) ResolveDefaultProjectPath ¶
func (d *ExecutorDependencies) ResolveDefaultProjectPath() string
ResolveDefaultProjectPath returns the default project path from bot settings.
type FileStore ¶
type FileStore struct {
// contains filtered or unexported fields
}
FileStore handles project-based file storage for bot media
func NewFileStore ¶
func NewFileStore() *FileStore
NewFileStore creates a new file store with default limits
func NewFileStoreWithLimits ¶
NewFileStoreWithLimits creates a new file store with custom limits
func NewFileStoreWithProxy ¶
NewFileStoreWithProxy creates a new file store with proxy support
func (*FileStore) DownloadFile ¶
func (s *FileStore) DownloadFile(ctx context.Context, projectPath, url, mimeType string) (*StoredFile, error)
DownloadFile downloads a file from a URL to the project's .download directory Returns an error if file size exceeds limits
func (*FileStore) GetDownloadDir ¶
GetDownloadDir returns the .download directory for a project
func (*FileStore) IsAllowedSize ¶
IsAllowedSize checks if the size is within limits for the mime type
func (*FileStore) IsAllowedType ¶
IsAllowedType checks if the mime type is allowed
func (*FileStore) SetTelegramToken ¶
SetTelegramToken sets the Telegram bot token for resolving file URLs
type HandlerContext ¶
type HandlerContext struct {
Bot imbot.Bot
BotUUID string
ChatID string
SenderID string
MessageID string
Platform imbot.Platform
Message imbot.Message
}
HandlerContext contains per-message context data
func (*HandlerContext) IsDirect ¶
func (c *HandlerContext) IsDirect() bool
func (*HandlerContext) IsGroup ¶
func (c *HandlerContext) IsGroup() bool
func (*HandlerContext) Text ¶
func (c *HandlerContext) Text() string
type Lifecycle ¶
type Lifecycle interface {
// Start starts a bot by UUID
Start(ctx context.Context, uuid string) error
// Stop stops a bot by UUID
Stop(uuid string)
// IsRunning checks if a bot is running
IsRunning(uuid string) bool
// Sync ensures running bots match the enabled settings
Sync(ctx context.Context) error
}
Lifecycle defines the interface for controlling bot lifecycle This allows the API layer to control bot startup/shutdown without direct dependency on the Manager type
type Manager ¶
type Manager struct {
// contains filtered or unexported fields
}
Manager manages the lifecycle of running bot instances
func NewManager ¶
func NewManager(store SettingsStore, sessionMgr *session.Manager, agentBoot *agentboot.AgentBoot, ) *Manager
NewManager creates a new bot manager with a settings store
func (*Manager) AuditLogger ¶ added in v0.260507.1
AuditLogger returns the manager's audit logger.
func (*Manager) ChatStore ¶ added in v0.260507.1
func (m *Manager) ChatStore() (ChatStoreInterface, error)
ChatStore opens (and the caller must Close) a chat store backed by the manager's data path. Used by the CLI to read/clear pairings without touching a running bot's store.
func (*Manager) PairingManager ¶ added in v0.260507.1
func (m *Manager) PairingManager() *PairingManager
PairingManager returns the manager's PairingManager instance. Used by CLI helpers that mint, rotate, or revoke pairing codes.
func (*Manager) SetChannelRegistry ¶ added in v0.260507.1
SetChannelRegistry wires a remote channel registry so each running bot exposes itself as a remote.channel.Channel reachable from /tingly/:scenario scenario plugins. Safe to call once at startup before any bot is started.
func (*Manager) SetDataPath ¶
SetDataPath sets the data path for JSON chat store operations
func (*Manager) SetTBClient ¶
SetTBClient sets the TBClient for SmartGuide configuration
func (*Manager) StartEnabled ¶
StartEnabled starts all enabled bots
func (*Manager) StartEnabledStopDisabled ¶
StartEnabledStopDisabled is a convenience method that ensures running bots match enabled settings. It's an alias for Sync() with clearer naming for specific use cases.
type OutputBehavior ¶
type OutputBehavior struct {
Verbose bool // Send intermediate processing messages
}
OutputBehavior controls what is shown in bot messages
func DefaultOutputBehavior ¶
func DefaultOutputBehavior() OutputBehavior
DefaultOutputBehavior returns the default output behavior
type PairingManager ¶ added in v0.260507.1
type PairingManager = security.PairingManager
Type aliases — fully transparent to callers.
type PairingManagerOption ¶ added in v0.260507.1
type PairingManagerOption = security.PairingManagerOption
type PendingBind ¶
PendingBind represents a pending bind confirmation request
type PreparedRequest ¶
type PreparedRequest struct {
HCtx HandlerContext
Text string
ProjectPath string // fully resolved: override > ChatStore > default
Meta *ResponseMeta // shared pointer, created by router
SessionID string // resolved session ID (chatID for SmartGuide)
IsNewSession bool // whether session was just created
PermissionMode string // resolved from session (Claude Code / Mock)
ReplyTo string
}
PreparedRequest is the fully-resolved request built by AgentRouter. All executors receive this — shared *ResponseMeta ensures path changes propagate.
type ResponseMeta ¶
type ResponseMeta struct {
ProjectPath string
ChatID string
UserID string
SessionID string
AgentType string // Current agent identifier (e.g., "tingly-box", "claude")
}
ResponseMeta contains metadata for response formatting
type SessionInfo ¶
type SessionInfo struct {
ID string
Status string
Project string
Request string
Error string
PermissionMode string
LastActivity time.Time
}
SessionInfo holds session information.
type SettingsStore ¶
type SettingsStore interface {
// GetSettingsByUUIDInterface returns settings by UUID as interface{}
GetSettingsByUUIDInterface(uuid string) (interface{}, error)
// ListEnabledSettingsInterface returns all enabled settings as interface{}
ListEnabledSettingsInterface() (interface{}, error)
}
SettingsStore defines the interface for bot settings storage This allows both the legacy bot.Store and the new db.ImBotSettingsStore to be used
type SmartGuideCompletionCallback ¶
type SmartGuideCompletionCallback struct {
// contains filtered or unexported fields
}
SmartGuideCompletionCallback handles completion events for SmartGuide agent It saves messages to session, updates project path if changed, and sends response + action keyboard
func (*SmartGuideCompletionCallback) OnComplete ¶
func (c *SmartGuideCompletionCallback) OnComplete(result *agentboot.CompletionResult)
OnComplete implements agentboot.CompletionCallback
type SmartGuideExecutor ¶
type SmartGuideExecutor struct {
// contains filtered or unexported fields
}
SmartGuideExecutor executes messages through Smart Guide (Tingly Box) agent
func NewSmartGuideExecutor ¶
func NewSmartGuideExecutor(deps *ExecutorDependencies) *SmartGuideExecutor
NewSmartGuideExecutor creates a new Smart Guide executor
func (*SmartGuideExecutor) Execute ¶
func (e *SmartGuideExecutor) Execute(ctx context.Context, req PreparedRequest) (*ExecutionResult, error)
Execute processes a user message through Smart Guide
func (*SmartGuideExecutor) GetAgentType ¶
func (e *SmartGuideExecutor) GetAgentType() agentboot.AgentType
GetAgentType returns the agent type identifier
type SmartGuideSessionStore ¶
type SmartGuideSessionStore = smart_guide.SessionStore
type StoredFile ¶
type StoredFile struct {
Path string // Full path: {projectPath}/.agent/{filename}
RelPath string // Relative path for agent: .agent/{filename}
URL string // Original URL
Filename string
Size int64
MimeType string
}
StoredFile represents a stored file
type TelegramFile ¶
type TelegramFile struct {
Ok bool `json:"ok"`
Result struct {
FileID string `json:"file_id"`
FileSize int `json:"file_size"`
FilePath string `json:"file_path"`
} `json:"result"`
}
TelegramFile represents the response from Telegram's getFile API
type TestBootOptions ¶ added in v0.260507.1
type TestBootOptions struct {
// DataDir overrides the chat-store directory (default: t.TempDir()).
DataDir string
// FixtureScript, when non-nil, registers a Claude agent backed by a
// fixture.Factory(script). The fixture replaces the legacy mockagent —
// tests now drive the real claude.Driver + claude.Transport + Runner
// pipeline against scripted wire-format output.
//
// When nil (default), no Claude agent is registered and tests that
// depend on agent execution must register their own.
FixtureScript fixture.Script
}
TestBootOptions tweaks BootForTest defaults. All fields are optional.
type TestHarness ¶ added in v0.260507.1
type TestHarness struct {
Setting BotSetting
Handler *BotHandler
ChatStore ChatStoreInterface
SessionMgr *session.Manager
AgentBoot *agentboot.AgentBoot
Pairing *PairingManager
Audit *audit.Logger
DataDir string
Manager *imbot.Manager
// contains filtered or unexported fields
}
TestHarness wires the production BotHandler against a test imbot.Manager (typically backed by the tingly platform). It owns the support infrastructure — chat store, session manager, agentboot, pairing — and exposes them so tests can drive state directly.
Construction:
env := testenv.NewTestEnv(t)
uuid := env.BotUUID() // creates a tingly bot in env.Manager()
harness := bot.BootForTest(t, env.Manager(), bot.BotSetting{
UUID: uuid,
Platform: "tingly",
Enabled: true,
})
require.NoError(t, env.Manager().Start(env.Context()))
Tests then drive the bot through the testenv chat helpers.
func BootForTest ¶ added in v0.260507.1
func BootForTest(t *testing.T, manager *imbot.Manager, setting BotSetting, opts ...TestBootOptions) *TestHarness
BootForTest spins up a production BotHandler against the given imbot.Manager. It assumes the Manager already has a bot registered for setting.UUID (the tingly testenv arranges this via AddTinglyBotWithUUID when env.BotUUID() is called).
The harness registers the BotHandler.HandleMessage callback on the Manager. Callers must Start the Manager themselves — keeping that step in the test makes it explicit when inbound messages start flowing.
func (*TestHarness) MarkChatPaired ¶ added in v0.260507.1
func (h *TestHarness) MarkChatPaired(chatID, senderID string)
MarkChatPaired records a pairing for the harness's bot via the same production API path that VerifyAndPair uses. Tests focused on post-pairing behavior can skip the /bind handshake without bypassing the real persistence path — exercising any future bug in SetPaired.
func (*TestHarness) MintPairingCode ¶ added in v0.260507.1
func (h *TestHarness) MintPairingCode() (code string, expiresAt time.Time)
MintPairingCode mints a fresh pairing code for the harness's bot. Tests that exercise the pairing-required path use this to obtain the code the user must send via /bind.
func (*TestHarness) SetCurrentAgent ¶ added in v0.260507.1
func (h *TestHarness) SetCurrentAgent(chatID, agentType string)
SetCurrentAgent updates the current-agent binding for a chat through the same production path the @cc/@tb handoff uses. Going through chatStore.SetCurrentAgent (rather than mutating Chat directly) keeps the harness honest: any regression in the persistence path — e.g. a silent no-op on a missing chat row — surfaces as a test failure.
func (*TestHarness) WhitelistGroup ¶ added in v0.260507.1
func (h *TestHarness) WhitelistGroup(chatID, ownerID string)
WhitelistGroup adds a group chat to the bot's whitelist (required for the bot to respond to group messages).
Source Files
¶
- agent_claude_code.go
- agent_executor.go
- agent_router.go
- agent_smart_guide.go
- bot_agent.go
- bot_command.go
- bot_file_send.go
- bot_stream.go
- card_metadata.go
- chat_store.go
- command.go
- command_integration.go
- file_store.go
- handler_bind.go
- handler_constructor.go
- handler_format.go
- handler_message.go
- handler_next.go
- handler_pair.go
- handler_send.go
- handler_types.go
- handler_verbose.go
- manager.go
- output.go
- pairing_manager.go
- telegram_callback.go
- testharness.go
- type.go
- util.go